github.com/blend/go-sdk@v1.20220411.3/filelock/filelock.go (about)

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