package flock import ( "errors" "os" "golang.org/x/sys/unix" ) // Lock gets an exclusive lock on the file at the given path. If the file // doesn't exist, it's created. func Lock(path string) (*os.File, error) { return lock(path, unix.LOCK_EX) } // TryLock will return a nil file if the file is already locked. func TryLock(path string) (*os.File, error) { return lock(path, unix.LOCK_EX|unix.LOCK_NB) } func LockFile(f *os.File) error { _, err := lockFile(f, unix.LOCK_EX) return err } // Returns true if the lock was successfully acquired. func TryLockFile(f *os.File) (bool, error) { return lockFile(f, unix.LOCK_EX|unix.LOCK_NB) } func lockFile(f *os.File, flags int) (bool, error) { if err := unix.Flock(int(f.Fd()), flags); err != nil { if flags&unix.LOCK_NB != 0 && errors.Is(err, unix.EAGAIN) { return false, nil } return false, err } return true, nil } func lock(path string, flags int) (*os.File, error) { perm := os.O_CREATE | os.O_RDWR f, err := os.OpenFile(path, perm, 0600) if err != nil { return nil, err } ok, err := lockFile(f, flags) if err != nil || !ok { f.Close() f = nil } return f, err } // Unlock releases the lock acquired via the Lock function. func Unlock(f *os.File) error { return f.Close() }