Removes experimental.WithFS (#922)
This removes the ability to override the current file system with Go context, allowing us to simplify common paths and improve performance. The context override was only used once in GitHub, in Trivy, and we found another way to do that without it. Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
@@ -2,6 +2,7 @@ package experimental_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
@@ -36,6 +37,13 @@ func Example_withCompilationCacheDirName() {
|
||||
//
|
||||
}
|
||||
|
||||
// fsWasm was generated by the following:
|
||||
//
|
||||
// cd testdata; wat2wasm --debug-names fs.wat
|
||||
//
|
||||
//go:embed testdata/fs.wasm
|
||||
var fsWasm []byte
|
||||
|
||||
// newRuntimeCompileDestroy creates a new wazero.Runtime, compile a binary, and then delete the runtime.
|
||||
func newRuntimeCompileClose(ctx context.Context) {
|
||||
r := wazero.NewRuntime(ctx)
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package experimental
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/fs"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
internalfs "github.com/tetratelabs/wazero/internal/sys"
|
||||
)
|
||||
|
||||
// WithFS overrides fs.FS in the context-based manner. Caller needs to take
|
||||
// responsibility for closing the returned api.Closer.
|
||||
//
|
||||
// Note: This has the same effect as the same function on wazero.ModuleConfig.
|
||||
func WithFS(ctx context.Context, fs fs.FS) (context.Context, api.Closer, error) {
|
||||
if fs == nil {
|
||||
fs = internalfs.EmptyFS
|
||||
}
|
||||
if fsCtx, err := internalfs.NewFSContext(fs); err != nil {
|
||||
return nil, nil, err
|
||||
} else {
|
||||
return context.WithValue(ctx, internalfs.FSKey{}, fsCtx), fsCtx, err
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package experimental_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/experimental"
|
||||
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
|
||||
)
|
||||
|
||||
// fsWasm was generated by the following:
|
||||
//
|
||||
// cd testdata; wat2wasm --debug-names fs.wat
|
||||
//
|
||||
//go:embed testdata/fs.wasm
|
||||
var fsWasm []byte
|
||||
|
||||
// This is a basic example of overriding the file system via WithFS. The main
|
||||
// goal is to show how it is configured.
|
||||
func Example_withFS() {
|
||||
ctx := context.Background()
|
||||
|
||||
r := wazero.NewRuntime(ctx)
|
||||
defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
|
||||
wasi_snapshot_preview1.MustInstantiate(ctx, r)
|
||||
|
||||
// Instantiate a module exporting a WASI function that uses the filesystem.
|
||||
mod, err := r.InstantiateModuleFromBinary(ctx, fsWasm)
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
// Configure the filesystem overlay, noting that it can fail if the
|
||||
// directory is invalid. The closer must be closed.
|
||||
ctx, closer, err := experimental.WithFS(ctx, os.DirFS("."))
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer closer.Close(ctx)
|
||||
|
||||
fdPrestatDirName := mod.ExportedFunction("fd_prestat_dir_name")
|
||||
fd := 3 // after stderr
|
||||
pathLen := 1 // length we expect the path to be.
|
||||
pathOffset := 0 // where to write pathLen bytes.
|
||||
|
||||
// By default, there are no pre-opened directories. If the configuration
|
||||
// was wrong, this call would fail.
|
||||
results, err := fdPrestatDirName.Call(ctx, uint64(fd), uint64(pathOffset), uint64(pathLen))
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
if results[0] != 0 {
|
||||
log.Panicf("received errno %d\n", results[0])
|
||||
}
|
||||
|
||||
// Try to read the path!
|
||||
if path, ok := mod.Memory().Read(ctx, uint32(pathOffset), uint32(pathLen)); !ok {
|
||||
log.Panicln("out of memory reading path")
|
||||
} else {
|
||||
fmt.Println(string(path))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// /
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package experimental_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental"
|
||||
"github.com/tetratelabs/wazero/internal/sys"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
|
||||
// This is a very basic integration of fs config. The main goal is to show how it is configured.
|
||||
func TestWithFS(t *testing.T) {
|
||||
fileName := "animals.txt"
|
||||
mapfs := fstest.MapFS{fileName: &fstest.MapFile{Data: []byte(`animals`)}}
|
||||
|
||||
// Set context to one that has experimental fs config
|
||||
ctx, closer, err := experimental.WithFS(context.Background(), mapfs)
|
||||
require.NoError(t, err)
|
||||
defer closer.Close(ctx)
|
||||
|
||||
v := ctx.Value(sys.FSKey{})
|
||||
require.NotNil(t, v)
|
||||
fsCtx, ok := v.(*sys.FSContext)
|
||||
require.True(t, ok)
|
||||
|
||||
entry, ok := fsCtx.OpenedFile(ctx, 3)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "/", entry.Name)
|
||||
|
||||
// Override to nil context, ex to block file access
|
||||
ctx, closer, err = experimental.WithFS(ctx, nil)
|
||||
require.NoError(t, err)
|
||||
defer closer.Close(ctx)
|
||||
|
||||
v = ctx.Value(sys.FSKey{})
|
||||
require.NotNil(t, v)
|
||||
fsCtx, ok = v.(*sys.FSContext)
|
||||
require.True(t, ok)
|
||||
|
||||
_, ok = fsCtx.OpenedFile(ctx, 3)
|
||||
require.False(t, ok)
|
||||
}
|
||||
BIN
experimental/testdata/clock.wasm
vendored
BIN
experimental/testdata/clock.wasm
vendored
Binary file not shown.
9
experimental/testdata/clock.wat
vendored
9
experimental/testdata/clock.wat
vendored
@@ -1,9 +0,0 @@
|
||||
(module
|
||||
(func ;; re-export fd_prestat_dir_name, imported from WASI
|
||||
(export "clock_time_get")
|
||||
(import "wasi_snapshot_preview1" "clock_time_get")
|
||||
(param $id i32) (param $precision i64) (param $result.timestamp i32) (result (;errno;) i32)
|
||||
)
|
||||
|
||||
(memory (export "memory") 1 1) ;; memory is required for WASI
|
||||
)
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
internalsys "github.com/tetratelabs/wazero/internal/sys"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
@@ -155,16 +156,19 @@ var abortMessageDisabled = abortMessageEnabled.WithGoModuleFunc(abort)
|
||||
|
||||
// abortWithMessage implements functionAbort
|
||||
func abortWithMessage(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
mem := mod.Memory()
|
||||
|
||||
message := uint32(stack[0])
|
||||
fileName := uint32(stack[1])
|
||||
lineNumber := uint32(stack[2])
|
||||
columnNumber := uint32(stack[3])
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
mem := mod.Memory()
|
||||
|
||||
// Don't panic if there was a problem reading the message
|
||||
stderr := fsc.FdWriter(internalsys.FdStderr)
|
||||
if msg, msgOk := readAssemblyScriptString(ctx, mem, message); msgOk {
|
||||
if fn, fnOk := readAssemblyScriptString(ctx, mem, fileName); fnOk {
|
||||
_, _ = fmt.Fprintf(sysCtx.Stderr(), "%s at %s:%d:%d\n", msg, fn, lineNumber, columnNumber)
|
||||
_, _ = fmt.Fprintf(stderr, "%s at %s:%d:%d\n", msg, fn, lineNumber, columnNumber)
|
||||
}
|
||||
}
|
||||
abort(ctx, mod, stack)
|
||||
@@ -195,14 +199,18 @@ var traceStdout = &wasm.HostFunc{
|
||||
Code: &wasm.Code{
|
||||
IsHostFunction: true,
|
||||
GoFunc: api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
traceTo(ctx, mod, stack, mod.(*wasm.CallContext).Sys.Stdout())
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
stdout := fsc.FdWriter(internalsys.FdStdout)
|
||||
traceTo(ctx, mod, stack, stdout)
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
// traceStderr implements trace to the configured Stderr.
|
||||
var traceStderr = traceStdout.WithGoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
traceTo(ctx, mod, stack, mod.(*wasm.CallContext).Sys.Stderr())
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
stderr := fsc.FdWriter(internalsys.FdStderr)
|
||||
traceTo(ctx, mod, stack, stderr)
|
||||
})
|
||||
|
||||
// traceTo implements the function "trace" in AssemblyScript. e.g.
|
||||
|
||||
@@ -86,11 +86,11 @@ var fdAllocate = stubFunction(
|
||||
// and https://linux.die.net/man/3/close
|
||||
var fdClose = newHostFunc(fdCloseName, fdCloseFn, []api.ValueType{i32}, "fd")
|
||||
|
||||
func fdCloseFn(ctx context.Context, mod api.Module, params []uint64) Errno {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
func fdCloseFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
fd := uint32(params[0])
|
||||
|
||||
if ok := sysCtx.FS(ctx).CloseFile(ctx, fd); !ok {
|
||||
if ok := fsc.CloseFile(fd); !ok {
|
||||
return ErrnoBadf
|
||||
}
|
||||
return ErrnoSuccess
|
||||
@@ -164,8 +164,8 @@ func fdFdstatGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
|
||||
}
|
||||
|
||||
// Otherwise, look up the file corresponding to the file descriptor.
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
file, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
file, ok := fsc.OpenedFile(fd)
|
||||
if !ok {
|
||||
return ErrnoBadf
|
||||
}
|
||||
@@ -326,8 +326,8 @@ func fdFilestatGetFunc(ctx context.Context, mod api.Module, fd, resultBuf uint32
|
||||
}
|
||||
|
||||
// Otherwise, look up the file corresponding to the file descriptor.
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
file, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
file, ok := fsc.OpenedFile(fd)
|
||||
if !ok {
|
||||
return ErrnoBadf
|
||||
}
|
||||
@@ -458,8 +458,8 @@ var fdPrestatGet = proxyResultParams(&wasm.HostFunc{
|
||||
Code: &wasm.Code{IsHostFunction: true, GoFunc: u64ResultParam(fdPrestatGetFn)},
|
||||
}, fdPrestatGetName)
|
||||
|
||||
func fdPrestatGetFn(ctx context.Context, mod api.Module, stack []uint64) (prestat uint64, errno Errno) {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
func fdPrestatGetFn(_ context.Context, mod api.Module, stack []uint64) (prestat uint64, errno Errno) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
fd := uint32(stack[0])
|
||||
|
||||
// Currently, we only pre-open the root file descriptor.
|
||||
@@ -467,7 +467,7 @@ func fdPrestatGetFn(ctx context.Context, mod api.Module, stack []uint64) (presta
|
||||
return 0, ErrnoBadf
|
||||
}
|
||||
|
||||
entry, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd)
|
||||
entry, ok := fsc.OpenedFile(fd)
|
||||
if !ok {
|
||||
return 0, ErrnoBadf
|
||||
}
|
||||
@@ -516,7 +516,7 @@ var fdPrestatDirName = newHostFunc(
|
||||
)
|
||||
|
||||
func fdPrestatDirNameFn(ctx context.Context, mod api.Module, params []uint64) Errno {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
fd, path, pathLen := uint32(params[0]), uint32(params[1]), uint32(params[2])
|
||||
|
||||
// Currently, we only pre-open the root file descriptor.
|
||||
@@ -524,7 +524,7 @@ func fdPrestatDirNameFn(ctx context.Context, mod api.Module, params []uint64) Er
|
||||
return ErrnoBadf
|
||||
}
|
||||
|
||||
f, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd)
|
||||
f, ok := fsc.OpenedFile(fd)
|
||||
if !ok {
|
||||
return ErrnoBadf
|
||||
}
|
||||
@@ -614,7 +614,7 @@ func fdReadFn(ctx context.Context, mod api.Module, stack []uint64) (nread uint32
|
||||
|
||||
func fdReadOrPread(ctx context.Context, mod api.Module, stack []uint64, isPread bool) (uint32, Errno) {
|
||||
mem := mod.Memory()
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fd := uint32(stack[0])
|
||||
iovs := uint32(stack[1])
|
||||
@@ -625,7 +625,7 @@ func fdReadOrPread(ctx context.Context, mod api.Module, stack []uint64, isPread
|
||||
offset = int64(stack[3])
|
||||
}
|
||||
|
||||
r := internalsys.FdReader(ctx, sysCtx, fd)
|
||||
r := fsc.FdReader(fd)
|
||||
if r == nil {
|
||||
return 0, ErrnoBadf
|
||||
}
|
||||
@@ -701,7 +701,7 @@ var fdReaddir = proxyResultParams(&wasm.HostFunc{
|
||||
|
||||
func fdReaddirFn(ctx context.Context, mod api.Module, stack []uint64) (uint32, Errno) {
|
||||
mem := mod.Memory()
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(ctx)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fd := uint32(stack[0])
|
||||
buf := uint32(stack[1])
|
||||
@@ -940,7 +940,7 @@ func writeDirent(buf []byte, dNext uint64, dNamlen uint32, dType bool) {
|
||||
|
||||
// openedDir returns the directory and ErrnoSuccess if the fd points to a readable directory.
|
||||
func openedDir(ctx context.Context, fsc *internalsys.FSContext, fd uint32) (fs.ReadDirFile, *internalsys.ReadDir, Errno) {
|
||||
if f, ok := fsc.OpenedFile(ctx, fd); !ok {
|
||||
if f, ok := fsc.OpenedFile(fd); !ok {
|
||||
return nil, nil, ErrnoBadf
|
||||
} else if d, ok := f.File.(fs.ReadDirFile); !ok {
|
||||
// fd_readdir docs don't indicate whether to return ErrnoNotdir or
|
||||
@@ -1011,7 +1011,7 @@ var fdSeek = proxyResultParams(&wasm.HostFunc{
|
||||
}, fdSeekName)
|
||||
|
||||
func fdSeekFn(ctx context.Context, mod api.Module, stack []uint64) (int64, Errno) {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
fd := uint32(stack[0])
|
||||
offset := stack[1]
|
||||
whence := uint32(stack[2])
|
||||
@@ -1022,7 +1022,7 @@ func fdSeekFn(ctx context.Context, mod api.Module, stack []uint64) (int64, Errno
|
||||
|
||||
var seeker io.Seeker
|
||||
// Check to see if the file descriptor is available
|
||||
if f, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd); !ok {
|
||||
if f, ok := fsc.OpenedFile(fd); !ok {
|
||||
return 0, ErrnoBadf
|
||||
// fs.FS doesn't declare io.Seeker, but implementations such as os.File implement it.
|
||||
} else if seeker, ok = f.File.(io.Seeker); !ok {
|
||||
@@ -1122,13 +1122,13 @@ var fdWrite = proxyResultParams(&wasm.HostFunc{
|
||||
|
||||
func fdWriteFn(ctx context.Context, mod api.Module, stack []uint64) (uint32, Errno) {
|
||||
mem := mod.Memory()
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fd := uint32(stack[0])
|
||||
iovs := uint32(stack[1])
|
||||
iovsCount := uint32(stack[2])
|
||||
|
||||
writer := internalsys.FdWriter(ctx, sysCtx, fd)
|
||||
writer := fsc.FdWriter(fd)
|
||||
if writer == nil {
|
||||
return 0, ErrnoBadf
|
||||
}
|
||||
@@ -1210,8 +1210,7 @@ var pathFilestatGet = newHostFunc(
|
||||
// pathFilestatGetFn cannot currently use proxyResultParams because filestat is
|
||||
// larger than api.ValueTypeI64 (i64 == 8 bytes, but filestat is 64).
|
||||
func pathFilestatGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
fsc := sysCtx.FS(ctx)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
dirfd := uint32(params[0])
|
||||
|
||||
@@ -1233,7 +1232,7 @@ func pathFilestatGetFn(ctx context.Context, mod api.Module, params []uint64) Err
|
||||
pathName := string(b)
|
||||
|
||||
// Prepend the path if necessary.
|
||||
if dir, ok := fsc.OpenedFile(ctx, dirfd); !ok {
|
||||
if dir, ok := fsc.OpenedFile(dirfd); !ok {
|
||||
return ErrnoBadf
|
||||
} else if _, ok := dir.File.(fs.ReadDirFile); !ok {
|
||||
return ErrnoNotdir // TODO: cache filetype instead of poking.
|
||||
@@ -1243,7 +1242,7 @@ func pathFilestatGetFn(ctx context.Context, mod api.Module, params []uint64) Err
|
||||
}
|
||||
|
||||
// Stat the file without allocating a file descriptor
|
||||
stat, errnoResult := statFile(ctx, fsc, pathName)
|
||||
stat, errnoResult := statFile(fsc, pathName)
|
||||
if errnoResult != ErrnoSuccess {
|
||||
return errnoResult
|
||||
}
|
||||
@@ -1356,8 +1355,7 @@ const (
|
||||
)
|
||||
|
||||
func pathOpenFn(ctx context.Context, mod api.Module, params []uint64) (uint32, Errno) {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
fsc := sysCtx.FS(ctx)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
dirfd := uint32(params[0])
|
||||
|
||||
@@ -1384,7 +1382,7 @@ func pathOpenFn(ctx context.Context, mod api.Module, params []uint64) (uint32, E
|
||||
// here in any way except assuming it is "/".
|
||||
//
|
||||
// See https://github.com/WebAssembly/wasi-libc/blob/659ff414560721b1660a19685110e484a081c3d4/libc-bottom-half/sources/at_fdcwd.c#L24-L26
|
||||
if _, ok := fsc.OpenedFile(ctx, dirfd); !ok {
|
||||
if _, ok := fsc.OpenedFile(dirfd); !ok {
|
||||
return 0, ErrnoBadf
|
||||
}
|
||||
|
||||
@@ -1399,25 +1397,25 @@ func pathOpenFn(ctx context.Context, mod api.Module, params []uint64) (uint32, E
|
||||
// path="bar", this should open "/tmp/foo/bar" not "/bar".
|
||||
//
|
||||
// See https://linux.die.net/man/2/openat
|
||||
newFD, errnoResult := openFile(ctx, fsc, string(b))
|
||||
newFD, errnoResult := openFile(fsc, string(b))
|
||||
if errnoResult != ErrnoSuccess {
|
||||
return 0, errnoResult
|
||||
}
|
||||
|
||||
// Check any flags that require the file to evaluate.
|
||||
if oflags&wasiOflagsDirectory != 0 {
|
||||
return newFD, failIfNotDirectory(ctx, fsc, newFD)
|
||||
return newFD, failIfNotDirectory(fsc, newFD)
|
||||
}
|
||||
|
||||
return newFD, ErrnoSuccess
|
||||
}
|
||||
|
||||
func failIfNotDirectory(ctx context.Context, fsc *internalsys.FSContext, fd uint32) Errno {
|
||||
func failIfNotDirectory(fsc *internalsys.FSContext, fd uint32) Errno {
|
||||
// Lookup the previous file
|
||||
if f, ok := fsc.OpenedFile(ctx, fd); !ok {
|
||||
if f, ok := fsc.OpenedFile(fd); !ok {
|
||||
return ErrnoBadf
|
||||
} else if _, ok := f.File.(fs.ReadDirFile); !ok {
|
||||
_ = fsc.CloseFile(ctx, fd)
|
||||
_ = fsc.CloseFile(fd)
|
||||
return ErrnoNotdir
|
||||
}
|
||||
return ErrnoSuccess
|
||||
@@ -1473,8 +1471,8 @@ var pathUnlinkFile = stubFunction(
|
||||
|
||||
// openFile attempts to open the file at the given path. Errors coerce to WASI
|
||||
// Errno.
|
||||
func openFile(ctx context.Context, fsc *internalsys.FSContext, name string) (fd uint32, errno Errno) {
|
||||
newFD, err := fsc.OpenFile(ctx, name)
|
||||
func openFile(fsc *internalsys.FSContext, name string) (fd uint32, errno Errno) {
|
||||
newFD, err := fsc.OpenFile(name)
|
||||
if err == nil {
|
||||
fd = newFD
|
||||
errno = ErrnoSuccess
|
||||
@@ -1486,8 +1484,8 @@ func openFile(ctx context.Context, fsc *internalsys.FSContext, name string) (fd
|
||||
|
||||
// statFile attempts to stat the file at the given path. Errors coerce to WASI
|
||||
// Errno.
|
||||
func statFile(ctx context.Context, fsc *internalsys.FSContext, name string) (stat fs.FileInfo, errno Errno) {
|
||||
s, err := fsc.StatFile(ctx, name)
|
||||
func statFile(fsc *internalsys.FSContext, name string) (stat fs.FileInfo, errno Errno) {
|
||||
s, err := fsc.StatFile(name)
|
||||
if err == nil {
|
||||
stat = s
|
||||
errno = ErrnoSuccess
|
||||
|
||||
@@ -51,12 +51,12 @@ func Test_fdClose(t *testing.T) {
|
||||
defer r.Close(testCtx)
|
||||
|
||||
// open both paths without using WASI
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fdToClose, err := fsc.OpenFile(testCtx, path1)
|
||||
fdToClose, err := fsc.OpenFile(path1)
|
||||
require.NoError(t, err)
|
||||
|
||||
fdToKeep, err := fsc.OpenFile(testCtx, path2)
|
||||
fdToKeep, err := fsc.OpenFile(path2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Close
|
||||
@@ -69,11 +69,11 @@ func Test_fdClose(t *testing.T) {
|
||||
`, "\n"+log.String())
|
||||
|
||||
// Verify fdToClose is closed and removed from the opened FDs.
|
||||
_, ok := fsc.OpenedFile(testCtx, fdToClose)
|
||||
_, ok := fsc.OpenedFile(fdToClose)
|
||||
require.False(t, ok)
|
||||
|
||||
// Verify fdToKeep is not closed
|
||||
_, ok = fsc.OpenedFile(testCtx, fdToKeep)
|
||||
_, ok = fsc.OpenedFile(fdToKeep)
|
||||
require.True(t, ok)
|
||||
|
||||
log.Reset()
|
||||
@@ -108,12 +108,12 @@ func Test_fdFdstatGet(t *testing.T) {
|
||||
memorySize := mod.Memory().Size(testCtx)
|
||||
|
||||
// open both paths without using WASI
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fileFd, err := fsc.OpenFile(testCtx, file)
|
||||
fileFd, err := fsc.OpenFile(file)
|
||||
require.NoError(t, err)
|
||||
|
||||
dirFd, err := fsc.OpenFile(testCtx, dir)
|
||||
dirFd, err := fsc.OpenFile(dir)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
@@ -297,12 +297,12 @@ func Test_fdFilestatGet(t *testing.T) {
|
||||
memorySize := mod.Memory().Size(testCtx)
|
||||
|
||||
// open both paths without using WASI
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fileFd, err := fsc.OpenFile(testCtx, file)
|
||||
fileFd, err := fsc.OpenFile(file)
|
||||
require.NoError(t, err)
|
||||
|
||||
dirFd, err := fsc.OpenFile(testCtx, dir)
|
||||
dirFd, err := fsc.OpenFile(dir)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
@@ -1242,9 +1242,9 @@ func Test_fdReaddir(t *testing.T) {
|
||||
mod, r, log := requireProxyModule(t, wazero.NewModuleConfig().WithFS(fdReadDirFs))
|
||||
defer r.Close(testCtx)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fd, err := fsc.OpenFile(testCtx, "dir")
|
||||
fd, err := fsc.OpenFile("dir")
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
@@ -1481,7 +1481,7 @@ func Test_fdReaddir(t *testing.T) {
|
||||
defer log.Reset()
|
||||
|
||||
// Assign the state we are testing
|
||||
file, ok := fsc.OpenedFile(testCtx, fd)
|
||||
file, ok := fsc.OpenedFile(fd)
|
||||
require.True(t, ok)
|
||||
dir := tc.dir()
|
||||
defer dir.File.Close()
|
||||
@@ -1521,12 +1521,12 @@ func Test_fdReaddir_Errors(t *testing.T) {
|
||||
defer r.Close(testCtx)
|
||||
memLen := mod.Memory().Size(testCtx)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
dirFD, err := fsc.OpenFile(testCtx, "dir")
|
||||
dirFD, err := fsc.OpenFile("dir")
|
||||
require.NoError(t, err)
|
||||
|
||||
fileFD, err := fsc.OpenFile(testCtx, "notdir")
|
||||
fileFD, err := fsc.OpenFile("notdir")
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
@@ -1685,7 +1685,7 @@ func Test_fdReaddir_Errors(t *testing.T) {
|
||||
defer log.Reset()
|
||||
|
||||
// Reset the directory so that tests don't taint each other.
|
||||
if file, ok := fsc.OpenedFile(testCtx, tc.fd); ok && tc.fd == dirFD {
|
||||
if file, ok := fsc.OpenedFile(tc.fd); ok && tc.fd == dirFD {
|
||||
dir, err := fdReadDirFs.Open("dir")
|
||||
require.NoError(t, err)
|
||||
defer dir.Close()
|
||||
@@ -2016,8 +2016,8 @@ func Test_fdSeek(t *testing.T) {
|
||||
maskMemory(t, testCtx, mod, len(tc.expectedMemory))
|
||||
|
||||
// Since we initialized this file, we know it is a seeker (because it is a MapFile)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
|
||||
f, ok := fsc.OpenedFile(testCtx, fd)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
f, ok := fsc.OpenedFile(fd)
|
||||
require.True(t, ok)
|
||||
seeker := f.File.(io.Seeker)
|
||||
|
||||
@@ -2375,14 +2375,14 @@ func Test_pathFilestatGet(t *testing.T) {
|
||||
memorySize := mod.Memory().Size(testCtx)
|
||||
|
||||
// open both paths without using WASI
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
rootFd := uint32(3) // after stderr
|
||||
|
||||
fileFd, err := fsc.OpenFile(testCtx, file)
|
||||
fileFd, err := fsc.OpenFile(file)
|
||||
require.NoError(t, err)
|
||||
|
||||
dirFd, err := fsc.OpenFile(testCtx, dir)
|
||||
dirFd, err := fsc.OpenFile(dir)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
@@ -2649,8 +2649,8 @@ func Test_pathOpen(t *testing.T) {
|
||||
require.Equal(t, expectedMemory, actual)
|
||||
|
||||
// verify the file was actually opened
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
|
||||
f, ok := fsc.OpenedFile(testCtx, expectedFD)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
f, ok := fsc.OpenedFile(expectedFD)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, pathName, f.Name)
|
||||
}
|
||||
@@ -2860,8 +2860,8 @@ func requireOpenFile(t *testing.T, pathName string, data []byte) (api.Module, ui
|
||||
}
|
||||
testFS := fstest.MapFS{pathName[1:]: mapFile} // strip the leading slash
|
||||
mod, r, log := requireProxyModule(t, wazero.NewModuleConfig().WithFS(testFS))
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
|
||||
fd, err := fsc.OpenFile(testCtx, pathName)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
fd, err := fsc.OpenFile(pathName)
|
||||
require.NoError(t, err)
|
||||
return mod, fd, log, r
|
||||
}
|
||||
@@ -2870,12 +2870,12 @@ func requireOpenFile(t *testing.T, pathName string, data []byte) (api.Module, ui
|
||||
func requireOpenWritableFile(t *testing.T, tmpDir string, pathName string) (api.Module, uint32, *bytes.Buffer, api.Closer) {
|
||||
writeable, testFS := createWriteableFile(t, tmpDir, pathName, []byte{})
|
||||
mod, r, log := requireProxyModule(t, wazero.NewModuleConfig().WithFS(testFS))
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
|
||||
fd, err := fsc.OpenFile(testCtx, pathName)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
fd, err := fsc.OpenFile(pathName)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Swap the read-only file with a writeable one until #390
|
||||
f, ok := fsc.OpenedFile(testCtx, fd)
|
||||
f, ok := fsc.OpenedFile(fd)
|
||||
require.True(t, ok)
|
||||
f.File.Close()
|
||||
f.File = writeable
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
internalsys "github.com/tetratelabs/wazero/internal/sys"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
|
||||
@@ -133,16 +132,16 @@ func processClockEvent(ctx context.Context, mod api.Module, inBuf []byte) Errno
|
||||
|
||||
// processFDEvent returns a validation error or ErrnoNotsup as file or socket
|
||||
// subscriptions are not yet supported.
|
||||
func processFDEvent(ctx context.Context, mod api.Module, eventType byte, inBuf []byte) Errno {
|
||||
func processFDEvent(_ context.Context, mod api.Module, eventType byte, inBuf []byte) Errno {
|
||||
fd := le.Uint32(inBuf)
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
// Choose the best error, which falls back to unsupported, until we support
|
||||
// files.
|
||||
errno := ErrnoNotsup
|
||||
if eventType == eventTypeFdRead && internalsys.FdReader(ctx, sysCtx, fd) == nil {
|
||||
if eventType == eventTypeFdRead && fsc.FdReader(fd) == nil {
|
||||
errno = ErrnoBadf
|
||||
} else if eventType == eventTypeFdWrite && internalsys.FdWriter(ctx, sysCtx, fd) == nil {
|
||||
} else if eventType == eventTypeFdWrite && fsc.FdWriter(fd) == nil {
|
||||
errno = ErrnoBadf
|
||||
}
|
||||
|
||||
|
||||
@@ -171,16 +171,16 @@ func Benchmark_fdReaddir(b *testing.B) {
|
||||
fn := mod.ExportedFunction(fdReaddirName)
|
||||
|
||||
// Open the root directory as a file-descriptor.
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
|
||||
fd, err := fsc.OpenFile(testCtx, ".")
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
fd, err := fsc.OpenFile(".")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
f, ok := fsc.OpenedFile(testCtx, fd)
|
||||
f, ok := fsc.OpenedFile(fd)
|
||||
if !ok {
|
||||
b.Fatal("couldn't open fd ", fd)
|
||||
}
|
||||
defer fsc.CloseFile(testCtx, fd)
|
||||
defer fsc.CloseFile(fd)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
@@ -277,12 +277,12 @@ func Benchmark_pathFilestat(b *testing.B) {
|
||||
// under a pre-determined directory: zig
|
||||
fd := sys.FdRoot
|
||||
if bc.fd != sys.FdRoot {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
|
||||
fd, err = fsc.OpenFile(testCtx, "zig")
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
fd, err = fsc.OpenFile("zig")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer fsc.CloseFile(testCtx, fd)
|
||||
defer fsc.CloseFile(fd)
|
||||
}
|
||||
|
||||
fn := mod.ExportedFunction(pathFilestatGetName)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
internalsys "github.com/tetratelabs/wazero/internal/sys"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
|
||||
@@ -91,7 +92,7 @@ func (*jsfsOpen) invoke(ctx context.Context, mod api.Module, args ...interface{}
|
||||
perm := toUint32(args[2])
|
||||
callback := args[3].(funcWrapper)
|
||||
|
||||
fd, err := syscallOpen(ctx, mod, name, flags, perm)
|
||||
fd, err := syscallOpen(mod, name, flags, perm)
|
||||
return callback.invoke(ctx, mod, refJsfs, err, fd) // note: error first
|
||||
}
|
||||
|
||||
@@ -105,18 +106,18 @@ func (*jsfsStat) invoke(ctx context.Context, mod api.Module, args ...interface{}
|
||||
name := args[0].(string)
|
||||
callback := args[1].(funcWrapper)
|
||||
|
||||
stat, err := syscallStat(ctx, mod, name)
|
||||
stat, err := syscallStat(mod, name)
|
||||
return callback.invoke(ctx, mod, refJsfs, err, stat) // note: error first
|
||||
}
|
||||
|
||||
// syscallStat is like syscall.Stat
|
||||
func syscallStat(ctx context.Context, mod api.Module, name string) (*jsSt, error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(ctx)
|
||||
if fd, err := fsc.OpenFile(ctx, name); err != nil {
|
||||
func syscallStat(mod api.Module, name string) (*jsSt, error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
if fd, err := fsc.OpenFile(name); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
defer fsc.CloseFile(ctx, fd)
|
||||
return syscallFstat(ctx, mod, fd)
|
||||
defer fsc.CloseFile(fd)
|
||||
return syscallFstat(fsc, fd)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,17 +128,18 @@ type jsfsFstat struct{}
|
||||
|
||||
// invoke implements jsFn.invoke
|
||||
func (*jsfsFstat) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fd := toUint32(args[0])
|
||||
callback := args[1].(funcWrapper)
|
||||
|
||||
fstat, err := syscallFstat(ctx, mod, fd)
|
||||
fstat, err := syscallFstat(fsc, fd)
|
||||
return callback.invoke(ctx, mod, refJsfs, err, fstat) // note: error first
|
||||
}
|
||||
|
||||
// syscallFstat is like syscall.Fstat
|
||||
func syscallFstat(ctx context.Context, mod api.Module, fd uint32) (*jsSt, error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(ctx)
|
||||
if f, ok := fsc.OpenedFile(ctx, fd); !ok {
|
||||
func syscallFstat(fsc *internalsys.FSContext, fd uint32) (*jsSt, error) {
|
||||
if f, ok := fsc.OpenedFile(fd); !ok {
|
||||
return nil, syscall.EBADF
|
||||
} else if stat, err := f.File.Stat(); err != nil {
|
||||
return nil, err
|
||||
@@ -159,17 +161,18 @@ type jsfsClose struct{}
|
||||
|
||||
// invoke implements jsFn.invoke
|
||||
func (*jsfsClose) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fd := toUint32(args[0])
|
||||
callback := args[1].(funcWrapper)
|
||||
|
||||
err := syscallClose(ctx, mod, fd)
|
||||
err := syscallClose(fsc, fd)
|
||||
return callback.invoke(ctx, mod, refJsfs, err, true) // note: error first
|
||||
}
|
||||
|
||||
// syscallClose is like syscall.Close
|
||||
func syscallClose(ctx context.Context, mod api.Module, fd uint32) (err error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(ctx)
|
||||
if ok := fsc.CloseFile(ctx, fd); !ok {
|
||||
func syscallClose(fsc *internalsys.FSContext, fd uint32) (err error) {
|
||||
if ok := fsc.CloseFile(fd); !ok {
|
||||
err = syscall.EBADF // already closed
|
||||
}
|
||||
return
|
||||
@@ -193,13 +196,15 @@ func (*jsfsRead) invoke(ctx context.Context, mod api.Module, args ...interface{}
|
||||
fOffset := args[4] // nil unless Pread
|
||||
callback := args[5].(funcWrapper)
|
||||
|
||||
n, err := syscallRead(ctx, mod, fd, fOffset, buf.slice[offset:offset+byteCount])
|
||||
n, err := syscallRead(mod, fd, fOffset, buf.slice[offset:offset+byteCount])
|
||||
return callback.invoke(ctx, mod, refJsfs, err, n) // note: error first
|
||||
}
|
||||
|
||||
// syscallRead is like syscall.Read
|
||||
func syscallRead(ctx context.Context, mod api.Module, fd uint32, offset interface{}, p []byte) (n uint32, err error) {
|
||||
r := fdReader(ctx, mod, fd)
|
||||
func syscallRead(mod api.Module, fd uint32, offset interface{}, p []byte) (n uint32, err error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
r := fsc.FdReader(fd)
|
||||
if r == nil {
|
||||
err = syscall.EBADF
|
||||
}
|
||||
@@ -244,15 +249,17 @@ func (*jsfsWrite) invoke(ctx context.Context, mod api.Module, args ...interface{
|
||||
callback := args[5].(funcWrapper)
|
||||
|
||||
if byteCount > 0 { // empty is possible on EOF
|
||||
n, err := syscallWrite(ctx, mod, fd, fOffset, buf.slice[offset:offset+byteCount])
|
||||
n, err := syscallWrite(mod, fd, fOffset, buf.slice[offset:offset+byteCount])
|
||||
return callback.invoke(ctx, mod, refJsfs, err, n) // note: error first
|
||||
}
|
||||
return callback.invoke(ctx, mod, refJsfs, nil, refValueZero)
|
||||
}
|
||||
|
||||
// syscallWrite is like syscall.Write
|
||||
func syscallWrite(ctx context.Context, mod api.Module, fd uint32, offset interface{}, p []byte) (n uint32, err error) {
|
||||
if writer := fdWriter(ctx, mod, fd); writer == nil {
|
||||
func syscallWrite(mod api.Module, fd uint32, offset interface{}, p []byte) (n uint32, err error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
if writer := fsc.FdWriter(fd); writer == nil {
|
||||
err = syscall.EBADF
|
||||
} else if nWritten, e := writer.Write(p); e == nil || e == io.EOF {
|
||||
// fs_js.go cannot parse io.EOF so coerce it to nil.
|
||||
@@ -279,15 +286,16 @@ func (*jsfsReaddir) invoke(ctx context.Context, mod api.Module, args ...interfac
|
||||
return callback.invoke(ctx, mod, refJsfs, err, stat) // note: error first
|
||||
}
|
||||
|
||||
func syscallReaddir(ctx context.Context, mod api.Module, name string) (*objectArray, error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(ctx)
|
||||
fd, err := fsc.OpenFile(ctx, name)
|
||||
func syscallReaddir(_ context.Context, mod api.Module, name string) (*objectArray, error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fd, err := fsc.OpenFile(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fsc.CloseFile(ctx, fd)
|
||||
defer fsc.CloseFile(fd)
|
||||
|
||||
if f, ok := fsc.OpenedFile(ctx, fd); !ok {
|
||||
if f, ok := fsc.OpenedFile(fd); !ok {
|
||||
return nil, syscall.EBADF
|
||||
} else if d, ok := f.File.(fs.ReadDirFile); !ok {
|
||||
return nil, syscall.ENOTDIR
|
||||
@@ -312,14 +320,14 @@ func (*returnZero) invoke(ctx context.Context, mod api.Module, args ...interface
|
||||
type returnSliceOfZero struct{}
|
||||
|
||||
// invoke implements jsFn.invoke
|
||||
func (*returnSliceOfZero) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
|
||||
func (*returnSliceOfZero) invoke(context.Context, api.Module, ...interface{}) (interface{}, error) {
|
||||
return &objectArray{slice: []interface{}{refValueZero}}, nil
|
||||
}
|
||||
|
||||
type returnArg0 struct{}
|
||||
|
||||
// invoke implements jsFn.invoke
|
||||
func (*returnArg0) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
|
||||
func (*returnArg0) invoke(_ context.Context, _ api.Module, args ...interface{}) (interface{}, error) {
|
||||
return args[0], nil
|
||||
}
|
||||
|
||||
@@ -327,7 +335,7 @@ func (*returnArg0) invoke(ctx context.Context, mod api.Module, args ...interface
|
||||
type cwd struct{}
|
||||
|
||||
// invoke implements jsFn.invoke
|
||||
func (*cwd) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
|
||||
func (*cwd) invoke(ctx context.Context, _ api.Module, _ ...interface{}) (interface{}, error) {
|
||||
return getState(ctx).cwd, nil
|
||||
}
|
||||
|
||||
@@ -336,19 +344,20 @@ type chdir struct{}
|
||||
|
||||
// invoke implements jsFn.invoke
|
||||
func (*chdir) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
path := args[0].(string)
|
||||
|
||||
// TODO: refactor so that sys has path-based ops, also needed in WASI.
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(ctx)
|
||||
if fd, err := fsc.OpenFile(ctx, path); err != nil {
|
||||
if fd, err := fsc.OpenFile(path); err != nil {
|
||||
return nil, syscall.ENOENT
|
||||
} else if f, ok := fsc.OpenedFile(ctx, fd); !ok {
|
||||
} else if f, ok := fsc.OpenedFile(fd); !ok {
|
||||
return nil, syscall.ENOENT
|
||||
} else if s, err := f.File.Stat(); err != nil {
|
||||
fsc.CloseFile(ctx, fd)
|
||||
fsc.CloseFile(fd)
|
||||
return nil, syscall.ENOENT
|
||||
} else if !s.IsDir() {
|
||||
fsc.CloseFile(ctx, fd)
|
||||
fsc.CloseFile(fd)
|
||||
return nil, syscall.ENOTDIR
|
||||
} else {
|
||||
getState(ctx).cwd = path
|
||||
|
||||
@@ -3,7 +3,6 @@ package gojs
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/spfunc"
|
||||
@@ -60,17 +59,12 @@ var WasmWrite = spfunc.MustCallFromSP(false, &wasm.HostFunc{
|
||||
})
|
||||
|
||||
func wasmWrite(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fd, p, n := uint32(stack[0]), uint32(stack[1]), uint32(stack[2])
|
||||
|
||||
var writer io.Writer
|
||||
|
||||
switch fd {
|
||||
case 1:
|
||||
writer = mod.(*wasm.CallContext).Sys.Stdout()
|
||||
case 2:
|
||||
writer = mod.(*wasm.CallContext).Sys.Stderr()
|
||||
default:
|
||||
// Keep things simple by expecting nothing past 2
|
||||
writer := fsc.FdWriter(fd)
|
||||
if writer == nil {
|
||||
panic(fmt.Errorf("unexpected fd %d", fd))
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"syscall"
|
||||
@@ -565,49 +564,9 @@ func mapJSError(err error) *syscallErr {
|
||||
}
|
||||
|
||||
// syscallOpen is like syscall.Open
|
||||
func syscallOpen(ctx context.Context, mod api.Module, name string, flags, perm uint32) (uint32, error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS(ctx)
|
||||
return fsc.OpenFile(ctx, name)
|
||||
}
|
||||
|
||||
const (
|
||||
fdStdin = iota
|
||||
fdStdout
|
||||
fdStderr
|
||||
)
|
||||
|
||||
// fdReader returns a valid reader for the given file descriptor or nil if ErrnoBadf.
|
||||
func fdReader(ctx context.Context, mod api.Module, fd uint32) io.Reader {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
if fd == fdStdin {
|
||||
return sysCtx.Stdin()
|
||||
} else if f, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd); !ok {
|
||||
return nil
|
||||
} else {
|
||||
return f.File
|
||||
}
|
||||
}
|
||||
|
||||
// fdWriter returns a valid writer for the given file descriptor or nil if ErrnoBadf.
|
||||
func fdWriter(ctx context.Context, mod api.Module, fd uint32) io.Writer {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
switch fd {
|
||||
case fdStdout:
|
||||
return sysCtx.Stdout()
|
||||
case fdStderr:
|
||||
return sysCtx.Stderr()
|
||||
default:
|
||||
// Check to see if the file descriptor is available
|
||||
if f, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd); !ok || f.File == nil {
|
||||
return nil
|
||||
// fs.FS doesn't declare io.Writer, but implementations such as
|
||||
// os.File implement it.
|
||||
} else if writer, ok := f.File.(io.Writer); !ok {
|
||||
return nil
|
||||
} else {
|
||||
return writer
|
||||
}
|
||||
}
|
||||
func syscallOpen(mod api.Module, name string, flags, perm uint32) (uint32, error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
return fsc.OpenFile(name)
|
||||
}
|
||||
|
||||
// funcWrapper is the result of go's js.FuncOf ("_makeFuncWrapper" here).
|
||||
|
||||
@@ -31,11 +31,6 @@ const (
|
||||
FdRoot
|
||||
)
|
||||
|
||||
// FSKey is a context.Context Value key. It allows overriding fs.FS for WASI.
|
||||
//
|
||||
// See https://github.com/tetratelabs/wazero/issues/491
|
||||
type FSKey struct{}
|
||||
|
||||
// EmptyFS is exported to special-case an empty file system.
|
||||
var EmptyFS = &emptyFS{}
|
||||
|
||||
@@ -104,6 +99,9 @@ type FSContext struct {
|
||||
// fs is the root ("/") mount.
|
||||
fs fs.FS
|
||||
|
||||
stdin io.Reader
|
||||
stdout, stderr io.Writer
|
||||
|
||||
// openedFiles is a map of file descriptor numbers (>=FdRoot) to open files
|
||||
// (or directories) and defaults to empty.
|
||||
// TODO: This is unguarded, so not goroutine-safe!
|
||||
@@ -113,15 +111,6 @@ type FSContext struct {
|
||||
lastFD uint32
|
||||
}
|
||||
|
||||
// emptyFSContext is the context associated with EmptyFS.
|
||||
//
|
||||
// Note: This is not mutable as operations functions do not affect field state.
|
||||
var emptyFSContext = &FSContext{
|
||||
fs: EmptyFS,
|
||||
openedFiles: map[uint32]*FileEntry{},
|
||||
lastFD: 2,
|
||||
}
|
||||
|
||||
var errNotDir = errors.New("not a directory")
|
||||
|
||||
// NewFSContext creates a FSContext, using the `root` parameter for any paths
|
||||
@@ -129,10 +118,30 @@ var errNotDir = errors.New("not a directory")
|
||||
// Otherwise, `root` is assigned file descriptor FdRoot and the returned
|
||||
// context can open files in that file system. Any error on opening "." is
|
||||
// returned.
|
||||
func NewFSContext(root fs.FS) (fsc *FSContext, err error) {
|
||||
func NewFSContext(stdin io.Reader, stdout, stderr io.Writer, root fs.FS) (fsc *FSContext, err error) {
|
||||
if stdin == nil {
|
||||
stdin = eofReader{}
|
||||
}
|
||||
|
||||
if stdout == nil {
|
||||
stdout = io.Discard
|
||||
}
|
||||
|
||||
if stderr == nil {
|
||||
stderr = io.Discard
|
||||
}
|
||||
|
||||
fsc = &FSContext{
|
||||
stdin: stdin,
|
||||
stdout: stdout,
|
||||
stderr: stderr,
|
||||
fs: root,
|
||||
openedFiles: map[uint32]*FileEntry{},
|
||||
lastFD: FdStderr,
|
||||
}
|
||||
|
||||
if root == EmptyFS {
|
||||
fsc = emptyFSContext
|
||||
return
|
||||
return fsc, nil
|
||||
}
|
||||
|
||||
// Open the root directory by using "." as "/" is not relevant in fs.FS.
|
||||
@@ -158,13 +167,10 @@ func NewFSContext(root fs.FS) (fsc *FSContext, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
return &FSContext{
|
||||
fs: root,
|
||||
openedFiles: map[uint32]*FileEntry{
|
||||
FdRoot: {Name: "/", File: rootDir},
|
||||
},
|
||||
lastFD: FdRoot,
|
||||
}, nil
|
||||
fsc.openedFiles[FdRoot] = &FileEntry{Name: "/", File: rootDir}
|
||||
fsc.lastFD = FdRoot
|
||||
|
||||
return fsc, nil
|
||||
}
|
||||
|
||||
// nextFD gets the next file descriptor number in a goroutine safe way (monotonically) or zero if we ran out.
|
||||
@@ -178,7 +184,7 @@ func (c *FSContext) nextFD() uint32 {
|
||||
}
|
||||
|
||||
// OpenedFile returns a file and true if it was opened or nil and false, if syscall.EBADF.
|
||||
func (c *FSContext) OpenedFile(_ context.Context, fd uint32) (*FileEntry, bool) {
|
||||
func (c *FSContext) OpenedFile(fd uint32) (*FileEntry, bool) {
|
||||
f, ok := c.openedFiles[fd]
|
||||
return f, ok
|
||||
}
|
||||
@@ -188,7 +194,7 @@ func (c *FSContext) OpenedFile(_ context.Context, fd uint32) (*FileEntry, bool)
|
||||
// TODO: Consider dirflags and oflags. Also, allow non-read-only open based on config about the mount.
|
||||
// e.g. allow os.O_RDONLY, os.O_WRONLY, or os.O_RDWR either by config flag or pattern on filename
|
||||
// See #390
|
||||
func (c *FSContext) OpenFile(_ context.Context, name string /* TODO: flags int, perm int */) (uint32, error) {
|
||||
func (c *FSContext) OpenFile(name string /* TODO: flags int, perm int */) (uint32, error) {
|
||||
f, err := c.openFile(name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -203,7 +209,7 @@ func (c *FSContext) OpenFile(_ context.Context, name string /* TODO: flags int,
|
||||
return newFD, nil
|
||||
}
|
||||
|
||||
func (c *FSContext) StatFile(_ context.Context, name string) (fs.FileInfo, error) {
|
||||
func (c *FSContext) StatFile(name string) (fs.FileInfo, error) {
|
||||
f, err := c.openFile(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -223,8 +229,43 @@ func (c *FSContext) openFile(name string) (fs.File, error) {
|
||||
return c.fs.Open(fsOpenPath)
|
||||
}
|
||||
|
||||
// FdWriter returns a valid writer for the given file descriptor or nil if syscall.EBADF.
|
||||
func (c *FSContext) FdWriter(fd uint32) io.Writer {
|
||||
switch fd {
|
||||
case FdStdout:
|
||||
return c.stdout
|
||||
case FdStderr:
|
||||
return c.stderr
|
||||
case FdRoot:
|
||||
return nil // directory, not a writeable file.
|
||||
default:
|
||||
// Check to see if the file descriptor is available
|
||||
if f, ok := c.openedFiles[fd]; !ok {
|
||||
return nil
|
||||
} else if writer, ok := f.File.(io.Writer); !ok {
|
||||
// Go's syscall.Write also returns EBADF if the FD is present, but not writeable
|
||||
return nil
|
||||
} else {
|
||||
return writer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FdReader returns a valid reader for the given file descriptor or nil if syscall.EBADF.
|
||||
func (c *FSContext) FdReader(fd uint32) io.Reader {
|
||||
if fd == FdStdin {
|
||||
return c.stdin
|
||||
} else if fd == FdRoot {
|
||||
return nil // directory, not a readable file.
|
||||
} else if f, ok := c.openedFiles[fd]; !ok {
|
||||
return nil
|
||||
} else {
|
||||
return f.File
|
||||
}
|
||||
}
|
||||
|
||||
// CloseFile returns true if a file was opened and closed without error, or false if syscall.EBADF.
|
||||
func (c *FSContext) CloseFile(_ context.Context, fd uint32) bool {
|
||||
func (c *FSContext) CloseFile(fd uint32) bool {
|
||||
f, ok := c.openedFiles[fd]
|
||||
if !ok {
|
||||
return false
|
||||
@@ -237,7 +278,7 @@ func (c *FSContext) CloseFile(_ context.Context, fd uint32) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Close implements io.Closer
|
||||
// Close implements api.Closer
|
||||
func (c *FSContext) Close(context.Context) (err error) {
|
||||
// Close any files opened in this context
|
||||
for fd, entry := range c.openedFiles {
|
||||
@@ -248,38 +289,3 @@ func (c *FSContext) Close(context.Context) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// FdWriter returns a valid writer for the given file descriptor or nil if syscall.EBADF.
|
||||
func FdWriter(ctx context.Context, sysCtx *Context, fd uint32) io.Writer {
|
||||
switch fd {
|
||||
case FdStdout:
|
||||
return sysCtx.Stdout()
|
||||
case FdStderr:
|
||||
return sysCtx.Stderr()
|
||||
case FdRoot:
|
||||
return nil // directory, not a writeable file.
|
||||
default:
|
||||
// Check to see if the file descriptor is available
|
||||
if f, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd); !ok {
|
||||
return nil
|
||||
} else if writer, ok := f.File.(io.Writer); !ok {
|
||||
// Go's syscall.Write also returns EBADF if the FD is present, but not writeable
|
||||
return nil
|
||||
} else {
|
||||
return writer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FdReader returns a valid reader for the given file descriptor or nil if syscall.EBADF.
|
||||
func FdReader(ctx context.Context, sysCtx *Context, fd uint32) io.Reader {
|
||||
if fd == FdStdin {
|
||||
return sysCtx.Stdin()
|
||||
} else if fd == FdRoot {
|
||||
return nil // directory, not a readable file.
|
||||
} else if f, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd); !ok {
|
||||
return nil
|
||||
} else {
|
||||
return f.File
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func TestNewFSContext(t *testing.T) {
|
||||
tc := tt
|
||||
|
||||
t.Run(tc.name, func(b *testing.T) {
|
||||
fsc, err := NewFSContext(tc.fs)
|
||||
fsc, err := NewFSContext(nil, nil, nil, tc.fs)
|
||||
require.NoError(t, err)
|
||||
defer fsc.Close(testCtx)
|
||||
|
||||
@@ -84,15 +84,20 @@ func TestEmptyFS(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEmptyFSContext(t *testing.T) {
|
||||
testFS := emptyFSContext
|
||||
testFS, err := NewFSContext(nil, nil, nil, EmptyFS)
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := &FSContext{
|
||||
stdin: eofReader{},
|
||||
stdout: io.Discard,
|
||||
stderr: io.Discard,
|
||||
fs: EmptyFS,
|
||||
openedFiles: map[uint32]*FileEntry{},
|
||||
lastFD: 2,
|
||||
}
|
||||
|
||||
t.Run("OpenFile doesn't affect state", func(t *testing.T) {
|
||||
fd, err := testFS.OpenFile(testCtx, "foo.txt")
|
||||
fd, err := testFS.OpenFile("foo.txt")
|
||||
require.Zero(t, fd)
|
||||
require.EqualError(t, err, "open foo.txt: file does not exist")
|
||||
|
||||
@@ -113,7 +118,7 @@ func TestContext_File(t *testing.T) {
|
||||
embedFS, err := fs.Sub(testdata, "testdata")
|
||||
require.NoError(t, err)
|
||||
|
||||
fsc, err := NewFSContext(embedFS)
|
||||
fsc, err := NewFSContext(nil, nil, nil, embedFS)
|
||||
require.NoError(t, err)
|
||||
defer fsc.Close(testCtx)
|
||||
|
||||
@@ -142,11 +147,11 @@ func TestContext_File(t *testing.T) {
|
||||
tc := tt
|
||||
|
||||
t.Run(tc.name, func(b *testing.T) {
|
||||
fd, err := fsc.OpenFile(testCtx, tc.name)
|
||||
fd, err := fsc.OpenFile(tc.name)
|
||||
require.NoError(t, err)
|
||||
defer fsc.CloseFile(testCtx, fd)
|
||||
defer fsc.CloseFile(fd)
|
||||
|
||||
f, ok := fsc.OpenedFile(testCtx, fd)
|
||||
f, ok := fsc.OpenedFile(fd)
|
||||
require.True(t, ok)
|
||||
|
||||
stat, err := f.File.Stat()
|
||||
@@ -169,12 +174,12 @@ func TestContext_File(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestContext_Close(t *testing.T) {
|
||||
fsc, err := NewFSContext(testfs.FS{"foo": &testfs.File{}})
|
||||
fsc, err := NewFSContext(nil, nil, nil, testfs.FS{"foo": &testfs.File{}})
|
||||
require.NoError(t, err)
|
||||
// Verify base case
|
||||
require.Equal(t, 1, len(fsc.openedFiles))
|
||||
|
||||
_, err = fsc.OpenFile(testCtx, "foo")
|
||||
_, err = fsc.OpenFile("foo")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(fsc.openedFiles))
|
||||
|
||||
@@ -190,11 +195,11 @@ func TestContext_Close(t *testing.T) {
|
||||
|
||||
func TestContext_Close_Error(t *testing.T) {
|
||||
file := &testfs.File{CloseErr: errors.New("error closing")}
|
||||
fsc, err := NewFSContext(testfs.FS{"foo": file})
|
||||
fsc, err := NewFSContext(nil, nil, nil, testfs.FS{"foo": file})
|
||||
require.NoError(t, err)
|
||||
|
||||
// open another file
|
||||
_, err = fsc.OpenFile(testCtx, "foo")
|
||||
_, err = fsc.OpenFile("foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
require.EqualError(t, fsc.Close(testCtx), "error closing")
|
||||
|
||||
@@ -17,8 +17,6 @@ import (
|
||||
type Context struct {
|
||||
args, environ [][]byte
|
||||
argsSize, environSize uint32
|
||||
stdin io.Reader
|
||||
stdout, stderr io.Writer
|
||||
|
||||
// Note: Using function pointers here keeps them stable for tests.
|
||||
|
||||
@@ -65,24 +63,6 @@ func (c *Context) EnvironSize() uint32 {
|
||||
return c.environSize
|
||||
}
|
||||
|
||||
// Stdin is like exec.Cmd Stdin and defaults to a reader of os.DevNull.
|
||||
// See wazero.ModuleConfig WithStdin
|
||||
func (c *Context) Stdin() io.Reader {
|
||||
return c.stdin
|
||||
}
|
||||
|
||||
// Stdout is like exec.Cmd Stdout and defaults to io.Discard.
|
||||
// See wazero.ModuleConfig WithStdout
|
||||
func (c *Context) Stdout() io.Writer {
|
||||
return c.stdout
|
||||
}
|
||||
|
||||
// Stderr is like exec.Cmd Stderr and defaults to io.Discard.
|
||||
// See wazero.ModuleConfig WithStderr
|
||||
func (c *Context) Stderr() io.Writer {
|
||||
return c.stderr
|
||||
}
|
||||
|
||||
// Walltime implements sys.Walltime.
|
||||
func (c *Context) Walltime(ctx context.Context) (sec int64, nsec int32) {
|
||||
return (*(c.walltime))(ctx)
|
||||
@@ -108,12 +88,8 @@ func (c *Context) Nanosleep(ctx context.Context, ns int64) {
|
||||
(*(c.nanosleep))(ctx, ns)
|
||||
}
|
||||
|
||||
// FS returns a possibly nil file system context.
|
||||
func (c *Context) FS(ctx context.Context) *FSContext {
|
||||
// Override Context when it is passed via context
|
||||
if fsValue := ctx.Value(FSKey{}); fsValue != nil {
|
||||
return fsValue.(*FSContext)
|
||||
}
|
||||
// FS returns the possibly empty (EmptyFS) file system context.
|
||||
func (c *Context) FS() *FSContext {
|
||||
return c.fsc
|
||||
}
|
||||
|
||||
@@ -171,24 +147,6 @@ func NewContext(
|
||||
return nil, fmt.Errorf("environ invalid: %w", err)
|
||||
}
|
||||
|
||||
if stdin == nil {
|
||||
sysCtx.stdin = eofReader{}
|
||||
} else {
|
||||
sysCtx.stdin = stdin
|
||||
}
|
||||
|
||||
if stdout == nil {
|
||||
sysCtx.stdout = io.Discard
|
||||
} else {
|
||||
sysCtx.stdout = stdout
|
||||
}
|
||||
|
||||
if stderr == nil {
|
||||
sysCtx.stderr = io.Discard
|
||||
} else {
|
||||
sysCtx.stderr = stderr
|
||||
}
|
||||
|
||||
if randSource == nil {
|
||||
sysCtx.randSource = platform.NewFakeRandSource()
|
||||
} else {
|
||||
@@ -224,9 +182,9 @@ func NewContext(
|
||||
}
|
||||
|
||||
if fs != nil {
|
||||
sysCtx.fsc, err = NewFSContext(fs)
|
||||
sysCtx.fsc, err = NewFSContext(stdin, stdout, stderr, fs)
|
||||
} else {
|
||||
sysCtx.fsc, err = NewFSContext(EmptyFS)
|
||||
sysCtx.fsc, err = NewFSContext(stdin, stdout, stderr, EmptyFS)
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -16,16 +16,10 @@ import (
|
||||
func TestContext_FS(t *testing.T) {
|
||||
sysCtx := DefaultContext(testfs.FS{})
|
||||
|
||||
fsc1, err := NewFSContext(testfs.FS{})
|
||||
fsc, err := NewFSContext(nil, nil, nil, testfs.FS{})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, fsc1, sysCtx.FS(testCtx))
|
||||
|
||||
fsc2, err := NewFSContext(testfs.FS{"foo": &testfs.File{}})
|
||||
require.NoError(t, err)
|
||||
|
||||
// can override to something else
|
||||
require.Equal(t, fsc2, sysCtx.FS(context.WithValue(testCtx, FSKey{}, fsc2)))
|
||||
require.Equal(t, fsc, sysCtx.FS())
|
||||
}
|
||||
|
||||
func TestDefaultSysContext(t *testing.T) {
|
||||
@@ -48,9 +42,6 @@ func TestDefaultSysContext(t *testing.T) {
|
||||
require.Zero(t, sysCtx.ArgsSize())
|
||||
require.Nil(t, sysCtx.Environ())
|
||||
require.Zero(t, sysCtx.EnvironSize())
|
||||
require.Equal(t, eofReader{}, sysCtx.Stdin())
|
||||
require.Equal(t, io.Discard, sysCtx.Stdout())
|
||||
require.Equal(t, io.Discard, sysCtx.Stderr())
|
||||
// To compare functions, we can only compare pointers, but the pointer will
|
||||
// change. Hence, we have to compare the results instead.
|
||||
sec, _ := sysCtx.Walltime(testCtx)
|
||||
@@ -60,8 +51,12 @@ func TestDefaultSysContext(t *testing.T) {
|
||||
require.Equal(t, sys.ClockResolution(1), sysCtx.NanotimeResolution())
|
||||
require.Equal(t, &ns, sysCtx.nanosleep)
|
||||
require.Equal(t, platform.NewFakeRandSource(), sysCtx.RandSource())
|
||||
expectedFS, _ := NewFSContext(testfs.FS{})
|
||||
require.Equal(t, expectedFS, sysCtx.FS(testCtx))
|
||||
|
||||
expectedFS, _ := NewFSContext(nil, nil, nil, testfs.FS{})
|
||||
require.Equal(t, eofReader{}, expectedFS.stdin)
|
||||
require.Equal(t, io.Discard, expectedFS.stdout)
|
||||
require.Equal(t, io.Discard, expectedFS.stderr)
|
||||
require.Equal(t, expectedFS, sysCtx.FS())
|
||||
}
|
||||
|
||||
func TestNewContext_Args(t *testing.T) {
|
||||
|
||||
@@ -115,7 +115,7 @@ func (m *CallContext) close(ctx context.Context, exitCode uint32) (c bool, err e
|
||||
}
|
||||
c = true
|
||||
if sysCtx := m.Sys; sysCtx != nil { // nil if from HostModuleBuilder
|
||||
err = sysCtx.FS(ctx).Close(ctx)
|
||||
err = sysCtx.FS().Close(ctx)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -144,9 +144,9 @@ func TestCallContext_Close(t *testing.T) {
|
||||
|
||||
t.Run("calls Context.Close()", func(t *testing.T) {
|
||||
sysCtx := sys.DefaultContext(testfs.FS{"foo": &testfs.File{}})
|
||||
fsCtx := sysCtx.FS(testCtx)
|
||||
fsCtx := sysCtx.FS()
|
||||
|
||||
_, err := fsCtx.OpenFile(testCtx, "/foo")
|
||||
_, err := fsCtx.OpenFile("/foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx)
|
||||
@@ -154,14 +154,14 @@ func TestCallContext_Close(t *testing.T) {
|
||||
|
||||
// We use side effects to determine if Close in fact called Context.Close (without repeating sys_test.go).
|
||||
// One side effect of Context.Close is that it clears the openedFiles map. Verify our base case.
|
||||
_, ok := fsCtx.OpenedFile(testCtx, 3)
|
||||
_, ok := fsCtx.OpenedFile(3)
|
||||
require.True(t, ok, "sysCtx.openedFiles was empty")
|
||||
|
||||
// Closing should not err.
|
||||
require.NoError(t, m.Close(testCtx))
|
||||
|
||||
// Verify our intended side-effect
|
||||
_, ok = fsCtx.OpenedFile(testCtx, 3)
|
||||
_, ok = fsCtx.OpenedFile(3)
|
||||
require.False(t, ok, "expected no opened files")
|
||||
|
||||
// Verify no error closing again.
|
||||
@@ -172,9 +172,9 @@ func TestCallContext_Close(t *testing.T) {
|
||||
// Right now, the only way to err closing the sys context is if a File.Close erred.
|
||||
testFS := testfs.FS{"foo": &testfs.File{CloseErr: errors.New("error closing")}}
|
||||
sysCtx := sys.DefaultContext(testFS)
|
||||
fsCtx := sysCtx.FS(testCtx)
|
||||
fsCtx := sysCtx.FS()
|
||||
|
||||
_, err := fsCtx.OpenFile(testCtx, "/foo")
|
||||
_, err := fsCtx.OpenFile("/foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx)
|
||||
@@ -183,7 +183,7 @@ func TestCallContext_Close(t *testing.T) {
|
||||
require.EqualError(t, m.Close(testCtx), "error closing")
|
||||
|
||||
// Verify our intended side-effect
|
||||
_, ok := fsCtx.OpenedFile(testCtx, 3)
|
||||
_, ok := fsCtx.OpenedFile(3)
|
||||
require.False(t, ok, "expected no opened files")
|
||||
})
|
||||
}
|
||||
@@ -240,9 +240,9 @@ func TestCallContext_CallDynamic(t *testing.T) {
|
||||
|
||||
t.Run("calls Context.Close()", func(t *testing.T) {
|
||||
sysCtx := sys.DefaultContext(testfs.FS{"foo": &testfs.File{}})
|
||||
fsCtx := sysCtx.FS(testCtx)
|
||||
fsCtx := sysCtx.FS()
|
||||
|
||||
_, err := fsCtx.OpenFile(testCtx, "/foo")
|
||||
_, err := fsCtx.OpenFile("/foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx)
|
||||
@@ -250,14 +250,14 @@ func TestCallContext_CallDynamic(t *testing.T) {
|
||||
|
||||
// We use side effects to determine if Close in fact called Context.Close (without repeating sys_test.go).
|
||||
// One side effect of Context.Close is that it clears the openedFiles map. Verify our base case.
|
||||
_, ok := fsCtx.OpenedFile(testCtx, 3)
|
||||
_, ok := fsCtx.OpenedFile(3)
|
||||
require.True(t, ok, "sysCtx.openedFiles was empty")
|
||||
|
||||
// Closing should not err.
|
||||
require.NoError(t, m.Close(testCtx))
|
||||
|
||||
// Verify our intended side-effect
|
||||
_, ok = fsCtx.OpenedFile(testCtx, 3)
|
||||
_, ok = fsCtx.OpenedFile(3)
|
||||
require.False(t, ok, "expected no opened files")
|
||||
|
||||
// Verify no error closing again.
|
||||
@@ -268,9 +268,9 @@ func TestCallContext_CallDynamic(t *testing.T) {
|
||||
// Right now, the only way to err closing the sys context is if a File.Close erred.
|
||||
testFS := testfs.FS{"foo": &testfs.File{CloseErr: errors.New("error closing")}}
|
||||
sysCtx := sys.DefaultContext(testFS)
|
||||
fsCtx := sysCtx.FS(testCtx)
|
||||
fsCtx := sysCtx.FS()
|
||||
|
||||
_, err := fsCtx.OpenFile(testCtx, "/foo")
|
||||
_, err := fsCtx.OpenFile("/foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx)
|
||||
@@ -279,7 +279,7 @@ func TestCallContext_CallDynamic(t *testing.T) {
|
||||
require.EqualError(t, m.Close(testCtx), "error closing")
|
||||
|
||||
// Verify our intended side-effect
|
||||
_, ok := fsCtx.OpenedFile(testCtx, 3)
|
||||
_, ok := fsCtx.OpenedFile(3)
|
||||
require.False(t, ok, "expected no opened files")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -235,9 +235,9 @@ func TestNamespace_CloseWithExitCode(t *testing.T) {
|
||||
// Right now, the only way to err closing the sys context is if a File.Close erred.
|
||||
testFS := testfs.FS{"foo": &testfs.File{CloseErr: errors.New("error closing")}}
|
||||
sysCtx := sys.DefaultContext(testFS)
|
||||
fsCtx := sysCtx.FS(testCtx)
|
||||
fsCtx := sysCtx.FS()
|
||||
|
||||
_, err := fsCtx.OpenFile(testCtx, "/foo")
|
||||
_, err := fsCtx.OpenFile("/foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
ns, m1, m2 := newTestNamespace()
|
||||
|
||||
Reference in New Issue
Block a user