lock.go 1011 B

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. package fileutil
  2. import (
  3. "errors"
  4. "os"
  5. "syscall"
  6. )
  7. var (
  8. ErrLocked = errors.New("file already locked")
  9. )
  10. type Lock interface {
  11. Name() string
  12. TryLock() error
  13. Lock() error
  14. Unlock() error
  15. Destroy() error
  16. }
  17. type lock struct {
  18. fd int
  19. file *os.File
  20. }
  21. func (l *lock) Name() string {
  22. return l.file.Name()
  23. }
  24. // TryLock acquires exclusivity on the lock without blocking
  25. func (l *lock) TryLock() error {
  26. err := syscall.Flock(l.fd, syscall.LOCK_EX|syscall.LOCK_NB)
  27. if err != nil && err == syscall.EWOULDBLOCK {
  28. return ErrLocked
  29. }
  30. return err
  31. }
  32. // Lock acquires exclusivity on the lock without blocking
  33. func (l *lock) Lock() error {
  34. return syscall.Flock(l.fd, syscall.LOCK_EX)
  35. }
  36. // Unlock unlocks the lock
  37. func (l *lock) Unlock() error {
  38. return syscall.Flock(l.fd, syscall.LOCK_UN)
  39. }
  40. func (l *lock) Destroy() error {
  41. return l.file.Close()
  42. }
  43. func NewLock(file string) (Lock, error) {
  44. f, err := os.Open(file)
  45. if err != nil {
  46. return nil, err
  47. }
  48. l := &lock{int(f.Fd()), f}
  49. return l, nil
  50. }