From 83587ca0f85c912dda60f5e08a0579b9353254db Mon Sep 17 00:00:00 2001 From: Marius Date: Sat, 19 Dec 2015 00:02:11 +0100 Subject: [PATCH] Add filestore.FileLocker --- filestore/filelock.go | 58 ++++++++++++++++++++++++++++++++++++++ filestore/filelock_test.go | 35 +++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 filestore/filelock.go create mode 100644 filestore/filelock_test.go diff --git a/filestore/filelock.go b/filestore/filelock.go new file mode 100644 index 0000000..8184a5d --- /dev/null +++ b/filestore/filelock.go @@ -0,0 +1,58 @@ +package filestore + +import ( + "os" + "path/filepath" + + "github.com/nightlyone/lockfile" + "github.com/tus/tusd" +) + +type FileLocker struct { + // Relative or absolute path to store the locks in. + Path string +} + +func (locker FileLocker) LockUpload(id string) error { + lock, err := locker.newLock(id) + if err != nil { + return err + } + + err = lock.TryLock() + if err == lockfile.ErrBusy { + return tusd.ErrFileLocked + } + + return err +} + +func (locker FileLocker) UnlockUpload(id string) error { + lock, err := locker.newLock(id) + if err != nil { + return err + } + + err = lock.Unlock() + + // A "no such file or directory" will be returned if no lockfile was found. + // Since this means that the file has never been locked, we drop the error + // and continue as if nothing happend. + if os.IsNotExist(err) { + err = nil + } + + return nil +} + +func (locker FileLocker) newLock(id string) (lockfile.Lockfile, error) { + path, err := filepath.Abs(locker.Path + "/" + id + ".lock") + if err != nil { + return lockfile.Lockfile(""), err + } + + // We use Lockfile directly instead of lockfile.New to bypass the unnecessary + // check whether the provided path is absolute since we just resolved it + // on our own. + return lockfile.Lockfile(path), nil +} diff --git a/filestore/filelock_test.go b/filestore/filelock_test.go new file mode 100644 index 0000000..71c5c97 --- /dev/null +++ b/filestore/filelock_test.go @@ -0,0 +1,35 @@ +package filestore + +import ( + "io/ioutil" + "testing" + + "github.com/tus/tusd" + "github.com/tus/tusd/lockingstore" +) + +func TestFileLocker(t *testing.T) { + dir, err := ioutil.TempDir("", "tusd-file-locker") + if err != nil { + t.Fatal(err) + } + + var locker lockingstore.Locker + locker = FileLocker{dir} + + if err := locker.LockUpload("one"); err != nil { + t.Errorf("unexpected error when locking file: %s", err) + } + + if err := locker.LockUpload("one"); err != tusd.ErrFileLocked { + t.Errorf("expected error when locking locked file: %s", err) + } + + if err := locker.UnlockUpload("one"); err != nil { + t.Errorf("unexpected error when unlocking file: %s", err) + } + + if err := locker.UnlockUpload("one"); err != nil { + t.Errorf("unexpected error when unlocking file again: %s", err) + } +}