More VFS API.

This commit is contained in:
Nuno Cruces
2023-05-18 01:34:54 +01:00
parent 6846b72b31
commit 67cc3d35d5
7 changed files with 96 additions and 56 deletions

View File

@@ -118,7 +118,7 @@ func vfsCurrentTime64(ctx context.Context, mod api.Module, pVfs, piNow uint32) _
}
func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative, nFull, zFull uint32) _ErrorCode {
vfs := getVFS(mod, pVfs)
vfs := vfsAPIGet(mod, pVfs)
rel := util.ReadString(mod, zRelative, _MAX_PATHNAME)
var abs string
@@ -126,7 +126,7 @@ func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative, nFull
if vfs != nil {
p, err := vfs.FullPathname(rel)
if err != nil {
return _CANTOPEN_FULLPATH
return vfsAPIErrorCode(err, _CANTOPEN_FULLPATH)
}
abs = p
} else {
@@ -158,7 +158,14 @@ func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative, nFull
}
func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath, syncDir uint32) _ErrorCode {
vfs := vfsAPIGet(mod, pVfs)
path := util.ReadString(mod, zPath, _MAX_PATHNAME)
if vfs != nil {
err := vfs.Delete(path, syncDir != 0)
return vfsAPIErrorCode(err, _IOERR_DELETE)
}
err := os.Remove(path)
if errors.Is(err, fs.ErrNotExist) {
return _IOERR_DELETE_NOENT
@@ -181,28 +188,39 @@ 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) _ErrorCode {
vfs := vfsAPIGet(mod, pVfs)
path := util.ReadString(mod, zPath, _MAX_PATHNAME)
err := osAccess(path, flags)
var res uint32
var rc _ErrorCode
if flags == _ACCESS_EXISTS {
switch {
case err == nil:
if vfs != nil {
ok, err := vfs.Access(path, flags)
if ok {
res = 1
case errors.Is(err, fs.ErrNotExist):
} else {
res = 0
default:
rc = _IOERR_ACCESS
}
rc = vfsAPIErrorCode(err, _IOERR_ACCESS)
} else {
switch {
case err == nil:
res = 1
case errors.Is(err, fs.ErrPermission):
res = 0
default:
rc = _IOERR_ACCESS
err := osAccess(path, flags)
if flags == _ACCESS_EXISTS {
switch {
case err == nil:
res = 1
case errors.Is(err, fs.ErrNotExist):
res = 0
default:
rc = _IOERR_ACCESS
}
} else {
switch {
case err == nil:
res = 1
case errors.Is(err, fs.ErrPermission):
res = 0
default:
rc = _IOERR_ACCESS
}
}
}
@@ -211,7 +229,7 @@ func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath uint32, flags _A
}
func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, flags _OpenFlag, pOutFlags uint32) _ErrorCode {
vfs := getVFS(mod, pVfs)
vfs := vfsAPIGet(mod, pVfs)
var oflags int
if flags&_OPEN_EXCLUSIVE != 0 {
@@ -249,7 +267,7 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, fla
os.Remove(f.Name())
}
file := openVFSFile(ctx, mod, pFile, f)
file := vfsFileOpen(ctx, mod, pFile, f)
file.psow = true
file.readOnly = flags&_OPEN_READONLY != 0
file.syncDir = runtime.GOOS != "windows" &&
@@ -263,7 +281,7 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, fla
}
func vfsClose(ctx context.Context, mod api.Module, pFile uint32) _ErrorCode {
err := closeVFSFile(ctx, mod, pFile)
err := vfsFileClose(ctx, mod, pFile)
if err != nil {
return _IOERR_CLOSE
}
@@ -273,7 +291,7 @@ func vfsClose(ctx context.Context, mod api.Module, pFile uint32) _ErrorCode {
func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst int64) _ErrorCode {
buf := util.View(mod, zBuf, uint64(iAmt))
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
n, err := file.ReadAt(buf, iOfst)
if n == int(iAmt) {
return _OK
@@ -290,7 +308,7 @@ func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfs
func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst int64) _ErrorCode {
buf := util.View(mod, zBuf, uint64(iAmt))
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
_, err := file.WriteAt(buf, iOfst)
if err != nil {
return _IOERR_WRITE
@@ -299,7 +317,7 @@ func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOf
}
func vfsTruncate(ctx context.Context, mod api.Module, pFile uint32, nByte int64) _ErrorCode {
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
err := file.Truncate(nByte)
if err != nil {
return _IOERR_TRUNCATE
@@ -311,7 +329,7 @@ func vfsSync(ctx context.Context, mod api.Module, pFile uint32, flags _SyncFlag)
dataonly := (flags & _SYNC_DATAONLY) != 0
fullsync := (flags & 0x0f) == _SYNC_FULL
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
err := osSync(file.File, fullsync, dataonly)
if err != nil {
return _IOERR_FSYNC
@@ -332,7 +350,7 @@ func vfsSync(ctx context.Context, mod api.Module, pFile uint32, flags _SyncFlag)
}
func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize uint32) _ErrorCode {
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
off, err := file.Seek(0, io.SeekEnd)
if err != nil {
return _IOERR_SEEK
@@ -345,16 +363,16 @@ func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize uint32) _Erro
func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _FcntlOpcode, pArg uint32) _ErrorCode {
switch op {
case _FCNTL_LOCKSTATE:
util.WriteUint32(mod, pArg, uint32(getVFSFile(ctx, mod, pFile).lock))
util.WriteUint32(mod, pArg, uint32(vfsFileGet(ctx, mod, pFile).lock))
return _OK
case _FCNTL_LOCK_TIMEOUT:
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
millis := file.lockTimeout.Milliseconds()
file.lockTimeout = time.Duration(util.ReadUint32(mod, pArg)) * time.Millisecond
util.WriteUint32(mod, pArg, uint32(millis))
return _OK
case _FCNTL_POWERSAFE_OVERWRITE:
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
switch util.ReadUint32(mod, pArg) {
case 0:
file.psow = false
@@ -386,7 +404,7 @@ func vfsSectorSize(ctx context.Context, mod api.Module, pFile uint32) uint32 {
}
func vfsDeviceCharacteristics(ctx context.Context, mod api.Module, pFile uint32) _DeviceCharacteristic {
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
if file.psow {
return _IOCAP_POWERSAFE_OVERWRITE
}
@@ -394,7 +412,7 @@ func vfsDeviceCharacteristics(ctx context.Context, mod api.Module, pFile uint32)
}
func vfsSizeHint(ctx context.Context, mod api.Module, pFile, pArg uint32) _ErrorCode {
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
size := util.ReadUint64(mod, pArg)
err := osAllocate(file.File, int64(size))
if err != nil {
@@ -404,7 +422,7 @@ func vfsSizeHint(ctx context.Context, mod api.Module, pFile, pArg uint32) _Error
}
func vfsFileMoved(ctx context.Context, mod api.Module, pFile, pResOut uint32) _ErrorCode {
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
fi, err := file.Stat()
if err != nil {
return _IOERR_FSTAT
@@ -420,11 +438,3 @@ func vfsFileMoved(ctx context.Context, mod api.Module, pFile, pResOut uint32) _E
util.WriteUint32(mod, pResOut, res)
return _OK
}
func getVFS(mod api.Module, pVfs uint32) sqlite3vfs.VFS {
if pVfs == 0 {
return nil
}
name := util.ReadString(mod, util.ReadUint32(mod, pVfs+16), _MAX_STRING)
return sqlite3vfs.Find(name)
}

28
internal/vfs/vfs_api.go Normal file
View File

@@ -0,0 +1,28 @@
package vfs
import (
"reflect"
"github.com/ncruces/go-sqlite3/internal/util"
"github.com/ncruces/go-sqlite3/sqlite3vfs"
"github.com/tetratelabs/wazero/api"
)
func vfsAPIGet(mod api.Module, pVfs uint32) sqlite3vfs.VFS {
if pVfs == 0 {
return nil
}
name := util.ReadString(mod, util.ReadUint32(mod, pVfs+16), _MAX_STRING)
return sqlite3vfs.Find(name)
}
func vfsAPIErrorCode(err error, def _ErrorCode) _ErrorCode {
if err == nil {
return _OK
}
switch v := reflect.ValueOf(err); v.Kind() {
case reflect.Uint8, reflect.Uint16, reflect.Uint32:
return _ErrorCode(v.Uint())
}
return def
}

View File

@@ -18,7 +18,7 @@ type vfsFile struct {
readOnly bool
}
func newVFSFile(vfs *vfsState, file *os.File) uint32 {
func vfsFileNew(vfs *vfsState, file *os.File) uint32 {
// Find an empty slot.
for id, f := range vfs.files {
if f.File == nil {
@@ -32,20 +32,20 @@ func newVFSFile(vfs *vfsState, file *os.File) uint32 {
return uint32(len(vfs.files) - 1)
}
func getVFSFile(ctx context.Context, mod api.Module, pFile uint32) *vfsFile {
func vfsFileGet(ctx context.Context, mod api.Module, pFile uint32) *vfsFile {
vfs := ctx.Value(vfsKey{}).(*vfsState)
id := util.ReadUint32(mod, pFile+4)
return &vfs.files[id]
}
func openVFSFile(ctx context.Context, mod api.Module, pFile uint32, file *os.File) *vfsFile {
func vfsFileOpen(ctx context.Context, mod api.Module, pFile uint32, file *os.File) *vfsFile {
vfs := ctx.Value(vfsKey{}).(*vfsState)
id := newVFSFile(vfs, file)
id := vfsFileNew(vfs, file)
util.WriteUint32(mod, pFile+4, id)
return &vfs.files[id]
}
func closeVFSFile(ctx context.Context, mod api.Module, pFile uint32) error {
func vfsFileClose(ctx context.Context, mod api.Module, pFile uint32) error {
vfs := ctx.Value(vfsKey{}).(*vfsState)
id := util.ReadUint32(mod, pFile+4)
file := vfs.files[id]

View File

@@ -22,7 +22,7 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock _LockLevel
panic(util.AssertErr())
}
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
switch {
case file.lock < _LOCK_NONE || file.lock > _LOCK_EXCLUSIVE:
@@ -98,7 +98,7 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock _LockLev
panic(util.AssertErr())
}
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
// Connection state check.
if file.lock < _LOCK_NONE || file.lock > _LOCK_EXCLUSIVE {
@@ -129,7 +129,7 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock _LockLev
}
func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut uint32) _ErrorCode {
file := getVFSFile(ctx, mod, pFile)
file := vfsFileGet(ctx, mod, pFile)
// Connection state check.
if file.lock < _LOCK_NONE || file.lock > _LOCK_EXCLUSIVE {

View File

@@ -43,8 +43,8 @@ func Test_vfsLock(t *testing.T) {
ctx, vfs := Context(context.TODO())
defer vfs.Close()
openVFSFile(ctx, mod, pFile1, file1)
openVFSFile(ctx, mod, pFile2, file2)
vfsFileOpen(ctx, mod, pFile1, file1)
vfsFileOpen(ctx, mod, pFile2, file2)
rc := vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
if rc != _OK {

View File

@@ -4,7 +4,7 @@ import "sync"
type VFS interface {
Open(name string, flags OpenFlag) (File, OpenFlag, error)
Delete(name string, dirSync bool) error
Delete(name string, syncDir bool) error
Access(name string, flags AccessFlag) (bool, error)
FullPathname(name string) (string, error)
}
@@ -14,10 +14,10 @@ type File interface {
ReadAt(p []byte, off int64) (n int, err error)
WriteAt(p []byte, off int64) (n int, err error)
Truncate(size int64) error
Sync(flag SyncFlag) error
Sync(flags SyncFlag) error
FileSize() (int64, error)
Lock(elock LockLevel) error
Unlock(elock LockLevel) error
Lock(lock LockLevel) error
Unlock(lock LockLevel) error
CheckReservedLock() (bool, error)
SectorSize() int64
}

View File

@@ -18,12 +18,14 @@ func (t testVFS) Open(name string, flags sqlite3vfs.OpenFlag) (sqlite3vfs.File,
return nil, flags, nil
}
func (testVFS) Delete(name string, dirSync bool) error {
panic("unimplemented")
func (t testVFS) Delete(name string, dirSync bool) error {
t.Log("Delete", name, dirSync)
return nil
}
func (testVFS) Access(name string, flags sqlite3vfs.AccessFlag) (bool, error) {
panic("unimplemented")
func (t testVFS) Access(name string, flags sqlite3vfs.AccessFlag) (bool, error) {
t.Log("Access", name, flags)
return true, nil
}
func (t testVFS) FullPathname(name string) (string, error) {