lock.go 1.23 KB
Newer Older
1
package lock
2 3

import (
Jeromy's avatar
Jeromy committed
4
	"fmt"
5
	"io"
6
	"os"
7
	"path"
Jeromy's avatar
Jeromy committed
8 9
	"strings"
	"syscall"
10

11 12
	lock "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/camlistore/lock"
	"github.com/ipfs/go-ipfs/util"
13 14
)

15
// LockFile is the filename of the repo lock, relative to config dir
16
// TODO rename repo lock and hide name
17
const LockFile = "repo.lock"
18

Jeromy's avatar
Jeromy committed
19 20 21 22
func errPerm(path string) error {
	return fmt.Errorf("failed to take lock at %s: permission denied", path)
}

23
func Lock(confdir string) (io.Closer, error) {
24
	c, err := lock.Lock(path.Join(confdir, LockFile))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
25
	return c, err
26 27
}

28
func Locked(confdir string) (bool, error) {
29
	if !util.FileExists(path.Join(confdir, LockFile)) {
30
		return false, nil
31
	}
32
	if lk, err := Lock(confdir); err != nil {
Jeromy's avatar
Jeromy committed
33 34 35 36 37 38
		// EAGAIN == someone else has the lock
		if err == syscall.EAGAIN {
			return true, nil
		}

		// lock fails on permissions error
39
		if os.IsPermission(err) {
Jeromy's avatar
Jeromy committed
40
			return false, errPerm(confdir)
41
		}
Jeromy's avatar
Jeromy committed
42 43 44 45 46 47
		if isLockCreatePermFail(err) {
			return false, errPerm(confdir)
		}

		// otherwise, we cant guarantee anything, error out
		return false, err
48 49
	} else {
		lk.Close()
50
		return false, nil
51 52
	}
}
Jeromy's avatar
Jeromy committed
53 54 55 56 57

func isLockCreatePermFail(err error) bool {
	s := err.Error()
	return strings.Contains(s, "Lock Create of") && strings.Contains(s, "permission denied")
}