Browse Source

Add support for file locking

tags/v4.0.0
Taru Karttunen 2 years ago
parent
commit
c926618166
5 changed files with 72 additions and 2 deletions
  1. 5
    0
      fs.go
  2. 9
    0
      memfs/memory.go
  3. 14
    2
      osfs/os.go
  4. 9
    0
      osfs/os_posix.go
  5. 35
    0
      osfs/os_windows.go

+ 5
- 0
fs.go View File

@@ -135,4 +135,9 @@ type File interface {
io.ReaderAt
io.Seeker
io.Closer
// Lock locks the file like e.g. flock. It protects against access from
// other processes.
Lock() error
// Unlock unlocks the file.
Unlock() error
}

+ 9
- 0
memfs/memory.go View File

@@ -297,6 +297,15 @@ func (f *file) Stat() (os.FileInfo, error) {
}, nil
}

// Lock protects file from access from other processes. Which is a no-op
// for this memory only filesystem.
func (f *file) Lock() error {
return nil
}
func (f *file) Unlock() error {
return nil
}

type fileInfo struct {
name string
size int

+ 14
- 2
osfs/os.go View File

@@ -23,6 +23,10 @@ func New(baseDir string) billy.Filesystem {
return chroot.New(&OS{}, baseDir)
}

type file struct {
*os.File
}

func (fs *OS) Create(filename string) (billy.File, error) {
return fs.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, defaultCreateMode)
}
@@ -34,7 +38,11 @@ func (fs *OS) OpenFile(filename string, flag int, perm os.FileMode) (billy.File,
}
}

return os.OpenFile(filename, flag, perm)
f, err := os.OpenFile(filename, flag, perm)
if err != nil {
return nil, err
}
return file{f}, err
}

func (fs *OS) createDir(fullpath string) error {
@@ -87,7 +95,11 @@ func (fs *OS) TempFile(dir, prefix string) (billy.File, error) {
return nil, err
}

return ioutil.TempFile(dir, prefix)
f, err := ioutil.TempFile(dir, prefix)
if err != nil {
return nil, err
}
return file{f}, nil
}

func (fs *OS) Join(elem ...string) string {

+ 9
- 0
osfs/os_posix.go View File

@@ -4,9 +4,18 @@ package osfs

import (
"os"
"syscall"
)

// Stat returns the FileInfo structure describing file.
func (fs *OS) Stat(filename string) (os.FileInfo, error) {
return os.Stat(filename)
}

// Lock protects file from access from other processes.
func (f file) Lock() error {
return syscall.Flock(int(f.File.Fd()), syscall.LOCK_EX)
}
func (f file) Unlock() error {
return syscall.Flock(int(f.File.Fd()), syscall.LOCK_UN)
}

+ 35
- 0
osfs/os_windows.go View File

@@ -5,7 +5,11 @@ package osfs
import (
"os"
"path/filepath"
"runtime"
"strings"
"unsafe"

"golang.org/x/sys/windows"
)

// Stat returns the FileInfo structure describing file.
@@ -39,3 +43,34 @@ type fileInfo struct {
func (fi *fileInfo) Name() string {
return fi.name
}

var (
kernel32DLL = windows.NewLazySystemDLL("kernel32.dll")
lockFileExProc = kernel32DLL.NewProc("LockFileEx")
unlockFileProc = kernel32DLL.NewProc("UnlockFile")
)

const (
lockfileExclusiveLock = 0x2
)

// Lock protects file from access from other processes.
func (f file) Lock() error {
var overlapped windows.Overlapped
// err is always non-nil as per sys/windows semantics.
ret, _, err := lockFileExProc.Call(f.File.Fd(), lockfileExclusiveLock, 0, 0xFFFFFFFF, 0,
uintptr(unsafe.Pointer(&overlapped)))
runtime.KeepAlive(&overlapped)
if ret == 0 {
return err
}
return nil
}
func (f file) Unlock() error {
// err is always non-nil as per sys/windows semantics.
ret, _, err := unlockFileProc.Call(f.File.Fd(), 0, 0, 0xFFFFFFFF, 0)
if ret == 0 {
return err
}
return nil
}

Loading…
Cancel
Save