From 5e1909a20eaafad587d58acdfe66aa5672bc83b9 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Mon, 24 Feb 2025 12:25:19 +0000 Subject: [PATCH] Issue #230. --- vfs/const.go | 3 +++ vfs/file.go | 21 +++++++++++++++++---- vfs/os_std_rw.go | 13 +++++++++++++ vfs/os_unix.go | 22 ++++++++++++++++++++++ vfs/os_windows.go | 17 +++++++++++++++++ 5 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 vfs/os_std_rw.go diff --git a/vfs/const.go b/vfs/const.go index dc3b0db..b789d12 100644 --- a/vfs/const.go +++ b/vfs/const.go @@ -31,6 +31,7 @@ const ( _READONLY _ErrorCode = util.READONLY _IOERR _ErrorCode = util.IOERR _NOTFOUND _ErrorCode = util.NOTFOUND + _FULL _ErrorCode = util.FULL _CANTOPEN _ErrorCode = util.CANTOPEN _IOERR_READ _ErrorCode = util.IOERR_READ _IOERR_SHORT_READ _ErrorCode = util.IOERR_SHORT_READ @@ -57,10 +58,12 @@ const ( _IOERR_COMMIT_ATOMIC _ErrorCode = util.IOERR_COMMIT_ATOMIC _IOERR_ROLLBACK_ATOMIC _ErrorCode = util.IOERR_ROLLBACK_ATOMIC _IOERR_DATA _ErrorCode = util.IOERR_DATA + _IOERR_CORRUPTFS _ErrorCode = util.IOERR_CORRUPTFS _BUSY_SNAPSHOT _ErrorCode = util.BUSY_SNAPSHOT _CANTOPEN_FULLPATH _ErrorCode = util.CANTOPEN_FULLPATH _CANTOPEN_ISDIR _ErrorCode = util.CANTOPEN_ISDIR _READONLY_CANTINIT _ErrorCode = util.READONLY_CANTINIT + _READONLY_DIRECTORY _ErrorCode = util.READONLY_DIRECTORY _OK_SYMLINK _ErrorCode = util.OK_SYMLINK ) diff --git a/vfs/file.go b/vfs/file.go index bc90555..83f9af3 100644 --- a/vfs/file.go +++ b/vfs/file.go @@ -88,6 +88,9 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error oflags |= os.O_RDWR } + isCreate := flags&(OPEN_CREATE) != 0 + isJournl := flags&(OPEN_MAIN_JOURNAL|OPEN_SUPER_JOURNAL|OPEN_WAL) != 0 + var err error var f *os.File if name == nil { @@ -102,6 +105,10 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error if errors.Is(err, syscall.EISDIR) { return nil, flags, _CANTOPEN_ISDIR } + if isCreate && isJournl && errors.Is(err, fs.ErrPermission) && + osAccess(name.String(), ACCESS_EXISTS) != nil { + return nil, flags, _READONLY_DIRECTORY + } return nil, flags, err } @@ -119,10 +126,8 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error File: f, psow: true, readOnly: flags&OPEN_READONLY != 0, - syncDir: canSyncDirs && - flags&(OPEN_MAIN_JOURNAL|OPEN_SUPER_JOURNAL|OPEN_WAL) != 0 && - flags&(OPEN_CREATE) != 0, - shm: NewSharedMemory(name.String()+"-shm", flags), + syncDir: canSyncDirs && isCreate && isJournl, + shm: NewSharedMemory(name.String()+"-shm", flags), } return &file, flags, nil } @@ -154,6 +159,14 @@ func (f *vfsFile) Close() error { return f.File.Close() } +func (f *vfsFile) ReadAt(p []byte, off int64) (n int, err error) { + return osReadAt(f.File, p, off) +} + +func (f *vfsFile) WriteAt(p []byte, off int64) (n int, err error) { + return osWriteAt(f.File, p, off) +} + func (f *vfsFile) Sync(flags SyncFlag) error { dataonly := (flags & SYNC_DATAONLY) != 0 fullsync := (flags & 0x0f) == SYNC_FULL diff --git a/vfs/os_std_rw.go b/vfs/os_std_rw.go new file mode 100644 index 0000000..40a5f27 --- /dev/null +++ b/vfs/os_std_rw.go @@ -0,0 +1,13 @@ +//go:build !unix && (!windows || sqlite3_dotlk) + +package vfs + +import "os" + +func osReadAt(file *os.File, p []byte, off int64) (int, error) { + return file.ReadAt(p, off) +} + +func osWriteAt(file *os.File, p []byte, off int64) (int, error) { + return file.WriteAt(p, off) +} diff --git a/vfs/os_unix.go b/vfs/os_unix.go index c4f9ba8..9f42b5f 100644 --- a/vfs/os_unix.go +++ b/vfs/os_unix.go @@ -25,6 +25,28 @@ func osAccess(path string, flags AccessFlag) error { return unix.Access(path, access) } +func osReadAt(file *os.File, p []byte, off int64) (int, error) { + n, err := file.ReadAt(p, off) + if errno, ok := err.(unix.Errno); ok { + switch errno { + case + unix.ERANGE, + unix.EIO, + unix.ENXIO: + return n, _IOERR_CORRUPTFS + } + } + return n, err +} + +func osWriteAt(file *os.File, p []byte, off int64) (int, error) { + n, err := file.WriteAt(p, off) + if errno, ok := err.(unix.Errno); ok && errno == unix.ENOSPC { + return n, _FULL + } + return n, err +} + func osSetMode(file *os.File, modeof string) error { fi, err := os.Stat(modeof) if err != nil { diff --git a/vfs/os_windows.go b/vfs/os_windows.go index 0398f47..ecce3cf 100644 --- a/vfs/os_windows.go +++ b/vfs/os_windows.go @@ -9,6 +9,23 @@ import ( "golang.org/x/sys/windows" ) +func osReadAt(file *os.File, p []byte, off int64) (int, error) { + return file.ReadAt(p, off) +} + +func osWriteAt(file *os.File, p []byte, off int64) (int, error) { + n, err := file.WriteAt(p, off) + if errno, ok := err.(windows.Errno); ok { + switch errno { + case + windows.ERROR_HANDLE_DISK_FULL, + windows.ERROR_DISK_FULL: + return n, _FULL + } + } + return n, err +} + func osGetSharedLock(file *os.File) _ErrorCode { // Acquire the PENDING lock temporarily before acquiring a new SHARED lock. rc := osReadLock(file, _PENDING_BYTE, 1, 0)