vendor: update buildkit to v0.15.0-rc1

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi
2024-07-03 11:39:35 -07:00
parent 74374ea418
commit 50aa895477
82 changed files with 2379 additions and 1183 deletions

114
vendor/github.com/gofrs/flock/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,114 @@
run:
timeout: 10m
linters:
enable:
- asasalint
- bidichk
- dogsled
- dupword
- durationcheck
- err113
- errname
- errorlint
- fatcontext
- forbidigo
- gocheckcompilerdirectives
- gochecknoinits
- gocritic
- godot
- godox
- gofumpt
- goheader
- goimports
- gomoddirectives
- goprintffuncname
- gosec
- inamedparam
- interfacebloat
- ireturn
- mirror
- misspell
- nolintlint
- revive
- stylecheck
- tenv
- testifylint
- thelper
- unconvert
- unparam
- usestdlibvars
- whitespace
linters-settings:
misspell:
locale: US
godox:
keywords:
- FIXME
goheader:
template: |-
Copyright 2015 Tim Heckman. All rights reserved.
Copyright 2018-{{ YEAR }} The Gofrs. All rights reserved.
Use of this source code is governed by the BSD 3-Clause
license that can be found in the LICENSE file.
gofumpt:
extra-rules: true
gocritic:
enabled-tags:
- diagnostic
- style
- performance
disabled-checks:
- paramTypeCombine # already handle by gofumpt.extra-rules
- whyNoLint # already handle by nonolint
- unnamedResult
- hugeParam
- sloppyReassign
- rangeValCopy
- octalLiteral
- ptrToRefParam
- appendAssign
- ruleguard
- httpNoBody
- exposedSyncMutex
revive:
rules:
- name: struct-tag
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: error-return
- name: error-strings
- name: error-naming
- name: exported
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: package-comments
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: empty-block
- name: superfluous-else
- name: unused-parameter
- name: unreachable-code
- name: redefines-builtin-id
issues:
exclude-use-default: true
max-issues-per-linter: 0
max-same-issues: 0
output:
show-stats: true
sort-results: true
sort-order:
- linter
- file

View File

@ -1,10 +0,0 @@
language: go
go:
- 1.14.x
- 1.15.x
script: go test -v -check.vv -race ./...
sudo: false
notifications:
email:
on_success: never
on_failure: always

View File

@ -1,3 +1,4 @@
Copyright (c) 2018-2024, The Gofrs
Copyright (c) 2015-2020, Tim Heckman
All rights reserved.

15
vendor/github.com/gofrs/flock/Makefile generated vendored Normal file
View File

@ -0,0 +1,15 @@
.PHONY: lint test test_race build_cross_os
default: lint test build_cross_os
test:
go test -v -cover ./...
test_race:
CGO_ENABLED=1 go test -v -race ./...
lint:
golangci-lint run
build_cross_os:
./build.sh

View File

