summaryrefslogtreecommitdiff
path: root/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2024-05-27 15:46:15 +0000
committerLibravatar GitHub <noreply@github.com>2024-05-27 17:46:15 +0200
commit1e7b32490dfdccddd04f46d4b0416b48d749d51b (patch)
tree62a11365933a5a11e0800af64cbdf9172e5e6e7a /vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go
parent[chore] Small styling + link issues (#2933) (diff)
downloadgotosocial-1e7b32490dfdccddd04f46d4b0416b48d749d51b.tar.xz
[experiment] add alternative wasm sqlite3 implementation available via build-tag (#2863)
This allows for building GoToSocial with [SQLite transpiled to WASM](https://github.com/ncruces/go-sqlite3) and accessed through [Wazero](https://wazero.io/).
Diffstat (limited to 'vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go')
-rw-r--r--vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go459
1 files changed, 459 insertions, 0 deletions
diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go b/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go
new file mode 100644
index 000000000..1887e9f22
--- /dev/null
+++ b/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go
@@ -0,0 +1,459 @@
+package vfs
+
+import (
+ "context"
+ "crypto/rand"
+ "io"
+ "reflect"
+ "sync"
+ "time"
+
+ "github.com/ncruces/go-sqlite3/internal/util"
+ "github.com/ncruces/julianday"
+ "github.com/tetratelabs/wazero"
+ "github.com/tetratelabs/wazero/api"
+)
+
+// ExportHostFunctions is an internal API users need not call directly.
+//
+// ExportHostFunctions registers the required VFS host functions
+// with the provided env module.
+func ExportHostFunctions(env wazero.HostModuleBuilder) wazero.HostModuleBuilder {
+ util.ExportFuncII(env, "go_vfs_find", vfsFind)
+ util.ExportFuncIIJ(env, "go_localtime", vfsLocaltime)
+ util.ExportFuncIIII(env, "go_randomness", vfsRandomness)
+ util.ExportFuncIII(env, "go_sleep", vfsSleep)
+ util.ExportFuncIII(env, "go_current_time_64", vfsCurrentTime64)
+ util.ExportFuncIIIII(env, "go_full_pathname", vfsFullPathname)
+ util.ExportFuncIIII(env, "go_delete", vfsDelete)
+ util.ExportFuncIIIII(env, "go_access", vfsAccess)
+ util.ExportFuncIIIIIII(env, "go_open", vfsOpen)
+ util.ExportFuncII(env, "go_close", vfsClose)
+ util.ExportFuncIIIIJ(env, "go_read", vfsRead)
+ util.ExportFuncIIIIJ(env, "go_write", vfsWrite)
+ util.ExportFuncIIJ(env, "go_truncate", vfsTruncate)
+ util.ExportFuncIII(env, "go_sync", vfsSync)
+ util.ExportFuncIII(env, "go_file_size", vfsFileSize)
+ util.ExportFuncIIII(env, "go_file_control", vfsFileControl)
+ util.ExportFuncII(env, "go_sector_size", vfsSectorSize)
+ util.ExportFuncII(env, "go_device_characteristics", vfsDeviceCharacteristics)
+ util.ExportFuncIII(env, "go_lock", vfsLock)
+ util.ExportFuncIII(env, "go_unlock", vfsUnlock)
+ util.ExportFuncIII(env, "go_check_reserved_lock", vfsCheckReservedLock)
+ util.ExportFuncIIIIII(env, "go_shm_map", vfsShmMap)
+ util.ExportFuncIIIII(env, "go_shm_lock", vfsShmLock)
+ util.ExportFuncIII(env, "go_shm_unmap", vfsShmUnmap)
+ util.ExportFuncVI(env, "go_shm_barrier", vfsShmBarrier)
+ return env
+}
+
+func vfsFind(ctx context.Context, mod api.Module, zVfsName uint32) uint32 {
+ name := util.ReadString(mod, zVfsName, _MAX_NAME)
+ if vfs := Find(name); vfs != nil && vfs != (vfsOS{}) {
+ return 1
+ }
+ return 0
+}
+
+func vfsLocaltime(ctx context.Context, mod api.Module, pTm uint32, t int64) _ErrorCode {
+ tm := time.Unix(t, 0)
+ var isdst int
+ if tm.IsDST() {
+ isdst = 1
+ }
+
+ const size = 32 / 8
+ // https://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html
+ util.WriteUint32(mod, pTm+0*size, uint32(tm.Second()))
+ util.WriteUint32(mod, pTm+1*size, uint32(tm.Minute()))
+ util.WriteUint32(mod, pTm+2*size, uint32(tm.Hour()))
+ util.WriteUint32(mod, pTm+3*size, uint32(tm.Day()))
+ util.WriteUint32(mod, pTm+4*size, uint32(tm.Month()-time.January))
+ util.WriteUint32(mod, pTm+5*size, uint32(tm.Year()-1900))
+ util.WriteUint32(mod, pTm+6*size, uint32(tm.Weekday()-time.Sunday))
+ util.WriteUint32(mod, pTm+7*size, uint32(tm.YearDay()-1))
+ util.WriteUint32(mod, pTm+8*size, uint32(isdst))
+ return _OK
+}
+
+func vfsRandomness(ctx context.Context, mod api.Module, pVfs uint32, nByte int32, zByte uint32) uint32 {
+ mem := util.View(mod, zByte, uint64(nByte))
+ n, _ := rand.Reader.Read(mem)
+ return uint32(n)
+}
+
+func vfsSleep(ctx context.Context, mod api.Module, pVfs uint32, nMicro int32) _ErrorCode {
+ osSleep(time.Duration(nMicro) * time.Microsecond)
+ return _OK
+}
+
+func vfsCurrentTime64(ctx context.Context, mod api.Module, pVfs, piNow uint32) _ErrorCode {
+ day, nsec := julianday.Date(time.Now())
+ msec := day*86_400_000 + nsec/1_000_000
+ util.WriteUint64(mod, piNow, uint64(msec))
+ return _OK
+}
+
+func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative uint32, nFull int32, zFull uint32) _ErrorCode {
+ vfs := vfsGet(mod, pVfs)
+ path := util.ReadString(mod, zRelative, _MAX_PATHNAME)
+
+ path, err := vfs.FullPathname(path)
+
+ if len(path) >= int(nFull) {
+ return _CANTOPEN_FULLPATH
+ }
+ util.WriteString(mod, zFull, path)
+
+ return vfsErrorCode(err, _CANTOPEN_FULLPATH)
+}
+
+func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath, syncDir uint32) _ErrorCode {
+ vfs := vfsGet(mod, pVfs)
+ path := util.ReadString(mod, zPath, _MAX_PATHNAME)
+
+ err := vfs.Delete(path, syncDir != 0)
+ return vfsErrorCode(err, _IOERR_DELETE)
+}
+
+func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath uint32, flags AccessFlag, pResOut uint32) _ErrorCode {
+ vfs := vfsGet(mod, pVfs)
+ path := util.ReadString(mod, zPath, _MAX_PATHNAME)
+
+ ok, err := vfs.Access(path, flags)
+ var res uint32
+ if ok {
+ res = 1
+ }
+
+ util.WriteUint32(mod, pResOut, res)
+ return vfsErrorCode(err, _IOERR_ACCESS)
+}
+
+func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile uint32, flags OpenFlag, pOutFlags, pOutVFS uint32) _ErrorCode {
+ vfs := vfsGet(mod, pVfs)
+
+ var path string
+ if zPath != 0 {
+ path = util.ReadString(mod, zPath, _MAX_PATHNAME)
+ }
+
+ var file File
+ var err error
+ if ffs, ok := vfs.(VFSFilename); ok {
+ name := OpenFilename(ctx, mod, zPath, flags)
+ file, flags, err = ffs.OpenFilename(name, flags)
+ } else {
+ file, flags, err = vfs.Open(path, flags)
+ }
+ if err != nil {
+ return vfsErrorCode(err, _CANTOPEN)
+ }
+
+ if file, ok := file.(FilePowersafeOverwrite); ok {
+ name := OpenFilename(ctx, mod, zPath, flags)
+ if b, ok := util.ParseBool(name.URIParameter("psow")); ok {
+ file.SetPowersafeOverwrite(b)
+ }
+ }
+ if file, ok := file.(FileSharedMemory); ok &&
+ pOutVFS != 0 && file.SharedMemory() != nil {
+ util.WriteUint32(mod, pOutVFS, 1)
+ }
+ if pOutFlags != 0 {
+ util.WriteUint32(mod, pOutFlags, uint32(flags))
+ }
+ vfsFileRegister(ctx, mod, pFile, file)
+ return _OK
+}
+
+func vfsClose(ctx context.Context, mod api.Module, pFile uint32) _ErrorCode {
+ err := vfsFileClose(ctx, mod, pFile)
+ if err != nil {
+ return vfsErrorCode(err, _IOERR_CLOSE)
+ }
+ return _OK
+}
+
+func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf uint32, iAmt int32, iOfst int64) _ErrorCode {
+ file := vfsFileGet(ctx, mod, pFile).(File)
+ buf := util.View(mod, zBuf, uint64(iAmt))
+
+ n, err := file.ReadAt(buf, iOfst)
+ if n == int(iAmt) {
+ return _OK
+ }
+ if err != io.EOF {
+ return vfsErrorCode(err, _IOERR_READ)
+ }
+ clear(buf[n:])
+ return _IOERR_SHORT_READ
+}
+
+func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf uint32, iAmt int32, iOfst int64) _ErrorCode {
+ file := vfsFileGet(ctx, mod, pFile).(File)
+ buf := util.View(mod, zBuf, uint64(iAmt))
+
+ _, err := file.WriteAt(buf, iOfst)
+ if err != nil {
+ return vfsErrorCode(err, _IOERR_WRITE)
+ }
+ return _OK
+}
+
+func vfsTruncate(ctx context.Context, mod api.Module, pFile uint32, nByte int64) _ErrorCode {
+ file := vfsFileGet(ctx, mod, pFile).(File)
+ err := file.Truncate(nByte)
+ return vfsErrorCode(err, _IOERR_TRUNCATE)
+}
+
+func vfsSync(ctx context.Context, mod api.Module, pFile uint32, flags SyncFlag) _ErrorCode {
+ file := vfsFileGet(ctx, mod, pFile).(File)
+ err := file.Sync(flags)
+ return vfsErrorCode(err, _IOERR_FSYNC)
+}
+
+func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize uint32) _ErrorCode {
+ file := vfsFileGet(ctx, mod, pFile).(File)
+ size, err := file.Size()
+ util.WriteUint64(mod, pSize, uint64(size))
+ return vfsErrorCode(err, _IOERR_SEEK)
+}
+
+func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock LockLevel) _ErrorCode {
+ file := vfsFileGet(ctx, mod, pFile).(File)
+ err := file.Lock(eLock)
+ return vfsErrorCode(err, _IOERR_LOCK)
+}
+
+func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock LockLevel) _ErrorCode {
+ file := vfsFileGet(ctx, mod, pFile).(File)
+ err := file.Unlock(eLock)
+ return vfsErrorCode(err, _IOERR_UNLOCK)
+}
+
+func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut uint32) _ErrorCode {
+ file := vfsFileGet(ctx, mod, pFile).(File)
+ locked, err := file.CheckReservedLock()
+
+ var res uint32
+ if locked {
+ res = 1
+ }
+
+ util.WriteUint32(mod, pResOut, res)
+ return vfsErrorCode(err, _IOERR_CHECKRESERVEDLOCK)
+}
+
+func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _FcntlOpcode, pArg uint32) _ErrorCode {
+ file := vfsFileGet(ctx, mod, pFile).(File)
+
+ switch op {
+ case _FCNTL_LOCKSTATE:
+ if file, ok := file.(FileLockState); ok {
+ util.WriteUint32(mod, pArg, uint32(file.LockState()))
+ return _OK
+ }
+
+ case _FCNTL_PERSIST_WAL:
+ if file, ok := file.(FilePersistentWAL); ok {
+ if i := util.ReadUint32(mod, pArg); int32(i) >= 0 {
+ file.SetPersistentWAL(i != 0)
+ } else if file.PersistentWAL() {
+ util.WriteUint32(mod, pArg, 1)
+ } else {
+ util.WriteUint32(mod, pArg, 0)
+ }
+ return _OK
+ }
+
+ case _FCNTL_POWERSAFE_OVERWRITE:
+ if file, ok := file.(FilePowersafeOverwrite); ok {
+ if i := util.ReadUint32(mod, pArg); int32(i) >= 0 {
+ file.SetPowersafeOverwrite(i != 0)
+ } else if file.PowersafeOverwrite() {
+ util.WriteUint32(mod, pArg, 1)
+ } else {
+ util.WriteUint32(mod, pArg, 0)
+ }
+ return _OK
+ }
+
+ case _FCNTL_CHUNK_SIZE:
+ if file, ok := file.(FileChunkSize); ok {
+ size := util.ReadUint32(mod, pArg)
+ file.ChunkSize(int(size))
+ return _OK
+ }
+
+ case _FCNTL_SIZE_HINT:
+ if file, ok := file.(FileSizeHint); ok {
+ size := util.ReadUint64(mod, pArg)
+ err := file.SizeHint(int64(size))
+ return vfsErrorCode(err, _IOERR_TRUNCATE)
+ }
+
+ case _FCNTL_HAS_MOVED:
+ if file, ok := file.(FileHasMoved); ok {
+ moved, err := file.HasMoved()
+ var res uint32
+ if moved {
+ res = 1
+ }
+ util.WriteUint32(mod, pArg, res)
+ return vfsErrorCode(err, _IOERR_FSTAT)
+ }
+
+ case _FCNTL_OVERWRITE:
+ if file, ok := file.(FileOverwrite); ok {
+ err := file.Overwrite()
+ return vfsErrorCode(err, _IOERR)
+ }
+
+ case _FCNTL_COMMIT_PHASETWO:
+ if file, ok := file.(FileCommitPhaseTwo); ok {
+ err := file.CommitPhaseTwo()
+ return vfsErrorCode(err, _IOERR)
+ }
+
+ case _FCNTL_BEGIN_ATOMIC_WRITE:
+ if file, ok := file.(FileBatchAtomicWrite); ok {
+ err := file.BeginAtomicWrite()
+ return vfsErrorCode(err, _IOERR_BEGIN_ATOMIC)
+ }
+ case _FCNTL_COMMIT_ATOMIC_WRITE:
+ if file, ok := file.(FileBatchAtomicWrite); ok {
+ err := file.CommitAtomicWrite()
+ return vfsErrorCode(err, _IOERR_COMMIT_ATOMIC)
+ }
+ case _FCNTL_ROLLBACK_ATOMIC_WRITE:
+ if file, ok := file.(FileBatchAtomicWrite); ok {
+ err := file.RollbackAtomicWrite()
+ return vfsErrorCode(err, _IOERR_ROLLBACK_ATOMIC)
+ }
+
+ case _FCNTL_CKPT_DONE:
+ if file, ok := file.(FileCheckpoint); ok {
+ err := file.CheckpointDone()
+ return vfsErrorCode(err, _IOERR)
+ }
+ case _FCNTL_CKPT_START:
+ if file, ok := file.(FileCheckpoint); ok {
+ err := file.CheckpointStart()
+ return vfsErrorCode(err, _IOERR)
+ }
+
+ case _FCNTL_PRAGMA:
+ if file, ok := file.(FilePragma); ok {
+ ptr := util.ReadUint32(mod, pArg+1*ptrlen)
+ name := util.ReadString(mod, ptr, _MAX_SQL_LENGTH)
+ var value string
+ if ptr := util.ReadUint32(mod, pArg+2*ptrlen); ptr != 0 {
+ value = util.ReadString(mod, ptr, _MAX_SQL_LENGTH)
+ }
+
+ out, err := file.Pragma(name, value)
+
+ ret := vfsErrorCode(err, _ERROR)
+ if ret == _ERROR {
+ out = err.Error()
+ }
+ if out != "" {
+ fn := mod.ExportedFunction("malloc")
+ stack := [...]uint64{uint64(len(out) + 1)}
+ if err := fn.CallWithStack(ctx, stack[:]); err != nil {
+ panic(err)
+ }
+ util.WriteUint32(mod, pArg, uint32(stack[0]))
+ util.WriteString(mod, uint32(stack[0]), out)
+ }
+ return ret
+ }
+ }
+
+ // Consider also implementing these opcodes (in use by SQLite):
+ // _FCNTL_BUSYHANDLER
+ // _FCNTL_LAST_ERRNO
+ // _FCNTL_SYNC
+ return _NOTFOUND
+}
+
+func vfsSectorSize(ctx context.Context, mod api.Module, pFile uint32) uint32 {
+ file := vfsFileGet(ctx, mod, pFile).(File)
+ return uint32(file.SectorSize())
+}
+
+func vfsDeviceCharacteristics(ctx context.Context, mod api.Module, pFile uint32) DeviceCharacteristic {
+ file := vfsFileGet(ctx, mod, pFile).(File)
+ return file.DeviceCharacteristics()
+}
+
+var shmBarrier sync.Mutex
+
+func vfsShmBarrier(ctx context.Context, mod api.Module, pFile uint32) {
+ shmBarrier.Lock()
+ defer shmBarrier.Unlock()
+}
+
+func vfsShmMap(ctx context.Context, mod api.Module, pFile uint32, iRegion, szRegion int32, bExtend, pp uint32) _ErrorCode {
+ shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory()
+ p, err := shm.shmMap(ctx, mod, iRegion, szRegion, bExtend != 0)
+ if err != nil {
+ return vfsErrorCode(err, _IOERR_SHMMAP)
+ }
+ util.WriteUint32(mod, pp, p)
+ return _OK
+}
+
+func vfsShmLock(ctx context.Context, mod api.Module, pFile uint32, offset, n int32, flags _ShmFlag) _ErrorCode {
+ shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory()
+ err := shm.shmLock(offset, n, flags)
+ return vfsErrorCode(err, _IOERR_SHMLOCK)
+}
+
+func vfsShmUnmap(ctx context.Context, mod api.Module, pFile, bDelete uint32) _ErrorCode {
+ shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory()
+ shm.shmUnmap(bDelete != 0)
+ return _OK
+}
+
+func vfsGet(mod api.Module, pVfs uint32) VFS {
+ var name string
+ if pVfs != 0 {
+ const zNameOffset = 16
+ name = util.ReadString(mod, util.ReadUint32(mod, pVfs+zNameOffset), _MAX_NAME)
+ }
+ if vfs := Find(name); vfs != nil {
+ return vfs
+ }
+ panic(util.NoVFSErr + util.ErrorString(name))
+}
+
+func vfsFileRegister(ctx context.Context, mod api.Module, pFile uint32, file File) {
+ const fileHandleOffset = 4
+ id := util.AddHandle(ctx, file)
+ util.WriteUint32(mod, pFile+fileHandleOffset, id)
+}
+
+func vfsFileGet(ctx context.Context, mod api.Module, pFile uint32) any {
+ const fileHandleOffset = 4
+ id := util.ReadUint32(mod, pFile+fileHandleOffset)
+ return util.GetHandle(ctx, id)
+}
+
+func vfsFileClose(ctx context.Context, mod api.Module, pFile uint32) error {
+ const fileHandleOffset = 4
+ id := util.ReadUint32(mod, pFile+fileHandleOffset)
+ return util.DelHandle(ctx, id)
+}
+
+func vfsErrorCode(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
+}