mirror of
https://github.com/containers/skopeo.git
synced 2025-09-26 12:44:55 +00:00
Bumps [github.com/containers/storage](https://github.com/containers/storage) from 1.18.2 to 1.19.0. - [Release notes](https://github.com/containers/storage/releases) - [Changelog](https://github.com/containers/storage/blob/master/docs/containers-storage-changes.md) - [Commits](https://github.com/containers/storage/compare/v1.18.2...v1.19.0) Signed-off-by: dependabot-preview[bot] <support@dependabot.com> Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
108 lines
3.4 KiB
Go
108 lines
3.4 KiB
Go
package lockfile
|
|
|
|
import (
|
|
"path/filepath"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// A Locker represents a file lock where the file is used to cache an
|
|
// identifier of the last party that made changes to whatever's being protected
|
|
// by the lock.
|
|
type Locker interface {
|
|
// Acquire a writer lock.
|
|
// The default unix implementation panics if:
|
|
// - opening the lockfile failed
|
|
// - tried to lock a read-only lock-file
|
|
Lock()
|
|
|
|
// Acquire a writer lock recursively, allowing for recursive acquisitions
|
|
// within the same process space.
|
|
RecursiveLock()
|
|
|
|
// Unlock the lock.
|
|
// The default unix implementation panics if:
|
|
// - unlocking an unlocked lock
|
|
// - if the lock counter is corrupted
|
|
Unlock()
|
|
|
|
// Acquire a reader lock.
|
|
RLock()
|
|
|
|
// Touch records, for others sharing the lock, that the caller was the
|
|
// last writer. It should only be called with the lock held.
|
|
Touch() error
|
|
|
|
// Modified() checks if the most recent writer was a party other than the
|
|
// last recorded writer. It should only be called with the lock held.
|
|
Modified() (bool, error)
|
|
|
|
// TouchedSince() checks if the most recent writer modified the file (likely using Touch()) after the specified time.
|
|
TouchedSince(when time.Time) bool
|
|
|
|
// IsReadWrite() checks if the lock file is read-write
|
|
IsReadWrite() bool
|
|
|
|
// Locked() checks if lock is locked for writing by a thread in this process
|
|
Locked() bool
|
|
}
|
|
|
|
var (
|
|
lockfiles map[string]Locker
|
|
lockfilesLock sync.Mutex
|
|
)
|
|
|
|
// GetLockfile opens a read-write lock file, creating it if necessary. The
|
|
// Locker object may already be locked if the path has already been requested
|
|
// by the current process.
|
|
func GetLockfile(path string) (Locker, error) {
|
|
return getLockfile(path, false)
|
|
}
|
|
|
|
// GetROLockfile opens a read-only lock file, creating it if necessary. The
|
|
// Locker object may already be locked if the path has already been requested
|
|
// by the current process.
|
|
func GetROLockfile(path string) (Locker, error) {
|
|
return getLockfile(path, true)
|
|
}
|
|
|
|
// getLockfile returns a Locker object, possibly (depending on the platform)
|
|
// working inter-process, and associated with the specified path.
|
|
//
|
|
// If ro, the lock is a read-write lock and the returned Locker should correspond to the
|
|
// “lock for reading” (shared) operation; otherwise, the lock is either an exclusive lock,
|
|
// or a read-write lock and Locker should correspond to the “lock for writing” (exclusive) operation.
|
|
//
|
|
// WARNING:
|
|
// - The lock may or MAY NOT be inter-process.
|
|
// - There may or MAY NOT be an actual object on the filesystem created for the specified path.
|
|
// - Even if ro, the lock MAY be exclusive.
|
|
func getLockfile(path string, ro bool) (Locker, error) {
|
|
lockfilesLock.Lock()
|
|
defer lockfilesLock.Unlock()
|
|
if lockfiles == nil {
|
|
lockfiles = make(map[string]Locker)
|
|
}
|
|
cleanPath, err := filepath.Abs(path)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "error ensuring that path %q is an absolute path", path)
|
|
}
|
|
if locker, ok := lockfiles[cleanPath]; ok {
|
|
if ro && locker.IsReadWrite() {
|
|
return nil, errors.Errorf("lock %q is not a read-only lock", cleanPath)
|
|
}
|
|
if !ro && !locker.IsReadWrite() {
|
|
return nil, errors.Errorf("lock %q is not a read-write lock", cleanPath)
|
|
}
|
|
return locker, nil
|
|
}
|
|
locker, err := createLockerForPath(cleanPath, ro) // platform-dependent locker
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
lockfiles[cleanPath] = locker
|
|
return locker, nil
|
|
}
|