2023-01-18 01:30:11 +00:00
|
|
|
package sqlite3
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2023-01-19 00:18:39 +00:00
|
|
|
"errors"
|
2023-01-18 23:45:22 +00:00
|
|
|
"io"
|
2023-01-19 00:18:39 +00:00
|
|
|
"io/fs"
|
2023-01-18 01:30:11 +00:00
|
|
|
"math/rand"
|
2023-01-18 18:58:49 +00:00
|
|
|
"os"
|
2023-01-18 11:40:08 +00:00
|
|
|
"path/filepath"
|
2023-01-19 13:27:32 +00:00
|
|
|
"syscall"
|
2023-01-18 01:30:11 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/ncruces/julianday"
|
|
|
|
|
"github.com/tetratelabs/wazero"
|
|
|
|
|
"github.com/tetratelabs/wazero/api"
|
|
|
|
|
"github.com/tetratelabs/wazero/sys"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func vfsInstantiate(ctx context.Context, r wazero.Runtime) (err error) {
|
|
|
|
|
wasi := r.NewHostModuleBuilder("wasi_snapshot_preview1")
|
|
|
|
|
wasi.NewFunctionBuilder().WithFunc(vfsExit).Export("proc_exit")
|
|
|
|
|
_, err = wasi.Instantiate(ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
env := r.NewHostModuleBuilder("env")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsRandomness).Export("go_randomness")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsSleep).Export("go_sleep")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsCurrentTime).Export("go_current_time")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsCurrentTime64).Export("go_current_time_64")
|
2023-01-18 18:58:49 +00:00
|
|
|
env.NewFunctionBuilder().WithFunc(vfsFullPathname).Export("go_full_pathname")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsDelete).Export("go_delete")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsAccess).Export("go_access")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsOpen).Export("go_open")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsClose).Export("go_close")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsRead).Export("go_read")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsWrite).Export("go_write")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsTruncate).Export("go_truncate")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsSync).Export("go_sync")
|
|
|
|
|
env.NewFunctionBuilder().WithFunc(vfsFileSize).Export("go_file_size")
|
2023-01-18 01:30:11 +00:00
|
|
|
_, err = env.Instantiate(ctx)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func vfsExit(ctx context.Context, mod api.Module, exitCode uint32) {
|
|
|
|
|
// Ensure other callers see the exit code.
|
|
|
|
|
_ = mod.CloseWithExitCode(ctx, exitCode)
|
|
|
|
|
// Prevent any code from executing after this function.
|
|
|
|
|
panic(sys.NewExitError(mod.Name(), exitCode))
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-18 11:40:08 +00:00
|
|
|
func vfsRandomness(ctx context.Context, mod api.Module, vfs, nByte, zOut uint32) uint32 {
|
|
|
|
|
mem, ok := mod.Memory().Read(zOut, nByte)
|
2023-01-18 01:30:11 +00:00
|
|
|
if !ok {
|
2023-01-19 14:31:32 +00:00
|
|
|
panic(rangeErr)
|
2023-01-18 01:30:11 +00:00
|
|
|
}
|
|
|
|
|
n, _ := rand.Read(mem)
|
|
|
|
|
return uint32(n)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func vfsSleep(ctx context.Context, vfs, microseconds uint32) uint32 {
|
|
|
|
|
time.Sleep(time.Duration(microseconds) * time.Microsecond)
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func vfsCurrentTime(ctx context.Context, mod api.Module, vfs, out uint32) uint32 {
|
|
|
|
|
day := julianday.Float(time.Now())
|
2023-01-19 14:31:32 +00:00
|
|
|
if ok := mod.Memory().WriteFloat64Le(out, day); !ok {
|
|
|
|
|
panic(rangeErr)
|
2023-01-18 01:30:11 +00:00
|
|
|
}
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func vfsCurrentTime64(ctx context.Context, mod api.Module, vfs, out uint32) uint32 {
|
|
|
|
|
day, nsec := julianday.Date(time.Now())
|
|
|
|
|
msec := day*86_400_000 + nsec/1_000_000
|
2023-01-19 14:31:32 +00:00
|
|
|
if ok := mod.Memory().WriteUint64Le(out, uint64(msec)); !ok {
|
|
|
|
|
panic(rangeErr)
|
2023-01-18 01:30:11 +00:00
|
|
|
}
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
2023-01-18 11:40:08 +00:00
|
|
|
|
|
|
|
|
func vfsFullPathname(ctx context.Context, mod api.Module, vfs, zName, nOut, zOut uint32) uint32 {
|
|
|
|
|
name := getString(mod.Memory(), zName, _MAX_PATHNAME)
|
|
|
|
|
s, err := filepath.Abs(name)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return uint32(IOERR)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
siz := uint32(len(s) + 1)
|
2023-01-19 14:31:32 +00:00
|
|
|
if siz > nOut {
|
2023-01-18 11:40:08 +00:00
|
|
|
return uint32(IOERR)
|
|
|
|
|
}
|
|
|
|
|
mem, ok := mod.Memory().Read(zOut, siz)
|
|
|
|
|
if !ok {
|
2023-01-19 14:31:32 +00:00
|
|
|
panic(rangeErr)
|
2023-01-18 11:40:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mem[len(s)] = 0
|
|
|
|
|
copy(mem, s)
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
2023-01-18 18:58:49 +00:00
|
|
|
|
2023-01-19 01:12:09 +00:00
|
|
|
func vfsDelete(ctx context.Context, mod api.Module, vfs, zName, syncDir uint32) uint32 {
|
|
|
|
|
name := getString(mod.Memory(), zName, _MAX_PATHNAME)
|
|
|
|
|
err := os.Remove(name)
|
|
|
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return uint32(IOERR_DELETE)
|
|
|
|
|
}
|
|
|
|
|
if syncDir != 0 {
|
|
|
|
|
f, err := os.Open(filepath.Dir(name))
|
|
|
|
|
if err == nil {
|
|
|
|
|
err = f.Sync()
|
|
|
|
|
f.Close()
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return uint32(IOERR_DELETE)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
2023-01-18 18:58:49 +00:00
|
|
|
|
2023-01-19 00:18:39 +00:00
|
|
|
func vfsAccess(ctx context.Context, mod api.Module, vfs, zName, flags, pResOut uint32) uint32 {
|
|
|
|
|
name := getString(mod.Memory(), zName, _MAX_PATHNAME)
|
|
|
|
|
fi, err := os.Stat(name)
|
|
|
|
|
|
|
|
|
|
var res uint32
|
|
|
|
|
if flags == uint32(ACCESS_EXISTS) {
|
|
|
|
|
switch {
|
|
|
|
|
case err == nil:
|
|
|
|
|
res = 1
|
|
|
|
|
case errors.Is(err, fs.ErrNotExist):
|
|
|
|
|
res = 0
|
|
|
|
|
default:
|
|
|
|
|
return uint32(IOERR_ACCESS)
|
|
|
|
|
}
|
2023-01-19 13:27:32 +00:00
|
|
|
} else if err == nil {
|
|
|
|
|
var want fs.FileMode = syscall.S_IRUSR
|
2023-01-19 00:18:39 +00:00
|
|
|
if flags == uint32(ACCESS_READWRITE) {
|
2023-01-19 13:27:32 +00:00
|
|
|
want |= syscall.S_IWUSR
|
2023-01-19 00:18:39 +00:00
|
|
|
}
|
2023-01-19 13:27:32 +00:00
|
|
|
if fi.IsDir() {
|
|
|
|
|
want |= syscall.S_IXUSR
|
|
|
|
|
}
|
|
|
|
|
if fi.Mode()&want == want {
|
2023-01-19 00:18:39 +00:00
|
|
|
res = 1
|
|
|
|
|
} else {
|
|
|
|
|
res = 0
|
|
|
|
|
}
|
2023-01-19 13:27:32 +00:00
|
|
|
} else if errors.Is(err, fs.ErrPermission) {
|
|
|
|
|
res = 0
|
|
|
|
|
} else {
|
|
|
|
|
return uint32(IOERR_ACCESS)
|
2023-01-19 00:18:39 +00:00
|
|
|
}
|
|
|
|
|
|
2023-01-19 14:31:32 +00:00
|
|
|
if ok := mod.Memory().WriteUint32Le(pResOut, res); !ok {
|
|
|
|
|
panic(rangeErr)
|
2023-01-19 00:18:39 +00:00
|
|
|
}
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
2023-01-18 18:58:49 +00:00
|
|
|
|
|
|
|
|
func vfsOpen(ctx context.Context, mod api.Module, vfs, zName, file, flags, pOutFlags uint32) uint32 {
|
|
|
|
|
name := getString(mod.Memory(), zName, _MAX_PATHNAME)
|
|
|
|
|
c := ctx.Value(connContext{}).(*Conn)
|
|
|
|
|
|
|
|
|
|
var oflags int
|
|
|
|
|
if OpenFlag(flags)&OPEN_EXCLUSIVE != 0 {
|
|
|
|
|
oflags |= os.O_EXCL
|
|
|
|
|
}
|
|
|
|
|
if OpenFlag(flags)&OPEN_CREATE != 0 {
|
|
|
|
|
oflags |= os.O_CREATE
|
|
|
|
|
}
|
|
|
|
|
if OpenFlag(flags)&OPEN_READONLY != 0 {
|
|
|
|
|
oflags |= os.O_RDONLY
|
|
|
|
|
}
|
|
|
|
|
if OpenFlag(flags)&OPEN_READWRITE != 0 {
|
|
|
|
|
oflags |= os.O_RDWR
|
|
|
|
|
}
|
|
|
|
|
f, err := os.OpenFile(name, oflags, 0600)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return uint32(CANTOPEN)
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-21 12:24:36 +00:00
|
|
|
if ok := mod.Memory().WriteUint32Le(file+ptrSize, c.getFile(f)); !ok {
|
|
|
|
|
panic(rangeErr)
|
2023-01-18 18:58:49 +00:00
|
|
|
}
|
2023-01-21 12:24:36 +00:00
|
|
|
if pOutFlags == 0 {
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
|
|
|
|
if ok := mod.Memory().WriteUint32Le(pOutFlags, flags); !ok {
|
2023-01-19 14:31:32 +00:00
|
|
|
panic(rangeErr)
|
2023-01-19 00:25:56 +00:00
|
|
|
}
|
2023-01-18 18:58:49 +00:00
|
|
|
return _OK
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func vfsClose(ctx context.Context, mod api.Module, file uint32) uint32 {
|
|
|
|
|
id, ok := mod.Memory().ReadUint32Le(file + ptrSize)
|
|
|
|
|
if !ok {
|
2023-01-19 14:31:32 +00:00
|
|
|
panic(rangeErr)
|
2023-01-18 18:58:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c := ctx.Value(connContext{}).(*Conn)
|
|
|
|
|
err := c.files[id].Close()
|
|
|
|
|
c.files[id] = nil
|
|
|
|
|
if err != nil {
|
2023-01-19 00:18:39 +00:00
|
|
|
return uint32(IOERR_CLOSE)
|
2023-01-18 18:58:49 +00:00
|
|
|
}
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 15:46:53 +00:00
|
|
|
func vfsFile(ctx context.Context, mod api.Module, file uint32) *os.File {
|
2023-01-18 23:45:22 +00:00
|
|
|
id, ok := mod.Memory().ReadUint32Le(file + ptrSize)
|
|
|
|
|
if !ok {
|
2023-01-19 14:31:32 +00:00
|
|
|
panic(rangeErr)
|
2023-01-18 23:45:22 +00:00
|
|
|
}
|
|
|
|
|
|
2023-01-19 15:46:53 +00:00
|
|
|
c := ctx.Value(connContext{}).(*Conn)
|
|
|
|
|
return c.files[id]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func vfsRead(ctx context.Context, mod api.Module, file, buf, iAmt uint32, iOfst uint64) uint32 {
|
2023-01-18 23:45:22 +00:00
|
|
|
mem, ok := mod.Memory().Read(buf, iAmt)
|
|
|
|
|
if !ok {
|
2023-01-19 14:31:32 +00:00
|
|
|
panic(rangeErr)
|
2023-01-18 23:45:22 +00:00
|
|
|
}
|
|
|
|
|
|
2023-01-19 15:46:53 +00:00
|
|
|
f := vfsFile(ctx, mod, file)
|
|
|
|
|
n, err := f.ReadAt(mem, int64(iOfst))
|
2023-01-18 23:45:22 +00:00
|
|
|
if n == int(iAmt) {
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
|
|
|
|
if n == 0 && err != io.EOF {
|
|
|
|
|
return uint32(IOERR_READ)
|
|
|
|
|
}
|
|
|
|
|
for i := range mem[n:] {
|
|
|
|
|
mem[i] = 0
|
|
|
|
|
}
|
|
|
|
|
return uint32(IOERR_SHORT_READ)
|
2023-01-18 18:58:49 +00:00
|
|
|
}
|
|
|
|
|
|
2023-01-19 00:58:57 +00:00
|
|
|
func vfsWrite(ctx context.Context, mod api.Module, file, buf, iAmt uint32, iOfst uint64) uint32 {
|
|
|
|
|
mem, ok := mod.Memory().Read(buf, iAmt)
|
|
|
|
|
if !ok {
|
2023-01-19 14:31:32 +00:00
|
|
|
panic(rangeErr)
|
2023-01-19 00:58:57 +00:00
|
|
|
}
|
|
|
|
|
|
2023-01-19 15:46:53 +00:00
|
|
|
f := vfsFile(ctx, mod, file)
|
|
|
|
|
_, err := f.WriteAt(mem, int64(iOfst))
|
2023-01-19 00:58:57 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return uint32(IOERR_WRITE)
|
|
|
|
|
}
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
2023-01-18 18:58:49 +00:00
|
|
|
|
2023-01-19 01:12:09 +00:00
|
|
|
func vfsTruncate(ctx context.Context, mod api.Module, file uint32, size uint64) uint32 {
|
2023-01-19 15:46:53 +00:00
|
|
|
f := vfsFile(ctx, mod, file)
|
|
|
|
|
err := f.Truncate(int64(size))
|
2023-01-19 01:12:09 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return uint32(IOERR_TRUNCATE)
|
|
|
|
|
}
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
2023-01-18 18:58:49 +00:00
|
|
|
|
2023-01-19 00:58:57 +00:00
|
|
|
func vfsSync(ctx context.Context, mod api.Module, file, flags uint32) uint32 {
|
2023-01-19 15:46:53 +00:00
|
|
|
f := vfsFile(ctx, mod, file)
|
|
|
|
|
err := f.Sync()
|
2023-01-19 00:58:57 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return uint32(IOERR_FSYNC)
|
|
|
|
|
}
|
|
|
|
|
return _OK
|
|
|
|
|
}
|
2023-01-18 18:58:49 +00:00
|
|
|
|
2023-01-19 00:25:56 +00:00
|
|
|
func vfsFileSize(ctx context.Context, mod api.Module, file, pSize uint32) uint32 {
|
2023-01-19 15:46:53 +00:00
|
|
|
f := vfsFile(ctx, mod, file)
|
|
|
|
|
off, err := f.Seek(0, io.SeekEnd)
|
2023-01-19 00:25:56 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return uint32(IOERR_SEEK)
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 14:31:32 +00:00
|
|
|
if ok := mod.Memory().WriteUint64Le(pSize, uint64(off)); !ok {
|
|
|
|
|
panic(rangeErr)
|
2023-01-19 00:25:56 +00:00
|
|
|
}
|
|
|
|
|
return _OK
|
|
|
|
|
}
|