aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/gofrs
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2024-09-10 12:16:33 +0200
committerTaras Madan <tarasmadan@google.com>2024-09-10 14:05:26 +0000
commitc97c816133b42257d0bcf1ee4bd178bb2a7a2b9e (patch)
tree0bcbc2e540bbf8f62f6c17887cdd53b8c2cee637 /vendor/github.com/gofrs
parent54e657429ab892ad06c90cd7c1a4eb33ba93a3dc (diff)
vendor: update
Diffstat (limited to 'vendor/github.com/gofrs')
-rw-r--r--vendor/github.com/gofrs/flock/.golangci.yml114
-rw-r--r--vendor/github.com/gofrs/flock/.travis.yml10
-rw-r--r--vendor/github.com/gofrs/flock/LICENSE1
-rw-r--r--vendor/github.com/gofrs/flock/Makefile15
-rw-r--r--vendor/github.com/gofrs/flock/README.md32
-rw-r--r--vendor/github.com/gofrs/flock/SECURITY.md21
-rw-r--r--vendor/github.com/gofrs/flock/appveyor.yml25
-rw-r--r--vendor/github.com/gofrs/flock/build.sh18
-rw-r--r--vendor/github.com/gofrs/flock/flock.go110
-rw-r--r--vendor/github.com/gofrs/flock/flock_aix.go281
-rw-r--r--vendor/github.com/gofrs/flock/flock_others.go40
-rw-r--r--vendor/github.com/gofrs/flock/flock_unix.go179
-rw-r--r--vendor/github.com/gofrs/flock/flock_unix_fcntl.go393
-rw-r--r--vendor/github.com/gofrs/flock/flock_winapi.go76
-rw-r--r--vendor/github.com/gofrs/flock/flock_windows.go122
15 files changed, 871 insertions, 566 deletions
diff --git a/vendor/github.com/gofrs/flock/.golangci.yml b/vendor/github.com/gofrs/flock/.golangci.yml
new file mode 100644
index 000000000..3ad88a38f
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/.golangci.yml
@@ -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
diff --git a/vendor/github.com/gofrs/flock/.travis.yml b/vendor/github.com/gofrs/flock/.travis.yml
deleted file mode 100644
index b16d040fa..000000000
--- a/vendor/github.com/gofrs/flock/.travis.yml
+++ /dev/null
@@ -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
diff --git a/vendor/github.com/gofrs/flock/LICENSE b/vendor/github.com/gofrs/flock/LICENSE
index 8b8ff36fe..7de525bf0 100644
--- a/vendor/github.com/gofrs/flock/LICENSE
+++ b/vendor/github.com/gofrs/flock/LICENSE
@@ -1,3 +1,4 @@
+Copyright (c) 2018-2024, The Gofrs
Copyright (c) 2015-2020, Tim Heckman
All rights reserved.
diff --git a/vendor/github.com/gofrs/flock/Makefile b/vendor/github.com/gofrs/flock/Makefile
new file mode 100644
index 000000000..65c139d68
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/Makefile
@@ -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
diff --git a/vendor/github.com/gofrs/flock/README.md b/vendor/github.com/gofrs/flock/README.md
index 71ce63692..f7ca0dd9c 100644
--- a/vendor/github.com/gofrs/flock/README.md
+++ b/vendor/github.com/gofrs/flock/README.md
@@ -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)
-[![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.
+[![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/main/LICENSE)
+[![Go Report Card](https://goreportcard.com/badge/github.com/gofrs/flock)](https://goreportcard.com/report/github.com/gofrs/flock)
-## License
-`flock` is released under the BSD 3-Clause License. See the `LICENSE` file for more details.
+`flock` implements a thread-safe file lock.
-## 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).
diff --git a/vendor/github.com/gofrs/flock/SECURITY.md b/vendor/github.com/gofrs/flock/SECURITY.md
new file mode 100644
index 000000000..01419bd59
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/SECURITY.md
@@ -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/).
diff --git a/vendor/github.com/gofrs/flock/appveyor.yml b/vendor/github.com/gofrs/flock/appveyor.yml
deleted file mode 100644
index 909b4bf7c..000000000
--- a/vendor/github.com/gofrs/flock/appveyor.yml
+++ /dev/null
@@ -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 ./...
diff --git a/vendor/github.com/gofrs/flock/build.sh b/vendor/github.com/gofrs/flock/build.sh
new file mode 100644
index 000000000..60f7809f0
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/build.sh
@@ -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
diff --git a/vendor/github.com/gofrs/flock/flock.go b/vendor/github.com/gofrs/flock/flock.go
index 95c784ca5..ff942b228 100644
--- a/vendor/github.com/gofrs/flock/flock.go
+++ b/vendor/github.com/gofrs/flock/flock.go
@@ -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()
@@ -114,31 +163,44 @@ func tryCtx(ctx context.Context, fn func() (bool, error), retryDelay time.Durati
}
}
-func (f *Flock) setFh() error {
+func (f *Flock) setFh(flag int) 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, 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
+// resetFh resets file handle:
+// - tries to close the file (ignore errors)
+// - sets fh to nil.
+func (f *Flock) resetFh() {
+ if f.fh == nil {
+ return
+ }
+
+ _ = f.fh.Close()
+
+ f.fh = nil
+}
+
+// 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.resetFh()
+}
+
+func (f *Flock) reset() {
+ f.l = false
+ f.r = false
+
+ f.resetFh()
}
diff --git a/vendor/github.com/gofrs/flock/flock_aix.go b/vendor/github.com/gofrs/flock/flock_aix.go
deleted file mode 100644
index 7277c1b6b..000000000
--- a/vendor/github.com/gofrs/flock/flock_aix.go
+++ /dev/null
@@ -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
- }
- }
-}
diff --git a/vendor/github.com/gofrs/flock/flock_others.go b/vendor/github.com/gofrs/flock/flock_others.go
new file mode 100644
index 000000000..18b14f1bd
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/flock_others.go
@@ -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()
+}
diff --git a/vendor/github.com/gofrs/flock/flock_unix.go b/vendor/github.com/gofrs/flock/flock_unix.go
index c315a3e29..cf8919c7a 100644
--- a/vendor/github.com/gofrs/flock/flock_unix.go
+++ b/vendor/github.com/gofrs/flock/flock_unix.go
@@ -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 {
@@ -48,13 +50,15 @@ func (f *Flock) lock(locked *bool, flag int) error {
}
if f.fh == nil {
- if err := f.setFh(); err != nil {
+ if err := f.setFh(f.flag); 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) {
@@ -140,25 +147,28 @@ func (f *Flock) try(locked *bool, flag int) (bool, error) {
}
if f.fh == nil {
- if err := f.setFh(); err != nil {
+ if err := f.setFh(f.flag); 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,32 @@ 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().
+// > https://github.com/util-linux/util-linux/blob/198e920aa24743ef6ace4e07cf6237de527f9261/sys-utils/flock.c#L374-L390
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
+ }
+
+ if st.Mode()&f.perm != f.perm {
+ return false, nil
+ }
+
+ f.resetFh()
+
+ // reopen in read-write mode and set the file handle
+ err = f.setFh(f.flag | os.O_RDWR)
+ if err != nil {
+ return false, err
}
- return false, nil
+ return true, nil
}
diff --git a/vendor/github.com/gofrs/flock/flock_unix_fcntl.go b/vendor/github.com/gofrs/flock/flock_unix_fcntl.go
new file mode 100644
index 000000000..ea007b47d
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/flock_unix_fcntl.go
@@ -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(f.flag); 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(f.flag); 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
+ }
+ }
+}
diff --git a/vendor/github.com/gofrs/flock/flock_winapi.go b/vendor/github.com/gofrs/flock/flock_winapi.go
deleted file mode 100644
index fe405a255..000000000
--- a/vendor/github.com/gofrs/flock/flock_winapi.go
+++ /dev/null
@@ -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
-}
diff --git a/vendor/github.com/gofrs/flock/flock_windows.go b/vendor/github.com/gofrs/flock/flock_windows.go
index ddb534cce..dfd31e15f 100644
--- a/vendor/github.com/gofrs/flock/flock_windows.go
+++ b/vendor/github.com/gofrs/flock/flock_windows.go
@@ -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
+// 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
+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.
+// 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.
+// 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)
}
@@ -43,26 +56,31 @@ func (f *Flock) lock(locked *bool, flag uint32) error {
}
if f.fh == nil {
- if err := f.setFh(); err != nil {
+ if err := f.setFh(f.flag); 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)
}
@@ -120,20 +136,20 @@ func (f *Flock) try(locked *bool, flag uint32) (bool, error) {
}
if f.fh == nil {
- if err := f.setFh(); err != nil {
+ if err := f.setFh(f.flag); 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