//go:build !windows package version import ( "errors" "fmt" "os" "golang.org/x/sys/unix" ) func lockFile(file *os.File) error { return unix.Flock(int(file.Fd()), unix.LOCK_EX|unix.LOCK_NB) } func unlockFile(file *os.File) error { return unix.Flock(int(file.Fd()), unix.LOCK_UN) } func isLockContended(err error) bool { return errors.Is(err, unix.EWOULDBLOCK) || errors.Is(err, unix.EAGAIN) } // Locking the directory inode as well as the named file prevents another // cooperating updater from bypassing the lock by unlinking and recreating the // lock pathname while a transaction is active. func openUpdateLockAnchor(directory string) (*os.File, error) { return os.Open(directory) } func releaseUpdateLockAnchor(anchor *os.File) error { if anchor == nil { return nil } unlockErr := unlockFile(anchor) closeErr := anchor.Close() if unlockErr != nil { return fmt.Errorf("unlock update directory anchor: %w", unlockErr) } if closeErr != nil { return fmt.Errorf("close update directory anchor: %w", closeErr) } return nil } func syncDirectory(path string) error { directory, err := os.Open(path) if err != nil { return err } defer directory.Close() return directory.Sync() }