@ -1,26 +1,22 @@
# flock
[![TravisCI Build Status](https://img.shields.io/travis/gofrs/flock/master.svg?style=flat)](https://travis-ci.org/gofrs/flock)
[![GoDoc](https://img.shields.io/badge/godoc-flock-blue.svg?style=flat)](https://godoc.org/github.com/gofrs/flock)
[![Go Reference](https://pkg.go.dev/badge/github.com/gofrs/flock.svg)](https://pkg.go.dev/github.com/gofrs/flock)
[![License](https://img.shields.io/badge/license-BSD_3--Clause-brightgreen.svg?style=flat)](https://github.com/gofrs/flock/blob/master/LICENSE)
[![Go Report Card](https://goreportcard.com/badge/github.com/gofrs/flock)](https://goreportcard.com/report/github.com/gofrs/flock)
`flock` implements a thread-safe sync.Locker interface for file locking. It also
includes a non-blocking TryLock() function to allow locking without blocking execution.
`flock` implements a thread-safe file lock.
## License
`flock` is released under the BSD 3-Clause License. See the `LICENSE` file for more details.
## Go Compatibility
This package makes use of the `context` package that was introduced in Go 1.7. As such, this
package has an implicit dependency on Go 1.7+.
It also includes a non-blocking `TryLock()` function to allow locking without blocking execution.
## Installation
```
```bash
go get -u github.com/gofrs/flock
```
## Usage
```Go
```go
import "github.com/gofrs/flock"
fileLock := flock.New("/var/lock/go-lock.lock")
@ -38,4 +34,12 @@ if locked {
```
For more detailed usage information take a look at the package API docs on
[GoDoc](https://godoc.org/github.com/gofrs/flock).
[GoDoc](https://pkg.go.dev/github.com/gofrs/flock).
## License
`flock` is released under the BSD 3-Clause License. See the [`LICENSE`](./LICENSE) file for more details.
## Project History
This project was originally `github.com/theckman/go-flock`, it was transferred to Gofrs by the original author [Tim Heckman ](https://github.com/theckman).

21
vendor/github.com/gofrs/flock/SECURITY.md generated vendored Normal file
View File

@ -0,0 +1,21 @@
# Security Policy
## Supported Versions
We support the latest version of this library.
We do not guarantee support of previous versions.
If a defect is reported, it will generally be fixed on the latest version (provided it exists) irrespective of whether it was introduced in a prior version.
## Reporting a Vulnerability
To report a potential security vulnerability, please create a [security advisory](https://github.com/gofrs/flock/security/advisories/new).
For us to respond to your report most effectively, please include any of the following:
- Steps to reproduce or a proof-of-concept
- Any relevant information, including the versions used
## Security Scorecard
This project submits security [results](https://scorecard.dev/viewer/?uri=github.com/gofrs/flock) to the [OpenSSF Scorecard](https://securityscorecards.dev/).

View File

@ -1,25 +0,0 @@
version: '{build}'
build: false
deploy: false
clone_folder: 'c:\gopath\src\github.com\gofrs\flock'
environment:
GOPATH: 'c:\gopath'
GOVERSION: '1.15'
init:
- git config --global core.autocrlf input
install:
- rmdir c:\go /s /q
- appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi
- msiexec /i go%GOVERSION%.windows-amd64.msi /q
- set Path=c:\go\bin;c:\gopath\bin;%Path%
- go version
- go env
test_script:
- go get -t ./...
- go test -race -v ./...

18
vendor/github.com/gofrs/flock/build.sh generated vendored Normal file
View File

@ -0,0 +1,18 @@
#!/bin/bash -e
# Not supported by flock:
# - plan9/*
# - js/wasm
# - wasp1/wasm
for row in $(go tool dist list -json | jq -r '.[] | @base64'); do
_jq() {
echo ${row} | base64 --decode | jq -r ${1}
}
GOOS=$(_jq '.GOOS')
GOARCH=$(_jq '.GOARCH')
echo "$GOOS/$GOARCH"
GOOS=$GOOS GOARCH=$GOARCH go build
done

View File

@ -1,4 +1,5 @@
// Copyright 2015 Tim Heckman. All rights reserved.
// Copyright 2018-2024 The Gofrs. All rights reserved.
// Use of this source code is governed by the BSD 3-Clause
// license that can be found in the LICENSE file.
@ -18,12 +19,29 @@ package flock
import (
"context"
"io/fs"
"os"
"runtime"
"sync"
"time"
)
type Option func(f *Flock)
// SetFlag sets the flag used to create/open the file.
func SetFlag(flag int) Option {
return func(f *Flock) {
f.flag = flag
}
}
// SetPermissions sets the OS permissions to set on the file.
func SetPermissions(perm fs.FileMode) Option {
return func(f *Flock) {
f.perm = perm
}
}
// Flock is the struct type to handle file locking. All fields are unexported,
// with access to some of the fields provided by getter methods (Path() and Locked()).
type Flock struct {
@ -32,12 +50,37 @@ type Flock struct {
fh *os.File
l bool
r bool
// flag is the flag used to create/open the file.
flag int
// perm is the OS permissions to set on the file.
perm fs.FileMode
}
// New returns a new instance of *Flock. The only parameter
// it takes is the path to the desired lockfile.
func New(path string) *Flock {
return &Flock{path: path}
func New(path string, opts ...Option) *Flock {
// create it if it doesn't exist, and open the file read-only.
flags := os.O_CREATE
switch runtime.GOOS {
case "aix", "solaris", "illumos":
// AIX cannot preform write-lock (i.e. exclusive) on a read-only file.
flags |= os.O_RDWR
default:
flags |= os.O_RDONLY
}
f := &Flock{
path: path,
flag: flags,
perm: fs.FileMode(0o600),
}
for _, opt := range opts {
opt(f)
}
return f
}
// NewFlock returns a new instance of *Flock. The only parameter
@ -67,6 +110,7 @@ func (f *Flock) Path() string {
func (f *Flock) Locked() bool {
f.m.RLock()
defer f.m.RUnlock()
return f.l
}
@ -76,6 +120,7 @@ func (f *Flock) Locked() bool {
func (f *Flock) RLocked() bool {
f.m.RLock()
defer f.m.RUnlock()
return f.r
}
@ -83,16 +128,18 @@ func (f *Flock) String() string {
return f.path
}
// TryLockContext repeatedly tries to take an exclusive lock until one of the
// conditions is met: TryLock succeeds, TryLock fails with error, or Context
// Done channel is closed.
// TryLockContext repeatedly tries to take an exclusive lock until one of the conditions is met:
// - TryLock succeeds
// - TryLock fails with error
// - Context Done channel is closed.
func (f *Flock) TryLockContext(ctx context.Context, retryDelay time.Duration) (bool, error) {
return tryCtx(ctx, f.TryLock, retryDelay)
}
// TryRLockContext repeatedly tries to take a shared lock until one of the
// conditions is met: TryRLock succeeds, TryRLock fails with error, or Context
// Done channel is closed.
// TryRLockContext repeatedly tries to take a shared lock until one of the conditions is met:
// - TryRLock succeeds
// - TryRLock fails with error
// - Context Done channel is closed.
func (f *Flock) TryRLockContext(ctx context.Context, retryDelay time.Duration) (bool, error) {
return tryCtx(ctx, f.TryRLock, retryDelay)
}
@ -101,10 +148,12 @@ func tryCtx(ctx context.Context, fn func() (bool, error), retryDelay time.Durati
if ctx.Err() != nil {
return false, ctx.Err()
}
for {
if ok, err := fn(); ok || err != nil {
return ok, err
}
select {
case <-ctx.Done():
return false, ctx.Err()
@ -116,29 +165,33 @@ func tryCtx(ctx context.Context, fn func() (bool, error), retryDelay time.Durati
func (f *Flock) setFh() error {
// open a new os.File instance
// create it if it doesn't exist, and open the file read-only.
flags := os.O_CREATE
if runtime.GOOS == "aix" {
// AIX cannot preform write-lock (ie exclusive) on a
// read-only file.
flags |= os.O_RDWR
} else {
flags |= os.O_RDONLY
}
fh, err := os.OpenFile(f.path, flags, os.FileMode(0600))
fh, err := os.OpenFile(f.path, f.flag, f.perm)
if err != nil {
return err
}
// set the filehandle on the struct
// set the file handle on the struct
f.fh = fh
return nil
}
// ensure the file handle is closed if no lock is held
// ensure the file handle is closed if no lock is held.
func (f *Flock) ensureFhState() {
if !f.l && !f.r && f.fh != nil {
f.fh.Close()
f.fh = nil
if f.l || f.r || f.fh == nil {
return
}
_ = f.fh.Close()
f.fh = nil
}
func (f *Flock) reset() {
f.l = false
f.r = false
_ = f.fh.Close()
f.fh = nil
}

View File

@ -1,281 +0,0 @@
// Copyright 2019 Tim Heckman. All rights reserved. Use of this source code is
// governed by the BSD 3-Clause license that can be found in the LICENSE file.
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This code implements the filelock API using POSIX 'fcntl' locks, which attach
// to an (inode, process) pair rather than a file descriptor. To avoid unlocking
// files prematurely when the same file is opened through different descriptors,
// we allow only one read-lock at a time.
//
// This code is adapted from the Go package:
// cmd/go/internal/lockedfile/internal/filelock
//+build aix
package flock
import (
"errors"
"io"
"os"
"sync"
"syscall"
"golang.org/x/sys/unix"
)
type lockType int16
const (
readLock lockType = unix.F_RDLCK
writeLock lockType = unix.F_WRLCK
)
type cmdType int
const (
tryLock cmdType = unix.F_SETLK
waitLock cmdType = unix.F_SETLKW
)
type inode = uint64
type inodeLock struct {
owner *Flock
queue []<-chan *Flock
}
var (
mu sync.Mutex
inodes = map[*Flock]inode{}
locks = map[inode]inodeLock{}
)
// Lock is a blocking call to try and take an exclusive file lock. It will wait
// until it is able to obtain the exclusive file lock. It's recommended that
// TryLock() be used over this function. This function may block the ability to
// query the current Locked() or RLocked() status due to a RW-mutex lock.
//
// If we are already exclusive-locked, this function short-circuits and returns
// immediately assuming it can take the mutex lock.
//
// If the *Flock has a shared lock (RLock), this may transparently replace the
// shared lock with an exclusive lock on some UNIX-like operating systems. Be
// careful when using exclusive locks in conjunction with shared locks
// (RLock()), because calling Unlock() may accidentally release the exclusive
// lock that was once a shared lock.
func (f *Flock) Lock() error {
return f.lock(&f.l, writeLock)
}
// RLock is a blocking call to try and take a shared file lock. It will wait
// until it is able to obtain the shared file lock. It's recommended that
// TryRLock() be used over this function. This function may block the ability to
// query the current Locked() or RLocked() status due to a RW-mutex lock.
//
// If we are already shared-locked, this function short-circuits and returns
// immediately assuming it can take the mutex lock.
func (f *Flock) RLock() error {
return f.lock(&f.r, readLock)
}
func (f *Flock) lock(locked *bool, flag lockType) error {
f.m.Lock()
defer f.m.Unlock()
if *locked {
return nil
}
if f.fh == nil {
if err := f.setFh(); err != nil {
return err
}
defer f.ensureFhState()
}
if _, err := f.doLock(waitLock, flag, true); err != nil {
return err
}
*locked = true
return nil
}
func (f *Flock) doLock(cmd cmdType, lt lockType, blocking bool) (bool, error) {
// POSIX locks apply per inode and process, and the lock for an inode is
// released when *any* descriptor for that inode is closed. So we need to
// synchronize access to each inode internally, and must serialize lock and
// unlock calls that refer to the same inode through different descriptors.
fi, err := f.fh.Stat()
if err != nil {
return false, err
}
ino := inode(fi.Sys().(*syscall.Stat_t).Ino)
mu.Lock()
if i, dup := inodes[f]; dup && i != ino {
mu.Unlock()
return false, &os.PathError{
Path: f.Path(),
Err: errors.New("inode for file changed since last Lock or RLock"),
}
}
inodes[f] = ino
var wait chan *Flock
l := locks[ino]
if l.owner == f {
// This file already owns the lock, but the call may change its lock type.
} else if l.owner == nil {
// No owner: it's ours now.
l.owner = f
} else if !blocking {
// Already owned: cannot take the lock.
mu.Unlock()
return false, nil
} else {
// Already owned: add a channel to wait on.
wait = make(chan *Flock)
l.queue = append(l.queue, wait)
}
locks[ino] = l
mu.Unlock()
if wait != nil {
wait <- f
}
err = setlkw(f.fh.Fd(), cmd, lt)
if err != nil {
f.doUnlock()
if cmd == tryLock && err == unix.EACCES {
return false, nil
}
return false, err
}
return true, nil
}
func (f *Flock) Unlock() error {
f.m.Lock()
defer f.m.Unlock()
// if we aren't locked or if the lockfile instance is nil
// just return a nil error because we are unlocked
if (!f.l && !f.r) || f.fh == nil {
return nil
}
if err := f.doUnlock(); err != nil {
return err
}
f.fh.Close()
f.l = false
f.r = false
f.fh = nil
return nil
}
func (f *Flock) doUnlock() (err error) {
var owner *Flock
mu.Lock()
ino, ok := inodes[f]
if ok {
owner = locks[ino].owner
}
mu.Unlock()
if owner == f {
err = setlkw(f.fh.Fd(), waitLock, unix.F_UNLCK)
}
mu.Lock()
l := locks[ino]
if len(l.queue) == 0 {
// No waiters: remove the map entry.
delete(locks, ino)
} else {
// The first waiter is sending us their file now.
// Receive it and update the queue.
l.owner = <-l.queue[0]
l.queue = l.queue[1:]
locks[ino] = l
}
delete(inodes, f)
mu.Unlock()
return err
}
// TryLock is the preferred function for taking an exclusive file lock. This
// function takes an RW-mutex lock before it tries to lock the file, so there is
// the possibility that this function may block for a short time if another
// goroutine is trying to take any action.
//
// The actual file lock is non-blocking. If we are unable to get the exclusive
// file lock, the function will return false instead of waiting for the lock. If
// we get the lock, we also set the *Flock instance as being exclusive-locked.
func (f *Flock) TryLock() (bool, error) {
return f.try(&f.l, writeLock)
}
// TryRLock is the preferred function for taking a shared file lock. This
// function takes an RW-mutex lock before it tries to lock the file, so there is
// the possibility that this function may block for a short time if another
// goroutine is trying to take any action.
//
// The actual file lock is non-blocking. If we are unable to get the shared file
// lock, the function will return false instead of waiting for the lock. If we
// get the lock, we also set the *Flock instance as being share-locked.
func (f *Flock) TryRLock() (bool, error) {
return f.try(&f.r, readLock)
}
func (f *Flock) try(locked *bool, flag lockType) (bool, error) {
f.m.Lock()
defer f.m.Unlock()
if *locked {
return true, nil
}
if f.fh == nil {
if err := f.setFh(); err != nil {
return false, err
}
defer f.ensureFhState()
}
haslock, err := f.doLock(tryLock, flag, false)
if err != nil {
return false, err
}
*locked = haslock
return haslock, nil
}
// setlkw calls FcntlFlock with cmd for the entire file indicated by fd.
func setlkw(fd uintptr, cmd cmdType, lt lockType) error {
for {
err := unix.FcntlFlock(fd, int(cmd), &unix.Flock_t{
Type: int16(lt),
Whence: io.SeekStart,
Start: 0,
Len: 0, // All bytes.
})
if err != unix.EINTR {
return err
}
}
}

40
vendor/github.com/gofrs/flock/flock_others.go generated vendored Normal file
View File

@ -0,0 +1,40 @@
//go:build (!unix && !windows) || plan9
package flock
import (
"errors"
"io/fs"
)
func (f *Flock) Lock() error {
return &fs.PathError{
Op: "Lock",
Path: f.Path(),
Err: errors.ErrUnsupported,
}
}
func (f *Flock) RLock() error {
return &fs.PathError{
Op: "RLock",
Path: f.Path(),
Err: errors.ErrUnsupported,
}
}
func (f *Flock) Unlock() error {
return &fs.PathError{
Op: "Unlock",
Path: f.Path(),
Err: errors.ErrUnsupported,
}
}
func (f *Flock) TryLock() (bool, error) {
return false, f.Lock()
}
func (f *Flock) TryRLock() (bool, error) {
return false, f.RLock()
}

View File

@ -1,42 +1,44 @@
// Copyright 2015 Tim Heckman. All rights reserved.
// Copyright 2018-2024 The Gofrs. All rights reserved.
// Use of this source code is governed by the BSD 3-Clause
// license that can be found in the LICENSE file.
// +build !aix,!windows
//go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd
package flock
import (
"errors"
"os"
"syscall"
"golang.org/x/sys/unix"
)
// Lock is a blocking call to try and take an exclusive file lock. It will wait
// until it is able to obtain the exclusive file lock. It's recommended that
// TryLock() be used over this function. This function may block the ability to
// query the current Locked() or RLocked() status due to a RW-mutex lock.
// Lock is a blocking call to try and take an exclusive file lock.
// It will wait until it is able to obtain the exclusive file lock.
// It's recommended that TryLock() be used over this function.
// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock.
//
// If we are already exclusive-locked, this function short-circuits and returns
// immediately assuming it can take the mutex lock.
// If we are already exclusive-locked,
// this function short-circuits and returns immediately assuming it can take the mutex lock.
//
// If the *Flock has a shared lock (RLock), this may transparently replace the
// shared lock with an exclusive lock on some UNIX-like operating systems. Be
// careful when using exclusive locks in conjunction with shared locks
// (RLock()), because calling Unlock() may accidentally release the exclusive
// lock that was once a shared lock.
// If the *Flock has a shared lock (RLock),
// this may transparently replace the shared lock with an exclusive lock on some UNIX-like operating systems.
// Be careful when using exclusive locks in conjunction with shared locks (RLock()),
// because calling Unlock() may accidentally release the exclusive lock that was once a shared lock.
func (f *Flock) Lock() error {
return f.lock(&f.l, syscall.LOCK_EX)
return f.lock(&f.l, unix.LOCK_EX)
}
// RLock is a blocking call to try and take a shared file lock. It will wait
// until it is able to obtain the shared file lock. It's recommended that
// TryRLock() be used over this function. This function may block the ability to
// query the current Locked() or RLocked() status due to a RW-mutex lock.
// RLock is a blocking call to try and take a shared file lock.
// It will wait until it is able to obtain the shared file lock.
// It's recommended that TryRLock() be used over this function.
// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock.
//
// If we are already shared-locked, this function short-circuits and returns
// immediately assuming it can take the mutex lock.
// If we are already shared-locked,
// this function short-circuits and returns immediately assuming it can take the mutex lock.
func (f *Flock) RLock() error {
return f.lock(&f.r, syscall.LOCK_SH)
return f.lock(&f.r, unix.LOCK_SH)
}
func (f *Flock) lock(locked *bool, flag int) error {
@ -51,10 +53,12 @@ func (f *Flock) lock(locked *bool, flag int) error {
if err := f.setFh(); err != nil {
return err
}
defer f.ensureFhState()
}
if err := syscall.Flock(int(f.fh.Fd()), flag); err != nil {
err := unix.Flock(int(f.fh.Fd()), flag)
if err != nil {
shouldRetry, reopenErr := f.reopenFDOnError(err)
if reopenErr != nil {
return reopenErr
@ -64,71 +68,74 @@ func (f *Flock) lock(locked *bool, flag int) error {
return err
}
if err = syscall.Flock(int(f.fh.Fd()), flag); err != nil {
err = unix.Flock(int(f.fh.Fd()), flag)
if err != nil {
return err
}
}
*locked = true
return nil
}
// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
// while it is running the Locked() and RLocked() functions will be blocked.
// Unlock is a function to unlock the file.
// This file takes a RW-mutex lock,
// so while it is running the Locked() and RLocked() functions will be blocked.
//
// This function short-circuits if we are unlocked already. If not, it calls
// syscall.LOCK_UN on the file and closes the file descriptor. It does not
// remove the file from disk. It's up to your application to do.
// This function short-circuits if we are unlocked already.
// If not, it calls unix.LOCK_UN on the file and closes the file descriptor.
// It does not remove the file from disk. It's up to your application to do.
//
// Please note, if your shared lock became an exclusive lock this may
// unintentionally drop the exclusive lock if called by the consumer that
// believes they have a shared lock. Please see Lock() for more details.
// Please note,
// if your shared lock became an exclusive lock,
// this may unintentionally drop the exclusive lock if called by the consumer that believes they have a shared lock.
// Please see Lock() for more details.
func (f *Flock) Unlock() error {
f.m.Lock()
defer f.m.Unlock()
// if we aren't locked or if the lockfile instance is nil
// just return a nil error because we are unlocked
// If we aren't locked or if the lockfile instance is nil
// just return a nil error because we are unlocked.
if (!f.l && !f.r) || f.fh == nil {
return nil
}
// mark the file as unlocked
if err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_UN); err != nil {
// Mark the file as unlocked.
err := unix.Flock(int(f.fh.Fd()), unix.LOCK_UN)
if err != nil {
return err
}
f.fh.Close()
f.l = false
f.r = false
f.fh = nil
f.reset()
return nil
}
// TryLock is the preferred function for taking an exclusive file lock. This
// function takes an RW-mutex lock before it tries to lock the file, so there is
// the possibility that this function may block for a short time if another
// goroutine is trying to take any action.
// TryLock is the preferred function for taking an exclusive file lock.
// This function takes an RW-mutex lock before it tries to lock the file,
// so there is the possibility that this function may block for a short time
// if another goroutine is trying to take any action.
//
// The actual file lock is non-blocking. If we are unable to get the exclusive
// file lock, the function will return false instead of waiting for the lock. If
// we get the lock, we also set the *Flock instance as being exclusive-locked.
// The actual file lock is non-blocking.
// If we are unable to get the exclusive file lock,
// the function will return false instead of waiting for the lock.
// If we get the lock, we also set the *Flock instance as being exclusive-locked.
func (f *Flock) TryLock() (bool, error) {
return f.try(&f.l, syscall.LOCK_EX)
return f.try(&f.l, unix.LOCK_EX)
}
// TryRLock is the preferred function for taking a shared file lock. This
// function takes an RW-mutex lock before it tries to lock the file, so there is
// the possibility that this function may block for a short time if another
// goroutine is trying to take any action.
// TryRLock is the preferred function for taking a shared file lock.
// This function takes an RW-mutex lock before it tries to lock the file,
// so there is the possibility that this function may block for a short time
// if another goroutine is trying to take any action.
//
// The actual file lock is non-blocking. If we are unable to get the shared file
// lock, the function will return false instead of waiting for the lock. If we
// get the lock, we also set the *Flock instance as being share-locked.
// The actual file lock is non-blocking.
// If we are unable to get the shared file lock,
// the function will return false instead of waiting for the lock.
// If we get the lock, we also set the *Flock instance as being share-locked.
func (f *Flock) TryRLock() (bool, error) {
return f.try(&f.r, syscall.LOCK_SH)
return f.try(&f.r, unix.LOCK_SH)
}
func (f *Flock) try(locked *bool, flag int) (bool, error) {
@ -143,22 +150,25 @@ func (f *Flock) try(locked *bool, flag int) (bool, error) {
if err := f.setFh(); err != nil {
return false, err
}
defer f.ensureFhState()
}
var retried bool
retry:
err := syscall.Flock(int(f.fh.Fd()), flag|syscall.LOCK_NB)
err := unix.Flock(int(f.fh.Fd()), flag|unix.LOCK_NB)
switch err {
case syscall.EWOULDBLOCK:
switch {
case errors.Is(err, unix.EWOULDBLOCK):
return false, nil
case nil:
case err == nil:
*locked = true
return true, nil
}
if !retried {
if shouldRetry, reopenErr := f.reopenFDOnError(err); reopenErr != nil {
shouldRetry, reopenErr := f.reopenFDOnError(err)
if reopenErr != nil {
return false, reopenErr
} else if shouldRetry {
retried = true
@ -169,29 +179,34 @@ retry:
return false, err
}
// reopenFDOnError determines whether we should reopen the file handle
// in readwrite mode and try again. This comes from util-linux/sys-utils/flock.c:
// Since Linux 3.4 (commit 55725513)
// Probably NFSv4 where flock() is emulated by fcntl().
// reopenFDOnError determines whether we should reopen the file handle in readwrite mode and try again.
// This comes from `util-linux/sys-utils/flock.c`:
// > Since Linux 3.4 (commit 55725513)
// > Probably NFSv4 where flock() is emulated by fcntl().
func (f *Flock) reopenFDOnError(err error) (bool, error) {
if err != syscall.EIO && err != syscall.EBADF {
if !errors.Is(err, unix.EIO) && !errors.Is(err, unix.EBADF) {
return false, nil
}
if st, err := f.fh.Stat(); err == nil {
// if the file is able to be read and written
if st.Mode()&0600 == 0600 {
f.fh.Close()
f.fh = nil
// reopen in read-write mode and set the filehandle
fh, err := os.OpenFile(f.path, os.O_CREATE|os.O_RDWR, os.FileMode(0600))
if err != nil {
return false, err
}
f.fh = fh
return true, nil
}
st, err := f.fh.Stat()
if err != nil {
return false, nil
}
return false, nil
if st.Mode()&f.perm != f.perm {
return false, nil
}
_ = f.fh.Close()
f.fh = nil
// reopen in read-write mode and set the file handle
fh, err := os.OpenFile(f.path, f.flag, f.perm)
if err != nil {
return false, err
}
f.fh = fh
return true, nil
}

393
vendor/github.com/gofrs/flock/flock_unix_fcntl.go generated vendored Normal file
View File

@ -0,0 +1,393 @@
// Copyright 2015 Tim Heckman. All rights reserved.
// Copyright 2018-2024 The Gofrs. All rights reserved.
// Use of this source code is governed by the BSD 3-Clause
// license that can be found in the LICENSE file.
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This code implements the filelock API using POSIX 'fcntl' locks,
// which attach to an (inode, process) pair rather than a file descriptor.
// To avoid unlocking files prematurely when the same file is opened through different descriptors,
// we allow only one read-lock at a time.
//
// This code is adapted from the Go package (go.22):
// https://github.com/golang/go/blob/release-branch.go1.22/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go
//go:build aix || (solaris && !illumos)
package flock
import (
"errors"
"io"
"io/fs"
"math/rand"
"sync"
"syscall"
"time"
"golang.org/x/sys/unix"
)
// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L28
type lockType int16
// String returns the name of the function corresponding to lt
// (Lock, RLock, or Unlock).
// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go#L67
func (lt lockType) String() string {
switch lt {
case readLock:
return "RLock"
case writeLock:
return "Lock"
default:
return "Unlock"
}
}
// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L30-L33
const (
readLock lockType = unix.F_RDLCK
writeLock lockType = unix.F_WRLCK
)
// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L35
type inode = uint64
// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L37-L40
type inodeLock struct {
owner *Flock
queue []<-chan *Flock
}
type cmdType int
const (
tryLock cmdType = unix.F_SETLK
waitLock cmdType = unix.F_SETLKW
)
var (
mu sync.Mutex
inodes = map[*Flock]inode{}
locks = map[inode]inodeLock{}
)
// Lock is a blocking call to try and take an exclusive file lock.
// It will wait until it is able to obtain the exclusive file lock.
// It's recommended that TryLock() be used over this function.
// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock.
//
// If we are already exclusive-locked, this function short-circuits and
// returns immediately assuming it can take the mutex lock.
//
// If the *Flock has a shared lock (RLock),
// this may transparently replace the shared lock with an exclusive lock on some UNIX-like operating systems.
// Be careful when using exclusive locks in conjunction with shared locks (RLock()),
// because calling Unlock() may accidentally release the exclusive lock that was once a shared lock.
func (f *Flock) Lock() error {
return f.lock(&f.l, writeLock)
}
// RLock is a blocking call to try and take a shared file lock.
// It will wait until it is able to obtain the shared file lock.
// It's recommended that TryRLock() be used over this function.
// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock.
//
// If we are already shared-locked, this function short-circuits and
// returns immediately assuming it can take the mutex lock.
func (f *Flock) RLock() error {
return f.lock(&f.r, readLock)
}
func (f *Flock) lock(locked *bool, flag lockType) error {
f.m.Lock()
defer f.m.Unlock()
if *locked {
return nil
}
if f.fh == nil {
if err := f.setFh(); err != nil {
return err
}
defer f.ensureFhState()
}
_, err := f.doLock(waitLock, flag, true)
if err != nil {
return err
}
*locked = true
return nil
}
// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L48
func (f *Flock) doLock(cmd cmdType, lt lockType, blocking bool) (bool, error) {
// POSIX locks apply per inode and process,
// and the lock for an inode is released when *any* descriptor for that inode is closed.
// So we need to synchronize access to each inode internally,
// and must serialize lock and unlock calls that refer to the same inode through different descriptors.
fi, err := f.fh.Stat()
if err != nil {
return false, err
}
// Note(ldez): don't replace `syscall.Stat_t` by `unix.Stat_t` because `FileInfo.Sys()` returns `syscall.Stat_t`
ino := fi.Sys().(*syscall.Stat_t).Ino
mu.Lock()
if i, dup := inodes[f]; dup && i != ino {
mu.Unlock()
return false, &fs.PathError{
Op: lt.String(),
Path: f.Path(),
Err: errors.New("inode for file changed since last Lock or RLock"),
}
}
inodes[f] = ino
var wait chan *Flock
l := locks[ino]
switch {
case l.owner == f:
// This file already owns the lock, but the call may change its lock type.
case l.owner == nil:
// No owner: it's ours now.
l.owner = f
case !blocking:
// Already owned: cannot take the lock.
mu.Unlock()
return false, nil
default:
// Already owned: add a channel to wait on.
wait = make(chan *Flock)
l.queue = append(l.queue, wait)
}
locks[ino] = l
mu.Unlock()
if wait != nil {
wait <- f
}
// Spurious EDEADLK errors arise on platforms that compute deadlock graphs at
// the process, rather than thread, level. Consider processes P and Q, with
// threads P.1, P.2, and Q.3. The following trace is NOT a deadlock, but will be
// reported as a deadlock on systems that consider only process granularity:
//
// P.1 locks file A.
// Q.3 locks file B.
// Q.3 blocks on file A.
// P.2 blocks on file B. (This is erroneously reported as a deadlock.)
// P.1 unlocks file A.
// Q.3 unblocks and locks file A.
// Q.3 unlocks files A and B.
// P.2 unblocks and locks file B.
// P.2 unlocks file B.
//
// These spurious errors were observed in practice on AIX and Solaris in
// cmd/go: see https://golang.org/issue/32817.
//
// We work around this bug by treating EDEADLK as always spurious. If there
// really is a lock-ordering bug between the interacting processes, it will
// become a livelock instead, but that's not appreciably worse than if we had
// a proper flock implementation (which generally does not even attempt to
// diagnose deadlocks).
//
// In the above example, that changes the trace to:
//
// P.1 locks file A.
// Q.3 locks file B.
// Q.3 blocks on file A.
// P.2 spuriously fails to lock file B and goes to sleep.
// P.1 unlocks file A.
// Q.3 unblocks and locks file A.
// Q.3 unlocks files A and B.
// P.2 wakes up and locks file B.
// P.2 unlocks file B.
//
// We know that the retry loop will not introduce a *spurious* livelock
// because, according to the POSIX specification, EDEADLK is only to be
// returned when “the lock is blocked by a lock from another process”.
// If that process is blocked on some lock that we are holding, then the
// resulting livelock is due to a real deadlock (and would manifest as such
// when using, for example, the flock implementation of this package).
// If the other process is *not* blocked on some other lock that we are
// holding, then it will eventually release the requested lock.
nextSleep := 1 * time.Millisecond
const maxSleep = 500 * time.Millisecond
for {
err = setlkw(f.fh.Fd(), cmd, lt)
if !errors.Is(err, unix.EDEADLK) {
break
}
time.Sleep(nextSleep)
nextSleep += nextSleep
if nextSleep > maxSleep {
nextSleep = maxSleep
}
// Apply 10% jitter to avoid synchronizing collisions when we finally unblock.
nextSleep += time.Duration((0.1*rand.Float64() - 0.05) * float64(nextSleep))
}
if err != nil {
f.doUnlock()
if cmd == tryLock && errors.Is(err, unix.EACCES) {
return false, nil
}
return false, &fs.PathError{
Op: lt.String(),
Path: f.Path(),
Err: err,
}
}
return true, nil
}
func (f *Flock) Unlock() error {
f.m.Lock()
defer f.m.Unlock()
// If we aren't locked or if the lockfile instance is nil
// just return a nil error because we are unlocked.
if (!f.l && !f.r) || f.fh == nil {
return nil
}
if err := f.doUnlock(); err != nil {
return err
}
f.reset()
return nil
}
// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L163
func (f *Flock) doUnlock() (err error) {
var owner *Flock
mu.Lock()
ino, ok := inodes[f]
if ok {
owner = locks[ino].owner
}
mu.Unlock()
if owner == f {
err = setlkw(f.fh.Fd(), waitLock, unix.F_UNLCK)
}
mu.Lock()
l := locks[ino]
if len(l.queue) == 0 {
// No waiters: remove the map entry.
delete(locks, ino)
} else {
// The first waiter is sending us their file now.
// Receive it and update the queue.
l.owner = <-l.queue[0]
l.queue = l.queue[1:]
locks[ino] = l
}
delete(inodes, f)
mu.Unlock()
return err
}
// TryLock is the preferred function for taking an exclusive file lock.
// This function takes an RW-mutex lock before it tries to lock the file,
// so there is the possibility that this function may block for a short time
// if another goroutine is trying to take any action.
//
// The actual file lock is non-blocking.
// If we are unable to get the exclusive file lock,
// the function will return false instead of waiting for the lock.
// If we get the lock, we also set the *Flock instance as being exclusive-locked.
func (f *Flock) TryLock() (bool, error) {
return f.try(&f.l, writeLock)
}
// TryRLock is the preferred function for taking a shared file lock.
// This function takes an RW-mutex lock before it tries to lock the file,
// so there is the possibility that this function may block for a short time
// if another goroutine is trying to take any action.
//
// The actual file lock is non-blocking.
// If we are unable to get the shared file lock,
// the function will return false instead of waiting for the lock.
// If we get the lock, we also set the *Flock instance as being share-locked.
func (f *Flock) TryRLock() (bool, error) {
return f.try(&f.r, readLock)
}
func (f *Flock) try(locked *bool, flag lockType) (bool, error) {
f.m.Lock()
defer f.m.Unlock()
if *locked {
return true, nil
}
if f.fh == nil {
if err := f.setFh(); err != nil {
return false, err
}
defer f.ensureFhState()
}
hasLock, err := f.doLock(tryLock, flag, false)
if err != nil {
return false, err
}
*locked = hasLock
return hasLock, nil
}
// setlkw calls FcntlFlock with cmd for the entire file indicated by fd.
// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L198
func setlkw(fd uintptr, cmd cmdType, lt lockType) error {
for {
err := unix.FcntlFlock(fd, int(cmd), &unix.Flock_t{
Type: int16(lt),
Whence: io.SeekStart,
Start: 0,
Len: 0, // All bytes.
})
if !errors.Is(err, unix.EINTR) {
return err
}
}
}

View File

@ -1,76 +0,0 @@
// Copyright 2015 Tim Heckman. All rights reserved.
// Use of this source code is governed by the BSD 3-Clause
// license that can be found in the LICENSE file.
// +build windows
package flock
import (
"syscall"
"unsafe"
)
var (
kernel32, _ = syscall.LoadLibrary("kernel32.dll")
procLockFileEx, _ = syscall.GetProcAddress(kernel32, "LockFileEx")
procUnlockFileEx, _ = syscall.GetProcAddress(kernel32, "UnlockFileEx")
)
const (
winLockfileFailImmediately = 0x00000001
winLockfileExclusiveLock = 0x00000002
winLockfileSharedLock = 0x00000000
)
// Use of 0x00000000 for the shared lock is a guess based on some the MS Windows
// `LockFileEX` docs, which document the `LOCKFILE_EXCLUSIVE_LOCK` flag as:
//
// > The function requests an exclusive lock. Otherwise, it requests a shared
// > lock.
//
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
func lockFileEx(handle syscall.Handle, flags uint32, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (bool, syscall.Errno) {
r1, _, errNo := syscall.Syscall6(
uintptr(procLockFileEx),
6,
uintptr(handle),
uintptr(flags),
uintptr(reserved),
uintptr(numberOfBytesToLockLow),
uintptr(numberOfBytesToLockHigh),
uintptr(unsafe.Pointer(offset)))
if r1 != 1 {
if errNo == 0 {
return false, syscall.EINVAL
}
return false, errNo
}
return true, 0
}
func unlockFileEx(handle syscall.Handle, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (bool, syscall.Errno) {
r1, _, errNo := syscall.Syscall6(
uintptr(procUnlockFileEx),
5,
uintptr(handle),
uintptr(reserved),
uintptr(numberOfBytesToLockLow),
uintptr(numberOfBytesToLockHigh),
uintptr(unsafe.Pointer(offset)),
0)
if r1 != 1 {
if errNo == 0 {
return false, syscall.EINVAL
}
return false, errNo
}
return true, 0
}

View File

@ -1,35 +1,48 @@
// Copyright 2015 Tim Heckman. All rights reserved.
// Copyright 2018-2024 The Gofrs. All rights reserved.
// Use of this source code is governed by the BSD 3-Clause
// license that can be found in the LICENSE file.
//go:build windows
package flock
import (
"syscall"
"errors"
"golang.org/x/sys/windows"
)
// ErrorLockViolation is the error code returned from the Windows syscall when a
// lock would block and you ask to fail immediately.
const ErrorLockViolation syscall.Errno = 0x21 // 33
// Lock is a blocking call to try and take an exclusive file lock. It will wait
// until it is able to obtain the exclusive file lock. It's recommended that
// TryLock() be used over this function. This function may block the ability to
// query the current Locked() or RLocked() status due to a RW-mutex lock.
// Use of 0x00000000 for the shared lock is a guess based on some the MS Windows `LockFileEX` docs,
// which document the `LOCKFILE_EXCLUSIVE_LOCK` flag as:
//
// If we are already locked, this function short-circuits and returns
// immediately assuming it can take the mutex lock.
// > The function requests an exclusive lock. Otherwise, it requests a shared lock.
//
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
const winLockfileSharedLock = 0x00000000
// ErrorLockViolation is the error code returned from the Windows syscall when a lock would block,
// and you ask to fail immediately.
const ErrorLockViolation windows.Errno = 0x21 // 33
// Lock is a blocking call to try and take an exclusive file lock.
// It will wait until it is able to obtain the exclusive file lock.
// It's recommended that TryLock() be used over this function.
// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock.
//
// If we are already locked, this function short-circuits and
// returns immediately assuming it can take the mutex lock.
func (f *Flock) Lock() error {
return f.lock(&f.l, winLockfileExclusiveLock)
return f.lock(&f.l, windows.LOCKFILE_EXCLUSIVE_LOCK)
}
// RLock is a blocking call to try and take a shared file lock. It will wait
// until it is able to obtain the shared file lock. It's recommended that
// TryRLock() be used over this function. This function may block the ability to
// query the current Locked() or RLocked() status due to a RW-mutex lock.
// RLock is a blocking call to try and take a shared file lock.
// It will wait until it is able to obtain the shared file lock.
// It's recommended that TryRLock() be used over this function.
// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock.
//
// If we are already locked, this function short-circuits and returns
// immediately assuming it can take the mutex lock.
// If we are already locked, this function short-circuits and
// returns immediately assuming it can take the mutex lock.
func (f *Flock) RLock() error {
return f.lock(&f.r, winLockfileSharedLock)
}
@ -46,23 +59,28 @@ func (f *Flock) lock(locked *bool, flag uint32) error {
if err := f.setFh(); err != nil {
return err
}
defer f.ensureFhState()
}
if _, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), flag, 0, 1, 0, &syscall.Overlapped{}); errNo > 0 {
return errNo
err := windows.LockFileEx(windows.Handle(f.fh.Fd()), flag, 0, 1, 0, &windows.Overlapped{})
if err != nil && !errors.Is(err, windows.Errno(0)) {
return err
}
*locked = true
return nil
}
// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
// while it is running the Locked() and RLocked() functions will be blocked.
// Unlock is a function to unlock the file.
// This file takes a RW-mutex lock,
// so while it is running the Locked() and RLocked() functions will be blocked.
//
// This function short-circuits if we are unlocked already. If not, it calls
// UnlockFileEx() on the file and closes the file descriptor. It does not remove
// the file from disk. It's up to your application to do.
// This function short-circuits if we are unlocked already.
// If not, it calls UnlockFileEx() on the file and closes the file descriptor.
// It does not remove the file from disk.
// It's up to your application to do.
func (f *Flock) Unlock() error {
f.m.Lock()
defer f.m.Unlock()
@ -74,39 +92,37 @@ func (f *Flock) Unlock() error {
}
// mark the file as unlocked
if _, errNo := unlockFileEx(syscall.Handle(f.fh.Fd()), 0, 1, 0, &syscall.Overlapped{}); errNo > 0 {
return errNo
err := windows.UnlockFileEx(windows.Handle(f.fh.Fd()), 0, 1, 0, &windows.Overlapped{})
if err != nil && !errors.Is(err, windows.Errno(0)) {
return err
}
f.fh.Close()
f.l = false
f.r = false
f.fh = nil
f.reset()
return nil
}
// TryLock is the preferred function for taking an exclusive file lock. This
// function does take a RW-mutex lock before it tries to lock the file, so there
// is the possibility that this function may block for a short time if another
// goroutine is trying to take any action.
// TryLock is the preferred function for taking an exclusive file lock.
// This function does take a RW-mutex lock before it tries to lock the file,
// so there is the possibility that this function may block for a short time
// if another goroutine is trying to take any action.
//
// The actual file lock is non-blocking. If we are unable to get the exclusive
// file lock, the function will return false instead of waiting for the lock. If
// we get the lock, we also set the *Flock instance as being exclusive-locked.
// The actual file lock is non-blocking.
// If we are unable to get the exclusive file lock,
// the function will return false instead of waiting for the lock.
// If we get the lock, we also set the *Flock instance as being exclusive-locked.
func (f *Flock) TryLock() (bool, error) {
return f.try(&f.l, winLockfileExclusiveLock)
return f.try(&f.l, windows.LOCKFILE_EXCLUSIVE_LOCK)
}
// TryRLock is the preferred function for taking a shared file lock. This
// function does take a RW-mutex lock before it tries to lock the file, so there
// is the possibility that this function may block for a short time if another
// goroutine is trying to take any action.
// TryRLock is the preferred function for taking a shared file lock.
// This function does take a RW-mutex lock before it tries to lock the file,
// so there is the possibility that this function may block for a short time if another goroutine is trying to take any action.
//
// The actual file lock is non-blocking. If we are unable to get the shared file
// lock, the function will return false instead of waiting for the lock. If we
// get the lock, we also set the *Flock instance as being shared-locked.
// The actual file lock is non-blocking.
// If we are unable to get the shared file lock,
// the function will return false instead of waiting for the lock.
// If we get the lock, we also set the *Flock instance as being shared-locked.
func (f *Flock) TryRLock() (bool, error) {
return f.try(&f.r, winLockfileSharedLock)
}
@ -123,17 +139,17 @@ func (f *Flock) try(locked *bool, flag uint32) (bool, error) {
if err := f.setFh(); err != nil {
return false, err
}
defer f.ensureFhState()
}
_, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), flag|winLockfileFailImmediately, 0, 1, 0, &syscall.Overlapped{})
if errNo > 0 {
if errNo == ErrorLockViolation || errNo == syscall.ERROR_IO_PENDING {
err := windows.LockFileEx(windows.Handle(f.fh.Fd()), flag|windows.LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &windows.Overlapped{})
if err != nil && !errors.Is(err, windows.Errno(0)) {
if errors.Is(err, ErrorLockViolation) || errors.Is(err, windows.ERROR_IO_PENDING) {
return false, nil
}
return false, errNo
return false, err
}
*locked = true