From 94c43a86855080d65551241150737e8c74ef9eaf Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Thu, 9 Mar 2023 01:59:46 +0000 Subject: [PATCH] Use access syscall. --- vfs.go | 45 +++-------------------------- vfs_unix.go | 78 +++++++++++++++++++++++++++++++------------------- vfs_windows.go | 40 +++++++++++++++++++++++++- 3 files changed, 91 insertions(+), 72 deletions(-) diff --git a/vfs.go b/vfs.go index db59852..2f9b595 100644 --- a/vfs.go +++ b/vfs.go @@ -9,7 +9,6 @@ import ( "os" "path/filepath" "runtime" - "syscall" "time" "github.com/ncruces/julianday" @@ -185,47 +184,14 @@ func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath, syncDir uint32) } func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath uint32, flags _AccessFlag, pResOut uint32) uint32 { - // Consider using [syscall.Access] for [ACCESS_READWRITE]/[ACCESS_READ] - // (as the Unix VFS does). - path := memory{mod}.readString(zPath, _MAX_PATHNAME) - fi, err := os.Stat(path) - + ok, rc := vfsOS.Access(path, flags) var res uint32 - switch { - case flags == _ACCESS_EXISTS: - switch { - case err == nil: - res = 1 - case errors.Is(err, fs.ErrNotExist): - res = 0 - default: - return uint32(IOERR_ACCESS) - } - - case err == nil: - var want fs.FileMode = syscall.S_IRUSR - if flags == _ACCESS_READWRITE { - want |= syscall.S_IWUSR - } - if fi.IsDir() { - want |= syscall.S_IXUSR - } - if fi.Mode()&want == want { - res = 1 - } else { - res = 0 - } - - case errors.Is(err, fs.ErrPermission): - res = 0 - - default: - return uint32(IOERR_ACCESS) + if ok { + res = 1 } - memory{mod}.writeUint32(pResOut, res) - return _OK + return uint32(rc) } func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, flags OpenFlag, pOutFlags uint32) uint32 { @@ -322,9 +288,6 @@ func vfsSync(ctx context.Context, mod api.Module, pFile, flags uint32) uint32 { } func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize uint32) uint32 { - // This uses [os.File.Seek] because we don't care about the offset for reading/writing. - // But consider using [os.File.Stat] instead (as other VFSes do). - file := vfsFile.GetOS(ctx, mod, pFile) off, err := file.Seek(0, io.SeekEnd) if err != nil { diff --git a/vfs_unix.go b/vfs_unix.go index 1469c0a..1d8b11d 100644 --- a/vfs_unix.go +++ b/vfs_unix.go @@ -3,15 +3,33 @@ package sqlite3 import ( + "io/fs" "os" "runtime" - "syscall" + + "golang.org/x/sys/unix" ) -func (vfsOSMethods) OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) { +func (vfsOSMethods) OpenFile(name string, flag int, perm fs.FileMode) (*os.File, error) { return os.OpenFile(name, flag, perm) } +func (vfsOSMethods) Access(path string, flags _AccessFlag) (bool, xErrorCode) { + var access uint32 = unix.F_OK + switch flags { + case _ACCESS_READWRITE: + access = unix.R_OK | unix.W_OK + case _ACCESS_READ: + access = unix.R_OK + } + + err := unix.Access(path, access) + if err == nil { + return true, _OK + } + return false, _OK +} + func (vfsOSMethods) GetExclusiveLock(file *os.File) xErrorCode { // Acquire the EXCLUSIVE lock. return vfsOS.writeLock(file, _SHARED_FIRST, _SHARED_SIZE) @@ -39,8 +57,8 @@ func (vfsOSMethods) ReleaseLock(file *os.File, _ vfsLockState) xErrorCode { } func (vfsOSMethods) unlock(file *os.File, start, len int64) xErrorCode { - err := vfsOS.fcntlSetLock(file, &syscall.Flock_t{ - Type: syscall.F_UNLCK, + err := vfsOS.fcntlSetLock(file, &unix.Flock_t{ + Type: unix.F_UNLCK, Start: start, Len: len, }) @@ -51,85 +69,85 @@ func (vfsOSMethods) unlock(file *os.File, start, len int64) xErrorCode { } func (vfsOSMethods) readLock(file *os.File, start, len int64) xErrorCode { - return vfsOS.lockErrorCode(vfsOS.fcntlSetLock(file, &syscall.Flock_t{ - Type: syscall.F_RDLCK, + return vfsOS.lockErrorCode(vfsOS.fcntlSetLock(file, &unix.Flock_t{ + Type: unix.F_RDLCK, Start: start, Len: len, }), IOERR_RDLOCK) } func (vfsOSMethods) writeLock(file *os.File, start, len int64) xErrorCode { - return vfsOS.lockErrorCode(vfsOS.fcntlSetLock(file, &syscall.Flock_t{ - Type: syscall.F_WRLCK, + return vfsOS.lockErrorCode(vfsOS.fcntlSetLock(file, &unix.Flock_t{ + Type: unix.F_WRLCK, Start: start, Len: len, }), IOERR_LOCK) } func (vfsOSMethods) checkLock(file *os.File, start, len int64) (bool, xErrorCode) { - lock := syscall.Flock_t{ - Type: syscall.F_RDLCK, + lock := unix.Flock_t{ + Type: unix.F_RDLCK, Start: start, Len: len, } if vfsOS.fcntlGetLock(file, &lock) != nil { return false, IOERR_CHECKRESERVEDLOCK } - return lock.Type != syscall.F_UNLCK, _OK + return lock.Type != unix.F_UNLCK, _OK } -func (vfsOSMethods) fcntlGetLock(file *os.File, lock *syscall.Flock_t) error { +func (vfsOSMethods) fcntlGetLock(file *os.File, lock *unix.Flock_t) error { var F_OFD_GETLK int switch runtime.GOOS { case "linux": // https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/fcntl.h - F_OFD_GETLK = 36 // F_OFD_GETLK + F_OFD_GETLK = 36 case "darwin": // https://github.com/apple/darwin-xnu/blob/main/bsd/sys/fcntl.h - F_OFD_GETLK = 92 // F_OFD_GETLK + F_OFD_GETLK = 92 case "illumos": // https://github.com/illumos/illumos-gate/blob/master/usr/src/uts/common/sys/fcntl.h - F_OFD_GETLK = 47 // F_OFD_GETLK + F_OFD_GETLK = 47 default: return notImplErr } - return syscall.FcntlFlock(file.Fd(), F_OFD_GETLK, lock) + return unix.FcntlFlock(file.Fd(), F_OFD_GETLK, lock) } -func (vfsOSMethods) fcntlSetLock(file *os.File, lock *syscall.Flock_t) error { +func (vfsOSMethods) fcntlSetLock(file *os.File, lock *unix.Flock_t) error { var F_OFD_SETLK int switch runtime.GOOS { case "linux": // https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/fcntl.h - F_OFD_SETLK = 37 // F_OFD_SETLK + F_OFD_SETLK = 37 case "darwin": // https://github.com/apple/darwin-xnu/blob/main/bsd/sys/fcntl.h - F_OFD_SETLK = 90 // F_OFD_SETLK + F_OFD_SETLK = 90 case "illumos": // https://github.com/illumos/illumos-gate/blob/master/usr/src/uts/common/sys/fcntl.h - F_OFD_SETLK = 48 // F_OFD_SETLK + F_OFD_SETLK = 48 default: return notImplErr } - return syscall.FcntlFlock(file.Fd(), F_OFD_SETLK, lock) + return unix.FcntlFlock(file.Fd(), F_OFD_SETLK, lock) } func (vfsOSMethods) lockErrorCode(err error, def xErrorCode) xErrorCode { if err == nil { return _OK } - if errno, ok := err.(syscall.Errno); ok { + if errno, ok := err.(unix.Errno); ok { switch errno { case - syscall.EACCES, - syscall.EAGAIN, - syscall.EBUSY, - syscall.EINTR, - syscall.ENOLCK, - syscall.EDEADLK, - syscall.ETIMEDOUT: + unix.EACCES, + unix.EAGAIN, + unix.EBUSY, + unix.EINTR, + unix.ENOLCK, + unix.EDEADLK, + unix.ETIMEDOUT: return xErrorCode(BUSY) - case syscall.EPERM: + case unix.EPERM: return xErrorCode(PERM) } } diff --git a/vfs_windows.go b/vfs_windows.go index 73be2a9..55b9cfe 100644 --- a/vfs_windows.go +++ b/vfs_windows.go @@ -1,16 +1,54 @@ package sqlite3 import ( + "errors" + "io/fs" "os" "syscall" "golang.org/x/sys/windows" ) -func (vfsOSMethods) OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) { +func (vfsOSMethods) OpenFile(name string, flag int, perm fs.FileMode) (*os.File, error) { return osOpenFile(name, flag, perm) } +func (vfsOSMethods) Access(path string, flags _AccessFlag) (bool, xErrorCode) { + fi, err := os.Stat(path) + + switch { + case flags == _ACCESS_EXISTS: + switch { + case err == nil: + return true, _OK + case errors.Is(err, fs.ErrNotExist): + return false, _OK + default: + return false, IOERR_ACCESS + } + + case err == nil: + var want fs.FileMode = syscall.S_IRUSR + if flags == _ACCESS_READWRITE { + want |= syscall.S_IWUSR + } + if fi.IsDir() { + want |= syscall.S_IXUSR + } + if fi.Mode()&want == want { + return true, _OK + } else { + return false, _OK + } + + case errors.Is(err, fs.ErrPermission): + return false, _OK + + default: + return false, IOERR_ACCESS + } +} + func (vfsOSMethods) GetExclusiveLock(file *os.File) xErrorCode { // Release the SHARED lock. vfsOS.unlock(file, _SHARED_FIRST, _SHARED_SIZE)