pax_global_header00006660000000000000000000000064142167164450014524gustar00rootroot0000000000000052 comment=8d142ea19e06ac7b7b064ca2db72f335a339d4df go-filemutex-1.2.0/000077500000000000000000000000001421671644500141315ustar00rootroot00000000000000go-filemutex-1.2.0/.github/000077500000000000000000000000001421671644500154715ustar00rootroot00000000000000go-filemutex-1.2.0/.github/workflows/000077500000000000000000000000001421671644500175265ustar00rootroot00000000000000go-filemutex-1.2.0/.github/workflows/go.yml000066400000000000000000000031051421671644500206550ustar00rootroot00000000000000name: Go on: push: branches: [ master ] pull_request: branches: [ master ] jobs: # Unfortunately there is much duplication below. I have not found a # way to set "runs-on" to an array, so instead I duplicated the # whole thing three times. linux_build_and_test: name: Build and test (Linux) runs-on: windows-latest strategy: fail-fast: false matrix: go: ['1.13', '1.14', '1.15', '1.16'] steps: - id: go name: Set up Go uses: actions/setup-go@v1 with: go-version: ${{ matrix.go }} - name: Checkout uses: actions/checkout@v2 - name: Build run: go build -v . - name: Test run: go test -v . windows_build_and_test: name: Build and test (Windows) runs-on: windows-latest strategy: fail-fast: false matrix: go: ['1.13', '1.14', '1.15', '1.16'] steps: - id: go name: Set up Go uses: actions/setup-go@v1 with: go-version: ${{ matrix.go }} - name: Checkout uses: actions/checkout@v2 - name: Build run: go build -v . - name: Test run: go test -v . macos_build_and_test: name: Build and test (macOS) runs-on: macos-latest strategy: fail-fast: false matrix: go: ['1.13', '1.14', '1.15', '1.16'] steps: - id: go name: Set up Go uses: actions/setup-go@v1 with: go-version: ${{ matrix.go }} - name: Checkout uses: actions/checkout@v2 - name: Build run: go build -v . - name: Test run: go test -v . go-filemutex-1.2.0/LICENSE000066400000000000000000000021121421671644500151320ustar00rootroot00000000000000The MIT License Copyright (c) 2010-2017 Alex Flint. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. go-filemutex-1.2.0/README.md000066400000000000000000000012671421671644500154160ustar00rootroot00000000000000# FileMutex FileMutex is similar to `sync.RWMutex`, but also synchronizes across processes. On Linux, OSX, and other POSIX systems it uses the flock system call. On windows it uses the LockFileEx and UnlockFileEx system calls. ```go import ( "log" "github.com/alexflint/go-filemutex" ) func main() { m, err := filemutex.New("/tmp/foo.lock") if err != nil { log.Fatalln("Directory did not exist or file could not created") } m.Lock() // Will block until lock can be acquired // Code here is protected by the mutex m.Unlock() } ``` ### Installation go get github.com/alexflint/go-filemutex Forked from https://github.com/golang/build/tree/master/cmd/builder/filemutex_*.go go-filemutex-1.2.0/filemutex.go000066400000000000000000000001341421671644500164600ustar00rootroot00000000000000package filemutex import "errors" var AlreadyLocked = errors.New("lock already acquired") go-filemutex-1.2.0/filemutex_flock.go000066400000000000000000000026241421671644500176440ustar00rootroot00000000000000// Copyright 2013 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. // +build darwin dragonfly freebsd linux netbsd openbsd solaris package filemutex import "golang.org/x/sys/unix" const ( mkdirPerm = 0750 ) // FileMutex is similar to sync.RWMutex, but also synchronizes across processes. // This implementation is based on flock syscall. type FileMutex struct { fd int } func New(filename string) (*FileMutex, error) { fd, err := unix.Open(filename, unix.O_CREAT|unix.O_RDONLY, mkdirPerm) if err != nil { return nil, err } return &FileMutex{fd: fd}, nil } func (m *FileMutex) Lock() error { return unix.Flock(m.fd, unix.LOCK_EX) } func (m *FileMutex) TryLock() error { if err := unix.Flock(m.fd, unix.LOCK_EX|unix.LOCK_NB); err != nil { if errno, ok := err.(unix.Errno); ok { if errno == unix.EWOULDBLOCK { return AlreadyLocked } } return err } return nil } func (m *FileMutex) Unlock() error { return unix.Flock(m.fd, unix.LOCK_UN) } func (m *FileMutex) RLock() error { return unix.Flock(m.fd, unix.LOCK_SH) } func (m *FileMutex) RUnlock() error { return unix.Flock(m.fd, unix.LOCK_UN) } // Close unlocks the lock and closes the underlying file descriptor. func (m *FileMutex) Close() error { if err := unix.Flock(m.fd, unix.LOCK_UN); err != nil { return err } return unix.Close(m.fd) } go-filemutex-1.2.0/filemutex_test.go000066400000000000000000000075461421671644500175350ustar00rootroot00000000000000package filemutex import ( "io/ioutil" "os" "path/filepath" "testing" "github.com/stretchr/testify/require" ) func TestLockUnlock(t *testing.T) { dir, err := ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(dir) path := filepath.Join(dir, "x") m, err := New(path) require.NoError(t, err) err = m.Lock() require.NoError(t, err) err = m.Unlock() require.NoError(t, err) } func TestTryLockUnlock(t *testing.T) { dir, err := ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(dir) path := filepath.Join(dir, "x") m, err := New(path) require.NoError(t, err) m2, err := New(path) require.NoError(t, err) err = m.Lock() require.NoError(t, err) err = m2.TryLock() require.Equal(t, AlreadyLocked, err) err = m.Unlock() require.NoError(t, err) err = m2.TryLock() require.NoError(t, err) } func TestRLockUnlock(t *testing.T) { dir, err := ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(dir) path := filepath.Join(dir, "x") m, err := New(path) require.NoError(t, err) err = m.RLock() require.NoError(t, err) err = m.RUnlock() require.NoError(t, err) } func TestClose(t *testing.T) { dir, err := ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(dir) path := filepath.Join(dir, "x") m, err := New(path) require.NoError(t, err) m.Lock() m.Close() } func TestOnlyClose(t *testing.T) { dir, err := ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(dir) path := filepath.Join(dir, "x") m, err := New(path) require.NoError(t, err) require.NoError(t, m.Close()) } func TestLockErrorsAreRecoverable(t *testing.T) { dir, err := ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(dir) path := filepath.Join(dir, "x") m, err := New(path) require.NoError(t, err) // muck with the internal state in order to cause an error oldfd := m.fd m.fd = 99999 // trigger an error err = m.Lock() require.Error(t, err) // restore a sane internal state m.fd = oldfd // this would hang if we hadn't Unlock()ed in the Lock error branch err = m.Lock() require.NoError(t, err) // clean up err = m.Unlock() require.NoError(t, err) } func TestUnlockErrorsAreRecoverable(t *testing.T) { dir, err := ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(dir) path := filepath.Join(dir, "x") m, err := New(path) require.NoError(t, err) err = m.Lock() require.NoError(t, err) // muck with the internal state in order to cause an error oldfd := m.fd m.fd = 99999 // trigger an error err = m.Unlock() require.Error(t, err) // restore a sane internal state m.fd = oldfd // this would crash if we the mutex were unlocked in the error branch err = m.Unlock() require.NoError(t, err) } func TestRLockErrorsAreRecoverable(t *testing.T) { dir, err := ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(dir) path := filepath.Join(dir, "x") m, err := New(path) require.NoError(t, err) // muck with the internal state in order to cause an error oldfd := m.fd m.fd = 99999 // trigger an error err = m.RLock() require.Error(t, err) // restore a sane internal state m.fd = oldfd // this would hang if we hadn't Unlock()ed in the RLock error branch err = m.Lock() require.NoError(t, err) // clean up err = m.Unlock() require.NoError(t, err) } func TestRUnlockErrorsAreRecoverable(t *testing.T) { dir, err := ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(dir) path := filepath.Join(dir, "x") m, err := New(path) require.NoError(t, err) err = m.RLock() require.NoError(t, err) // muck with the internal state in order to cause an error oldfd := m.fd m.fd = 99999 // trigger an error err = m.RUnlock() require.Error(t, err) // restore a sane internal state m.fd = oldfd // this would crash if we the mutex were unlocked in the error branch err = m.RUnlock() require.NoError(t, err) } go-filemutex-1.2.0/filemutex_windows.go000066400000000000000000000036311421671644500202370ustar00rootroot00000000000000// Copyright 2013 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. package filemutex import ( "syscall" "golang.org/x/sys/windows" ) // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx var errLockUnlocked syscall.Errno = 0x9E // FileMutex is similar to sync.RWMutex, but also synchronizes across processes. // This implementation is based on flock syscall. type FileMutex struct { fd windows.Handle } func New(filename string) (*FileMutex, error) { fd, err := windows.CreateFile(&(windows.StringToUTF16(filename)[0]), windows.GENERIC_READ|windows.GENERIC_WRITE, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, nil, windows.OPEN_ALWAYS, windows.FILE_ATTRIBUTE_NORMAL, 0) if err != nil { return nil, err } return &FileMutex{fd: fd}, nil } func (m *FileMutex) TryLock() error { if err := windows.LockFileEx(m.fd, windows.LOCKFILE_FAIL_IMMEDIATELY|windows.LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &windows.Overlapped{}); err != nil { if errno, ok := err.(windows.Errno); ok { if errno == windows.ERROR_LOCK_VIOLATION { return AlreadyLocked } } return err } return nil } func (m *FileMutex) Lock() error { return windows.LockFileEx(m.fd, windows.LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &windows.Overlapped{}) } func (m *FileMutex) Unlock() error { return windows.UnlockFileEx(m.fd, 0, 1, 0, &windows.Overlapped{}) } func (m *FileMutex) RLock() error { return windows.LockFileEx(m.fd, 0, 0, 1, 0, &windows.Overlapped{}) } func (m *FileMutex) RUnlock() error { return windows.UnlockFileEx(m.fd, 0, 1, 0, &windows.Overlapped{}) } // Close unlocks the lock and closes the underlying file descriptor. func (m *FileMutex) Close() error { if err := windows.UnlockFileEx(m.fd, 0, 1, 0, &windows.Overlapped{}); err != nil && err != errLockUnlocked { return err } return windows.Close(m.fd) } go-filemutex-1.2.0/go.mod000066400000000000000000000002301421671644500152320ustar00rootroot00000000000000module github.com/alexflint/go-filemutex go 1.13 require ( github.com/stretchr/testify v1.4.0 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 ) go-filemutex-1.2.0/go.sum000066400000000000000000000022271421671644500152670ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=