github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/filelock/filelock.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // TODO(Tilt team): Remove this copy of Go's internal filelock module when 6 // https://github.com/golang/go/issues/33974 makes a public file locking api. 7 8 // Package filelock provides a platform-independent API for advisory file 9 // locking. Calls to functions in this package on platforms that do not support 10 // advisory locks will return errors for which IsNotSupported returns true. 11 package filelock 12 13 import ( 14 "errors" 15 "io/fs" 16 "os" 17 ) 18 19 // A File provides the minimal set of methods required to lock an open file. 20 // File implementations must be usable as map keys. 21 // The usual implementation is *os.File. 22 type File interface { 23 // Name returns the name of the file. 24 Name() string 25 26 // Fd returns a valid file descriptor. 27 // (If the File is an *os.File, it must not be closed.) 28 Fd() uintptr 29 30 // Stat returns the FileInfo structure describing file. 31 Stat() (fs.FileInfo, error) 32 } 33 34 // Lock places an advisory write lock on the file, blocking until it can be 35 // locked. 36 // 37 // If Lock returns nil, no other process will be able to place a read or write 38 // lock on the file until this process exits, closes f, or calls Unlock on it. 39 // 40 // If f's descriptor is already read- or write-locked, the behavior of Lock is 41 // unspecified. 42 // 43 // Closing the file may or may not release the lock promptly. Callers should 44 // ensure that Unlock is always called when Lock succeeds. 45 func Lock(f File) error { 46 return lock(f, writeLock) 47 } 48 49 // RLock places an advisory read lock on the file, blocking until it can be locked. 50 // 51 // If RLock returns nil, no other process will be able to place a write lock on 52 // the file until this process exits, closes f, or calls Unlock on it. 53 // 54 // If f is already read- or write-locked, the behavior of RLock is unspecified. 55 // 56 // Closing the file may or may not release the lock promptly. Callers should 57 // ensure that Unlock is always called if RLock succeeds. 58 func RLock(f File) error { 59 return lock(f, readLock) 60 } 61 62 // Unlock removes an advisory lock placed on f by this process. 63 // 64 // The caller must not attempt to unlock a file that is not locked. 65 func Unlock(f File) error { 66 return unlock(f) 67 } 68 69 // String returns the name of the function corresponding to lt 70 // (Lock, RLock, or Unlock). 71 func (lt lockType) String() string { 72 switch lt { 73 case readLock: 74 return "RLock" 75 case writeLock: 76 return "Lock" 77 default: 78 return "Unlock" 79 } 80 } 81 82 // IsNotSupported returns a boolean indicating whether the error is known to 83 // report that a function is not supported (possibly for a specific input). 84 // It is satisfied by ErrNotSupported as well as some syscall errors. 85 func IsNotSupported(err error) bool { 86 return isNotSupported(underlyingError(err)) 87 } 88 89 var ErrNotSupported = errors.New("operation not supported") 90 91 // underlyingError returns the underlying error for known os error types. 92 func underlyingError(err error) error { 93 switch err := err.(type) { 94 case *fs.PathError: 95 return err.Err 96 case *os.LinkError: 97 return err.Err 98 case *os.SyscallError: 99 return err.Err 100 } 101 return err 102 }