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  }