tusd/pkg/filelocker/filelocker.go

84 lines
2.4 KiB
Go
Raw Normal View History

2019-09-10 14:19:49 +00:00
// Package filelocker provide an upload locker based on the local file system.
2019-08-24 13:14:51 +00:00
//
2019-09-10 14:19:49 +00:00
// It provides an exclusive upload locking mechanism using lock files
2019-08-24 13:14:51 +00:00
// which are stored on disk. Each of them stores the PID of the process which
// acquired the lock. This allows locks to be automatically freed when a process
// is unable to release it on its own because the process is not alive anymore.
// For more information, consult the documentation for handler.LockerDataStore
2019-09-10 14:19:49 +00:00
// interface, which is implemented by FileLocker.
package filelocker
2019-08-24 13:14:51 +00:00
import (
"context"
2019-08-24 13:14:51 +00:00
"os"
"path/filepath"
"github.com/tus/tusd/pkg/handler"
"gopkg.in/Acconut/lockfile.v1"
)
var defaultFilePerm = os.FileMode(0664)
// See the handler.DataStore interface for documentation about the different
// methods.
type FileLocker struct {
// Relative or absolute path to store files in. FileStore does not check
// whether the path exists, use os.MkdirAll in this case on your own.
Path string
}
// New creates a new file based storage backend. The directory specified will
// be used as the only storage entry. This method does not check
// whether the path exists, use os.MkdirAll to ensure.
// In addition, a locking mechanism is provided.
func New(path string) FileLocker {
return FileLocker{path}
}
// UseIn adds this locker to the passed composer.
func (locker FileLocker) UseIn(composer *handler.StoreComposer) {
composer.UseLocker(locker)
}
2019-09-10 14:19:49 +00:00
func (locker FileLocker) NewLock(id string) (handler.Lock, error) {
2019-08-24 13:14:51 +00:00
path, err := filepath.Abs(filepath.Join(locker.Path, id+".lock"))
if err != nil {
2019-09-10 14:19:49 +00:00
return nil, err
2019-08-24 13:14:51 +00:00
}
// 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.
2019-09-10 14:19:49 +00:00
return &fileUploadLock{
2019-08-24 13:14:51 +00:00
file: lockfile.Lockfile(path),
}, nil
}
type fileUploadLock struct {
file lockfile.Lockfile
}
// TODO: Implement functionality for ctx and requestRelease.
func (lock fileUploadLock) Lock(ctx context.Context, requestRelease func()) error {
2019-09-10 14:19:49 +00:00
err := lock.file.TryLock()
2019-08-24 13:14:51 +00:00
if err == lockfile.ErrBusy {
return handler.ErrFileLocked
}
return err
}
func (lock fileUploadLock) Unlock() error {
2019-09-10 14:19:49 +00:00
err := lock.file.Unlock()
2019-08-24 13:14:51 +00:00
// 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 happened.
if os.IsNotExist(err) {
err = nil
}
return err
}