wasi: unexports errno and re-uses constants for logging (#971)

We originally exported WASI errno as we originally supported invoking
host functions directly (e.g. without a guest). This was an invalid call
pattern, and we removed that. However, we left the errnos exported even
though the caller of a guest won't ever see them. This prevented us from
re-using them cleanly in features such as logging.

This moves all constants including function names and flag enums
internal so that there is less duplication between logging and
implementation of wasi functions. This also helps in reference searches,
as we can analyze uses of a particular function name.

The only constant left exported is the module name, as there's a use
case for that (overriding implementations via FunctionBuilder).

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2022-12-29 09:42:10 +08:00
committed by GitHub
parent 15dc3d7d37
commit 64a4ab3ba5
41 changed files with 1249 additions and 1149 deletions

View File

@@ -7,10 +7,10 @@ import (
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/experimental"
wasilogging "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/logging"
gologging "github.com/tetratelabs/wazero/internal/gojs/logging"
"github.com/tetratelabs/wazero/internal/logging"
"github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
wasilogging "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1/logging"
)
type Writer interface {
@@ -78,7 +78,7 @@ func (f *loggingListenerFactory) NewListener(fnd api.FunctionDefinition) experim
var pSampler logging.ParamSampler
var rLoggers []logging.ResultLogger
switch fnd.ModuleName() {
case wasi_snapshot_preview1.ModuleName:
case wasi_snapshot_preview1.InternalModuleName:
if f.fsOnly && !wasilogging.IsFilesystemFunction(fnd) {
return nil
}

View File

@@ -9,8 +9,8 @@ import (
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/experimental/logging"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/testing/require"
wasi "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/wasm"
)
@@ -18,7 +18,7 @@ import (
var testCtx = context.WithValue(context.Background(), struct{}{}, "arbitrary")
func Test_loggingListener(t *testing.T) {
wasiFuncName := "random_get"
wasiFuncName := wasi.RandomGetName
wasiFuncType := &wasm.FunctionType{
Params: []api.ValueType{api.ValueTypeI32, api.ValueTypeI32},
Results: []api.ValueType{api.ValueTypeI32},
@@ -63,13 +63,13 @@ func Test_loggingListener(t *testing.T) {
{
name: "wasi",
functype: wasiFuncType,
moduleName: wasi_snapshot_preview1.ModuleName,
moduleName: wasi.InternalModuleName,
funcName: wasiFuncName,
paramNames: wasiParamNames,
resultNames: wasiResultNames,
isHostFunc: true,
params: wasiParams,
results: []uint64{uint64(wasi_snapshot_preview1.ErrnoSuccess)},
results: []uint64{uint64(wasi.ErrnoSuccess)},
expected: `==> wasi_snapshot_preview1.random_get(buf=0,buf_len=8)
<== errno=ESUCCESS
`,
@@ -77,13 +77,13 @@ func Test_loggingListener(t *testing.T) {
{
name: "wasi errno",
functype: wasiFuncType,
moduleName: wasi_snapshot_preview1.ModuleName,
moduleName: wasi.InternalModuleName,
funcName: wasiFuncName,
paramNames: wasiParamNames,
resultNames: wasiResultNames,
isHostFunc: true,
params: wasiParams,
results: []uint64{uint64(wasi_snapshot_preview1.ErrnoFault)},
results: []uint64{uint64(wasi.ErrnoFault)},
expected: `==> wasi_snapshot_preview1.random_get(buf=0,buf_len=8)
<== errno=EFAULT
`,
@@ -91,7 +91,7 @@ func Test_loggingListener(t *testing.T) {
{
name: "wasi error",
functype: wasiFuncType,
moduleName: wasi_snapshot_preview1.ModuleName,
moduleName: wasi.InternalModuleName,
funcName: wasiFuncName,
paramNames: wasiParamNames,
resultNames: wasiResultNames,

View File

@@ -4,15 +4,11 @@ import (
"context"
"github.com/tetratelabs/wazero/api"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/wasm"
)
const (
argsGetName = "args_get"
argsSizesGetName = "args_sizes_get"
)
// argsGet is the WASI function named argsGetName that reads command-line
// argsGet is the WASI function named ArgsGetName that reads command-line
// argument data.
//
// # Parameters
@@ -44,7 +40,7 @@ const (
// See argsSizesGet
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#args_get
// See https://en.wikipedia.org/wiki/Null-terminated_string
var argsGet = newHostFunc(argsGetName, argsGetFn, []api.ValueType{i32, i32}, "argv", "argv_buf")
var argsGet = newHostFunc(ArgsGetName, argsGetFn, []api.ValueType{i32, i32}, "argv", "argv_buf")
func argsGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
sysCtx := mod.(*wasm.CallContext).Sys
@@ -52,7 +48,7 @@ func argsGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
return writeOffsetsAndNullTerminatedValues(mod.Memory(), sysCtx.Args(), argv, argvBuf, sysCtx.ArgsSize())
}
// argsSizesGet is the WASI function named argsSizesGetName that reads
// argsSizesGet is the WASI function named ArgsSizesGetName that reads
// command-line argument sizes.
//
// # Parameters
@@ -81,7 +77,7 @@ func argsGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
// See argsGet
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#args_sizes_get
// See https://en.wikipedia.org/wiki/Null-terminated_string
var argsSizesGet = newHostFunc(argsSizesGetName, argsSizesGetFn, []api.ValueType{i32, i32}, "result.argc", "result.argv_len")
var argsSizesGet = newHostFunc(ArgsSizesGetName, argsSizesGetFn, []api.ValueType{i32, i32}, "result.argc", "result.argv_len")
func argsSizesGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
sysCtx := mod.(*wasm.CallContext).Sys

View File

@@ -1,10 +1,11 @@
package wasi_snapshot_preview1
package wasi_snapshot_preview1_test
import (
"testing"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/internal/testing/require"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
)
func Test_argsGet(t *testing.T) {
@@ -25,7 +26,7 @@ func Test_argsGet(t *testing.T) {
maskMemory(t, mod, len(expectedMemory)+int(argvBuf))
// Invoke argsGet and check the memory side effects.
requireErrno(t, ErrnoSuccess, mod, argsGetName, uint64(argv), uint64(argvBuf))
requireErrno(t, ErrnoSuccess, mod, ArgsGetName, uint64(argv), uint64(argvBuf))
require.Equal(t, `
==> wasi_snapshot_preview1.args_get(argv=22,argv_buf=16)
<== errno=ESUCCESS
@@ -94,7 +95,7 @@ func Test_argsGet_Errors(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
defer log.Reset()
requireErrno(t, ErrnoFault, mod, argsGetName, uint64(tc.argv), uint64(tc.argvBuf))
requireErrno(t, ErrnoFault, mod, ArgsGetName, uint64(tc.argv), uint64(tc.argvBuf))
require.Equal(t, tc.expectedLog, "\n"+log.String())
})
}
@@ -117,7 +118,7 @@ func Test_argsSizesGet(t *testing.T) {
maskMemory(t, mod, int(resultArgc)+len(expectedMemory))
// Invoke argsSizesGet and check the memory side effects.
requireErrno(t, ErrnoSuccess, mod, argsSizesGetName, uint64(resultArgc), uint64(resultArgvLen))
requireErrno(t, ErrnoSuccess, mod, ArgsSizesGetName, uint64(resultArgc), uint64(resultArgvLen))
require.Equal(t, `
==> wasi_snapshot_preview1.args_sizes_get(result.argc=16,result.argv_len=21)
<== errno=ESUCCESS
@@ -184,7 +185,7 @@ func Test_argsSizesGet_Errors(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
defer log.Reset()
requireErrno(t, ErrnoFault, mod, argsSizesGetName, uint64(tc.argc), uint64(tc.argvLen))
requireErrno(t, ErrnoFault, mod, ArgsSizesGetName, uint64(tc.argc), uint64(tc.argvLen))
require.Equal(t, tc.expectedLog, "\n"+log.String())
})
}

View File

@@ -5,25 +5,11 @@ import (
"time"
"github.com/tetratelabs/wazero/api"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/wasm"
)
const (
clockResGetName = "clock_res_get"
clockTimeGetName = "clock_time_get"
)
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clockid-enumu32
const (
// clockIDRealtime is the name ID named "realtime" like sys.Walltime
clockIDRealtime = iota
// clockIDMonotonic is the name ID named "monotonic" like sys.Nanotime
clockIDMonotonic
// Note: clockIDProcessCputime and clockIDThreadCputime were removed by
// WASI maintainers: https://github.com/WebAssembly/wasi-libc/pull/294
)
// clockResGet is the WASI function named clockResGetName that returns the
// clockResGet is the WASI function named ClockResGetName that returns the
// resolution of time values returned by clockTimeGet.
//
// # Parameters
@@ -51,7 +37,7 @@ const (
// Note: This is similar to `clock_getres` in POSIX.
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_res_getid-clockid---errno-timestamp
// See https://linux.die.net/man/3/clock_getres
var clockResGet = newHostFunc(clockResGetName, clockResGetFn, []api.ValueType{i32, i32}, "id", "result.resolution")
var clockResGet = newHostFunc(ClockResGetName, clockResGetFn, []api.ValueType{i32, i32}, "id", "result.resolution")
func clockResGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
sysCtx := mod.(*wasm.CallContext).Sys
@@ -59,9 +45,9 @@ func clockResGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
var resolution uint64 // ns
switch id {
case clockIDRealtime:
case ClockIDRealtime:
resolution = uint64(sysCtx.WalltimeResolution())
case clockIDMonotonic:
case ClockIDMonotonic:
resolution = uint64(sysCtx.NanotimeResolution())
default:
return ErrnoInval
@@ -73,7 +59,7 @@ func clockResGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
return ErrnoSuccess
}
// clockTimeGet is the WASI function named clockTimeGetName that returns
// clockTimeGet is the WASI function named ClockTimeGetName that returns
// the time value of a name (time.Now).
//
// # Parameters
@@ -104,7 +90,7 @@ func clockResGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
// Note: This is similar to `clock_gettime` in POSIX.
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_time_getid-clockid-precision-timestamp---errno-timestamp
// See https://linux.die.net/man/3/clock_gettime
var clockTimeGet = newHostFunc(clockTimeGetName, clockTimeGetFn, []api.ValueType{i32, i64, i32}, "id", "precision", "result.timestamp")
var clockTimeGet = newHostFunc(ClockTimeGetName, clockTimeGetFn, []api.ValueType{i32, i64, i32}, "id", "precision", "result.timestamp")
func clockTimeGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
sysCtx := mod.(*wasm.CallContext).Sys
@@ -115,10 +101,10 @@ func clockTimeGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
var val int64
switch id {
case clockIDRealtime:
case ClockIDRealtime:
sec, nsec := sysCtx.Walltime()
val = (sec * time.Second.Nanoseconds()) + int64(nsec)
case clockIDMonotonic:
case ClockIDMonotonic:
val = sysCtx.Nanotime()
default:
return ErrnoInval

View File

@@ -1,4 +1,4 @@
package wasi_snapshot_preview1
package wasi_snapshot_preview1_test
import (
_ "embed"
@@ -6,6 +6,7 @@ import (
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/internal/testing/require"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
)
func Test_clockResGet(t *testing.T) {
@@ -32,7 +33,7 @@ func Test_clockResGet(t *testing.T) {
}{
{
name: "Realtime",
clockID: clockIDRealtime,
clockID: ClockIDRealtime,
expectedMemory: expectedMemoryMicro,
expectedLog: `
==> wasi_snapshot_preview1.clock_res_get(id=0,result.resolution=16)
@@ -41,7 +42,7 @@ func Test_clockResGet(t *testing.T) {
},
{
name: "Monotonic",
clockID: clockIDMonotonic,
clockID: ClockIDMonotonic,
expectedMemory: expectedMemoryNano,
expectedLog: `
==> wasi_snapshot_preview1.clock_res_get(id=1,result.resolution=16)
@@ -59,7 +60,7 @@ func Test_clockResGet(t *testing.T) {
resultResolution := 16 // arbitrary offset
maskMemory(t, mod, resultResolution+len(tc.expectedMemory))
requireErrno(t, ErrnoSuccess, mod, clockResGetName, uint64(tc.clockID), uint64(resultResolution))
requireErrno(t, ErrnoSuccess, mod, ClockResGetName, uint64(tc.clockID), uint64(resultResolution))
require.Equal(t, tc.expectedLog, "\n"+log.String())
actual, ok := mod.Memory().Read(uint32(resultResolution-1), uint32(len(tc.expectedMemory)))
@@ -115,7 +116,7 @@ func Test_clockResGet_Unsupported(t *testing.T) {
defer log.Reset()
resultResolution := 16 // arbitrary offset
requireErrno(t, tc.expectedErrno, mod, clockResGetName, uint64(tc.clockID), uint64(resultResolution))
requireErrno(t, tc.expectedErrno, mod, ClockResGetName, uint64(tc.clockID), uint64(resultResolution))
require.Equal(t, tc.expectedLog, "\n"+log.String())
})
}
@@ -133,7 +134,7 @@ func Test_clockTimeGet(t *testing.T) {
}{
{
name: "Realtime",
clockID: clockIDRealtime,
clockID: ClockIDRealtime,
expectedMemory: []byte{
'?', // resultTimestamp is after this
0x0, 0x0, 0x1f, 0xa6, 0x70, 0xfc, 0xc5, 0x16, // little endian-encoded epochNanos
@@ -146,7 +147,7 @@ func Test_clockTimeGet(t *testing.T) {
},
{
name: "Monotonic",
clockID: clockIDMonotonic,
clockID: ClockIDMonotonic,
expectedMemory: []byte{
'?', // resultTimestamp is after this
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // fake nanotime starts at zero
@@ -167,7 +168,7 @@ func Test_clockTimeGet(t *testing.T) {
resultTimestamp := 16 // arbitrary offset
maskMemory(t, mod, resultTimestamp+len(tc.expectedMemory))
requireErrno(t, ErrnoSuccess, mod, clockTimeGetName, uint64(tc.clockID), 0 /* TODO: precision */, uint64(resultTimestamp))
requireErrno(t, ErrnoSuccess, mod, ClockTimeGetName, uint64(tc.clockID), 0 /* TODO: precision */, uint64(resultTimestamp))
require.Equal(t, tc.expectedLog, "\n"+log.String())
actual, ok := mod.Memory().Read(uint32(resultTimestamp-1), uint32(len(tc.expectedMemory)))
@@ -223,7 +224,7 @@ func Test_clockTimeGet_Unsupported(t *testing.T) {
defer log.Reset()
resultTimestamp := 16 // arbitrary offset
requireErrno(t, tc.expectedErrno, mod, clockTimeGetName, uint64(tc.clockID), uint64(0) /* TODO: precision */, uint64(resultTimestamp))
requireErrno(t, tc.expectedErrno, mod, ClockTimeGetName, uint64(tc.clockID), uint64(0) /* TODO: precision */, uint64(resultTimestamp))
require.Equal(t, tc.expectedLog, "\n"+log.String())
})
}
@@ -264,7 +265,7 @@ func Test_clockTimeGet_Errors(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
defer log.Reset()
requireErrno(t, ErrnoFault, mod, clockTimeGetName, uint64(0) /* TODO: id */, uint64(0) /* TODO: precision */, uint64(tc.resultTimestamp))
requireErrno(t, ErrnoFault, mod, ClockTimeGetName, uint64(0) /* TODO: id */, uint64(0) /* TODO: precision */, uint64(tc.resultTimestamp))
require.Equal(t, tc.expectedLog, "\n"+log.String())
})
}

View File

@@ -4,15 +4,11 @@ import (
"context"
"github.com/tetratelabs/wazero/api"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/wasm"
)
const (
environGetName = "environ_get"
environSizesGetName = "environ_sizes_get"
)
// environGet is the WASI function named environGetName that reads
// environGet is the WASI function named EnvironGetName that reads
// environment variables.
//
// # Parameters
@@ -44,7 +40,7 @@ const (
// See environSizesGet
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#environ_get
// See https://en.wikipedia.org/wiki/Null-terminated_string
var environGet = newHostFunc(environGetName, environGetFn, []api.ValueType{i32, i32}, "environ", "environ_buf")
var environGet = newHostFunc(EnvironGetName, environGetFn, []api.ValueType{i32, i32}, "environ", "environ_buf")
func environGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
sysCtx := mod.(*wasm.CallContext).Sys
@@ -53,7 +49,7 @@ func environGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
return writeOffsetsAndNullTerminatedValues(mod.Memory(), sysCtx.Environ(), environ, environBuf, sysCtx.EnvironSize())
}
// environSizesGet is the WASI function named environSizesGetName that
// environSizesGet is the WASI function named EnvironSizesGetName that
// reads environment variable sizes.
//
// # Parameters
@@ -84,7 +80,7 @@ func environGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
// See environGet
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#environ_sizes_get
// and https://en.wikipedia.org/wiki/Null-terminated_string
var environSizesGet = newHostFunc(environSizesGetName, environSizesGetFn, []api.ValueType{i32, i32}, "result.environc", "result.environv_len")
var environSizesGet = newHostFunc(EnvironSizesGetName, environSizesGetFn, []api.ValueType{i32, i32}, "result.environc", "result.environv_len")
func environSizesGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
sysCtx := mod.(*wasm.CallContext).Sys

View File

@@ -1,10 +1,11 @@
package wasi_snapshot_preview1
package wasi_snapshot_preview1_test
import (
"testing"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/internal/testing/require"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
)
func Test_environGet(t *testing.T) {
@@ -27,7 +28,7 @@ func Test_environGet(t *testing.T) {
maskMemory(t, mod, len(expectedMemory)+int(resultEnvironBuf))
// Invoke environGet and check the memory side effects.
requireErrno(t, ErrnoSuccess, mod, environGetName, uint64(resultEnviron), uint64(resultEnvironBuf))
requireErrno(t, ErrnoSuccess, mod, EnvironGetName, uint64(resultEnviron), uint64(resultEnvironBuf))
require.Equal(t, `
==> wasi_snapshot_preview1.environ_get(environ=26,environ_buf=16)
<== errno=ESUCCESS
@@ -97,7 +98,7 @@ func Test_environGet_Errors(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
defer log.Reset()
requireErrno(t, ErrnoFault, mod, environGetName, uint64(tc.environ), uint64(tc.environBuf))
requireErrno(t, ErrnoFault, mod, EnvironGetName, uint64(tc.environ), uint64(tc.environBuf))
require.Equal(t, tc.expectedLog, "\n"+log.String())
})
}
@@ -121,7 +122,7 @@ func Test_environSizesGet(t *testing.T) {
maskMemory(t, mod, len(expectedMemory)+int(resultEnvironc))
// Invoke environSizesGet and check the memory side effects.
requireErrno(t, ErrnoSuccess, mod, environSizesGetName, uint64(resultEnvironc), uint64(resultEnvironvLen))
requireErrno(t, ErrnoSuccess, mod, EnvironSizesGetName, uint64(resultEnvironc), uint64(resultEnvironvLen))
require.Equal(t, `
==> wasi_snapshot_preview1.environ_sizes_get(result.environc=16,result.environv_len=21)
<== errno=ESUCCESS
@@ -189,7 +190,7 @@ func Test_environSizesGet_Errors(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
defer log.Reset()
requireErrno(t, ErrnoFault, mod, environSizesGetName, uint64(tc.environc), uint64(tc.environLen))
requireErrno(t, ErrnoFault, mod, EnvironSizesGetName, uint64(tc.environc), uint64(tc.environLen))
require.Equal(t, tc.expectedLog, "\n"+log.String())
})
}

View File

@@ -1,4 +1,4 @@
package wasi_snapshot_preview1
package wasi_snapshot_preview1_test
import (
"context"
@@ -8,6 +8,7 @@ import (
"os"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/sys"
)
@@ -27,13 +28,10 @@ func Example() {
// Create a new WebAssembly Runtime.
r := wazero.NewRuntime(ctx)
defer r.Close(ctx)
// Instantiate WASI, which implements system I/O such as console output.
wm, err := Instantiate(ctx, r)
if err != nil {
log.Panicln(err)
}
defer wm.Close(testCtx)
wasi_snapshot_preview1.MustInstantiate(ctx, r)
// Compile the WebAssembly module using the default configuration.
code, err := r.CompileModule(ctx, exitOnStartWasm)

View File

@@ -8,70 +8,34 @@ import (
"math"
"os"
"path"
"syscall"
"github.com/tetratelabs/wazero/api"
internalsys "github.com/tetratelabs/wazero/internal/sys"
"github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/sys"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/wasm"
)
const (
fdAdviseName = "fd_advise"
fdAllocateName = "fd_allocate"
fdCloseName = "fd_close"
fdDatasyncName = "fd_datasync"
fdFdstatGetName = "fd_fdstat_get"
fdFdstatSetFlagsName = "fd_fdstat_set_flags"
fdFdstatSetRightsName = "fd_fdstat_set_rights"
fdFilestatGetName = "fd_filestat_get"
fdFilestatSetSizeName = "fd_filestat_set_size"
fdFilestatSetTimesName = "fd_filestat_set_times"
fdPreadName = "fd_pread"
fdPrestatGetName = "fd_prestat_get"
fdPrestatDirNameName = "fd_prestat_dir_name"
fdPwriteName = "fd_pwrite"
fdReadName = "fd_read"
fdReaddirName = "fd_readdir"
fdRenumberName = "fd_renumber"
fdSeekName = "fd_seek"
fdSyncName = "fd_sync"
fdTellName = "fd_tell"
fdWriteName = "fd_write"
pathCreateDirectoryName = "path_create_directory"
pathFilestatGetName = "path_filestat_get"
pathFilestatSetTimesName = "path_filestat_set_times"
pathLinkName = "path_link"
pathOpenName = "path_open"
pathReadlinkName = "path_readlink"
pathRemoveDirectoryName = "path_remove_directory"
pathRenameName = "path_rename"
pathSymlinkName = "path_symlink"
pathUnlinkFileName = "path_unlink_file"
)
// fdAdvise is the WASI function named fdAdviseName which provides file
// fdAdvise is the WASI function named FdAdviseName which provides file
// advisory information on a file descriptor.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_advisefd-fd-offset-filesize-len-filesize-advice-advice---errno
var fdAdvise = stubFunction(
fdAdviseName,
FdAdviseName,
[]wasm.ValueType{i32, i64, i64, i32},
"fd", "offset", "len", "advice",
)
// fdAllocate is the WASI function named fdAllocateName which forces the
// fdAllocate is the WASI function named FdAllocateName which forces the
// allocation of space in a file.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_allocatefd-fd-offset-filesize-len-filesize---errno
var fdAllocate = stubFunction(
fdAllocateName,
FdAllocateName,
[]wasm.ValueType{i32, i64, i64},
"fd", "offset", "len",
)
// fdClose is the WASI function named fdCloseName which closes a file
// fdClose is the WASI function named FdCloseName which closes a file
// descriptor.
//
// # Parameters
@@ -86,7 +50,7 @@ var fdAllocate = stubFunction(
// Note: This is similar to `close` in POSIX.
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_close
// and https://linux.die.net/man/3/close
var fdClose = newHostFunc(fdCloseName, fdCloseFn, []api.ValueType{i32}, "fd")
var fdClose = newHostFunc(FdCloseName, fdCloseFn, []api.ValueType{i32}, "fd")
func fdCloseFn(_ context.Context, mod api.Module, params []uint64) Errno {
fsc := mod.(*wasm.CallContext).Sys.FS()
@@ -98,13 +62,13 @@ func fdCloseFn(_ context.Context, mod api.Module, params []uint64) Errno {
return ErrnoSuccess
}
// fdDatasync is the WASI function named fdDatasyncName which synchronizes
// fdDatasync is the WASI function named FdDatasyncName which synchronizes
// the data of a file to disk.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_datasyncfd-fd---errno
var fdDatasync = stubFunction(fdDatasyncName, []api.ValueType{i32}, "fd")
var fdDatasync = stubFunction(FdDatasyncName, []api.ValueType{i32}, "fd")
// fdFdstatGet is the WASI function named fdFdstatGetName which returns the
// fdFdstatGet is the WASI function named FdFdstatGetName which returns the
// attributes of a file descriptor.
//
// # Parameters
@@ -141,7 +105,7 @@ var fdDatasync = stubFunction(fdDatasyncName, []api.ValueType{i32}, "fd")
// well as additional fields.
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fdstat
// and https://linux.die.net/man/3/fsync
var fdFdstatGet = newHostFunc(fdFdstatGetName, fdFdstatGetFn, []api.ValueType{i32, i32}, "fd", "result.stat")
var fdFdstatGet = newHostFunc(FdFdstatGetName, fdFdstatGetFn, []api.ValueType{i32, i32}, "fd", "result.stat")
// fdFdstatGetFn cannot currently use proxyResultParams because fdstat is larger
// than api.ValueTypeI64 (i64 == 8 bytes, but fdstat is 24).
@@ -158,7 +122,7 @@ func fdFdstatGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
stat, err := fsc.StatFile(fd)
if err != nil {
return toErrno(err)
return ToErrno(err)
}
filetype := getWasiFiletype(stat.Mode())
@@ -167,7 +131,7 @@ func fdFdstatGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
// Determine if it is writeable
if w := fsc.FdWriter(fd); w != nil {
// TODO: maybe cache flags to open instead
fdflags = wasi_snapshot_preview1.FD_APPEND
fdflags = FD_APPEND
}
writeFdstat(buf, filetype, fdflags)
@@ -176,7 +140,7 @@ func fdFdstatGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
}
var blockFdstat = []byte{
wasi_snapshot_preview1.FILETYPE_BLOCK_DEVICE, 0, // filetype
FILETYPE_BLOCK_DEVICE, 0, // filetype
0, 0, 0, 0, 0, 0, // fdflags
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_base
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_inheriting
@@ -189,22 +153,22 @@ func writeFdstat(buf []byte, filetype uint8, fdflags uint16) {
buf[2] = byte(fdflags)
}
// fdFdstatSetFlags is the WASI function named fdFdstatSetFlagsName which
// fdFdstatSetFlags is the WASI function named FdFdstatSetFlagsName which
// adjusts the flags associated with a file descriptor.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_fdstat_set_flagsfd-fd-flags-fdflags---errnoand is stubbed for GrainLang per #271
var fdFdstatSetFlags = stubFunction(fdFdstatSetFlagsName, []wasm.ValueType{i32, i32}, "fd", "flags")
var fdFdstatSetFlags = stubFunction(FdFdstatSetFlagsName, []wasm.ValueType{i32, i32}, "fd", "flags")
// fdFdstatSetRights will not be implemented as rights were removed from WASI.
//
// See https://github.com/bytecodealliance/wasmtime/pull/4666
var fdFdstatSetRights = stubFunction(
fdFdstatSetRightsName,
FdFdstatSetRightsName,
[]wasm.ValueType{i32, i64, i64},
"fd", "fs_rights_base", "fs_rights_inheriting",
)
// fdFilestatGet is the WASI function named fdFilestatGetName which returns
// fdFilestatGet is the WASI function named FdFilestatGetName which returns
// the stat attributes of an open file.
//
// # Parameters
@@ -251,7 +215,7 @@ var fdFdstatSetRights = stubFunction(
// Note: This is similar to `fstat` in POSIX.
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_filestat_getfd-fd---errno-filestat
// and https://linux.die.net/man/3/fstat
var fdFilestatGet = newHostFunc(fdFilestatGetName, fdFilestatGetFn, []api.ValueType{i32, i32}, "fd", "result.filestat")
var fdFilestatGet = newHostFunc(FdFilestatGetName, fdFilestatGetFn, []api.ValueType{i32, i32}, "fd", "result.filestat")
// fdFilestatGetFn cannot currently use proxyResultParams because filestat is
// larger than api.ValueTypeI64 (i64 == 8 bytes, but filestat is 64).
@@ -270,7 +234,7 @@ func fdFilestatGetFunc(mod api.Module, fd, resultBuf uint32) Errno {
stat, err := fsc.StatFile(fd)
if err != nil {
return toErrno(err)
return ToErrno(err)
}
writeFilestat(buf, stat)
@@ -279,17 +243,17 @@ func fdFilestatGetFunc(mod api.Module, fd, resultBuf uint32) Errno {
}
func getWasiFiletype(fileMode fs.FileMode) uint8 {
wasiFileType := wasi_snapshot_preview1.FILETYPE_UNKNOWN
wasiFileType := FILETYPE_UNKNOWN
if fileMode&fs.ModeDevice != 0 {
wasiFileType = wasi_snapshot_preview1.FILETYPE_BLOCK_DEVICE
wasiFileType = FILETYPE_BLOCK_DEVICE
} else if fileMode&fs.ModeCharDevice != 0 {
wasiFileType = wasi_snapshot_preview1.FILETYPE_CHARACTER_DEVICE
wasiFileType = FILETYPE_CHARACTER_DEVICE
} else if fileMode&fs.ModeDir != 0 {
wasiFileType = wasi_snapshot_preview1.FILETYPE_DIRECTORY
wasiFileType = FILETYPE_DIRECTORY
} else if fileMode&fs.ModeType == 0 {
wasiFileType = wasi_snapshot_preview1.FILETYPE_REGULAR_FILE
wasiFileType = FILETYPE_REGULAR_FILE
} else if fileMode&fs.ModeSymlink != 0 {
wasiFileType = wasi_snapshot_preview1.FILETYPE_SYMBOLIC_LINK
wasiFileType = FILETYPE_SYMBOLIC_LINK
}
return wasiFileType
}
@@ -297,7 +261,7 @@ func getWasiFiletype(fileMode fs.FileMode) uint8 {
var blockFilestat = []byte{
0, 0, 0, 0, 0, 0, 0, 0, // device
0, 0, 0, 0, 0, 0, 0, 0, // inode
wasi_snapshot_preview1.FILETYPE_BLOCK_DEVICE, 0, 0, 0, 0, 0, 0, 0, // filetype
FILETYPE_BLOCK_DEVICE, 0, 0, 0, 0, 0, 0, 0, // filetype
1, 0, 0, 0, 0, 0, 0, 0, // nlink
0, 0, 0, 0, 0, 0, 0, 0, // filesize
0, 0, 0, 0, 0, 0, 0, 0, // atim
@@ -319,30 +283,30 @@ func writeFilestat(buf []byte, stat fs.FileInfo) {
le.PutUint64(buf[56:], uint64(mtim)) // ctim
}
// fdFilestatSetSize is the WASI function named fdFilestatSetSizeName which
// fdFilestatSetSize is the WASI function named FdFilestatSetSizeName which
// adjusts the size of an open file.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_filestat_set_sizefd-fd-size-filesize---errno
var fdFilestatSetSize = stubFunction(fdFilestatSetSizeName, []wasm.ValueType{i32, i64}, "fd", "size")
var fdFilestatSetSize = stubFunction(FdFilestatSetSizeName, []wasm.ValueType{i32, i64}, "fd", "size")
// fdFilestatSetTimes is the WASI function named functionFdFilestatSetTimes
// which adjusts the times of an open file.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_filestat_set_timesfd-fd-atim-timestamp-mtim-timestamp-fst_flags-fstflags---errno
var fdFilestatSetTimes = stubFunction(
fdFilestatSetTimesName,
FdFilestatSetTimesName,
[]wasm.ValueType{i32, i64, i64, i32},
"fd", "atim", "mtim", "fst_flags",
)
// fdPread is the WASI function named fdPreadName which reads from a file
// fdPread is the WASI function named FdPreadName which reads from a file
// descriptor, without using and updating the file descriptor's offset.
//
// Except for handling offset, this implementation is identical to fdRead.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_preadfd-fd-iovs-iovec_array-offset-filesize---errno-size
var fdPread = newHostFunc(
fdPreadName, fdPreadFn,
FdPreadName, fdPreadFn,
[]api.ValueType{i32, i32, i32, i64, i32},
"fd", "iovs", "iovs_len", "offset", "result.nread",
)
@@ -351,7 +315,7 @@ func fdPreadFn(_ context.Context, mod api.Module, params []uint64) Errno {
return fdReadOrPread(mod, params, true)
}
// fdPrestatGet is the WASI function named fdPrestatGetName which returns
// fdPrestatGet is the WASI function named FdPrestatGetName which returns
// the prestat data of a file descriptor.
//
// # Parameters
@@ -382,14 +346,14 @@ func fdPreadFn(_ context.Context, mod api.Module, params []uint64) Errno {
//
// See fdPrestatDirName and
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#prestat
var fdPrestatGet = newHostFunc(fdPrestatGetName, fdPrestatGetFn, []api.ValueType{i32, i32}, "fd", "result.prestat")
var fdPrestatGet = newHostFunc(FdPrestatGetName, fdPrestatGetFn, []api.ValueType{i32, i32}, "fd", "result.prestat")
func fdPrestatGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
fsc := mod.(*wasm.CallContext).Sys.FS()
fd, resultPrestat := uint32(params[0]), uint32(params[1])
// Currently, we only pre-open the root file descriptor.
if fd != internalsys.FdRoot {
if fd != sys.FdRoot {
return ErrnoBadf
}
@@ -407,7 +371,7 @@ func fdPrestatGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
return ErrnoSuccess
}
// fdPrestatDirName is the WASI function named fdPrestatDirNameName which
// fdPrestatDirName is the WASI function named FdPrestatDirNameName which
// returns the path of the pre-opened directory of a file descriptor.
//
// # Parameters
@@ -438,7 +402,7 @@ func fdPrestatGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
// See fdPrestatGet
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_prestat_dir_name
var fdPrestatDirName = newHostFunc(
fdPrestatDirNameName, fdPrestatDirNameFn,
FdPrestatDirNameName, fdPrestatDirNameFn,
[]api.ValueType{i32, i32, i32},
"fd", "result.path", "result.path_len",
)
@@ -448,7 +412,7 @@ func fdPrestatDirNameFn(_ context.Context, mod api.Module, params []uint64) Errn
fd, path, pathLen := uint32(params[0]), uint32(params[1]), uint32(params[2])
// Currently, we only pre-open the root file descriptor.
if fd != internalsys.FdRoot {
if fd != sys.FdRoot {
return ErrnoBadf
}
@@ -468,17 +432,17 @@ func fdPrestatDirNameFn(_ context.Context, mod api.Module, params []uint64) Errn
return ErrnoSuccess
}
// fdPwrite is the WASI function named fdPwriteName which writes to a file
// fdPwrite is the WASI function named FdPwriteName which writes to a file
// descriptor, without using and updating the file descriptor's offset.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_pwritefd-fd-iovs-ciovec_array-offset-filesize---errno-size
var fdPwrite = stubFunction(
fdPwriteName,
FdPwriteName,
[]wasm.ValueType{i32, i32, i32, i64, i32},
"fd", "iovs", "iovs_len", "offset", "result.nwritten",
)
// fdRead is the WASI function named fdReadName which reads from a file
// fdRead is the WASI function named FdReadName which reads from a file
// descriptor.
//
// # Parameters
@@ -528,7 +492,7 @@ var fdPwrite = stubFunction(
// See fdWrite
// and https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_read
var fdRead = newHostFunc(
fdReadName, fdReadFn,
FdReadName, fdReadFn,
[]api.ValueType{i32, i32, i32, i32},
"fd", "iovs", "iovs_len", "result.nread",
)
@@ -619,12 +583,12 @@ func fdRead_shouldContinueRead(n, l uint32, err error) (bool, Errno) {
return n == l && n != 0, ErrnoSuccess
}
// fdReaddir is the WASI function named fdReaddirName which reads directory
// fdReaddir is the WASI function named FdReaddirName which reads directory
// entries from a directory.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_readdirfd-fd-buf-pointeru8-buf_len-size-cookie-dircookie---errno-size
var fdReaddir = newHostFunc(
fdReaddirName, fdReaddirFn,
FdReaddirName, fdReaddirFn,
[]wasm.ValueType{i32, i32, i32, i64, i32},
"fd", "buf", "buf_len", "cookie", "result.bufused",
)
@@ -644,7 +608,7 @@ func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) Errno {
// The bufLen must be enough to write a dirent. Otherwise, the caller can't
// read what the next cookie is.
if bufLen < direntSize {
if bufLen < DirentSize {
return ErrnoInval
}
@@ -660,10 +624,10 @@ func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) Errno {
}
// First, determine the maximum directory entries that can be encoded as
// dirents. The total size is direntSize(24) + nameSize, for each file.
// dirents. The total size is DirentSize(24) + nameSize, for each file.
// Since a zero-length file name is invalid, the minimum size entry is
// 25 (direntSize + 1 character).
maxDirEntries := int(bufLen/direntSize + 1)
// 25 (DirentSize + 1 character).
maxDirEntries := int(bufLen/DirentSize + 1)
// While unlikely maxDirEntries will fit into bufLen, add one more just in
// case, as we need to know if we hit the end of the directory or not to
@@ -719,10 +683,10 @@ func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) Errno {
return ErrnoSuccess
}
const largestDirent = int64(math.MaxUint32 - direntSize)
const largestDirent = int64(math.MaxUint32 - DirentSize)
// lastDirEntries is broken out from fdReaddirFn for testability.
func lastDirEntries(dir *internalsys.ReadDir, cookie int64) (entries []fs.DirEntry, errno Errno) {
func lastDirEntries(dir *sys.ReadDir, cookie int64) (entries []fs.DirEntry, errno Errno) {
if cookie < 0 {
errno = ErrnoInval // invalid as we will never send a negative cookie.
return
@@ -757,10 +721,6 @@ func lastDirEntries(dir *internalsys.ReadDir, cookie int64) (entries []fs.DirEnt
return
}
// direntSize is the size of the dirent struct, which should be followed by the
// length of a file name.
const direntSize = uint32(24)
// maxDirents returns the maximum count and total entries that can fit in
// maxLen bytes.
//
@@ -773,7 +733,7 @@ const direntSize = uint32(24)
func maxDirents(entries []fs.DirEntry, bufLen uint32) (bufused, direntCount uint32, writeTruncatedEntry bool) {
lenRemaining := bufLen
for _, e := range entries {
if lenRemaining < direntSize {
if lenRemaining < DirentSize {
// We don't have enough space in bufLen for another struct,
// entry. A caller who wants more will retry.
@@ -787,9 +747,9 @@ func maxDirents(entries []fs.DirEntry, bufLen uint32) (bufused, direntCount uint
nameLen := int64(len(e.Name()))
var entryLen uint32
// Check to see if direntSize + nameLen overflows, or if it would be
// Check to see if DirentSize + nameLen overflows, or if it would be
// larger than possible to encode.
if el := int64(direntSize) + nameLen; el < 0 || el > largestDirent {
if el := int64(DirentSize) + nameLen; el < 0 || el > largestDirent {
// panic, as testing is difficult. ex we would have to extract a
// function to get size of a string or allocate a 2^32 size one!
panic("invalid filename: too large")
@@ -801,8 +761,8 @@ func maxDirents(entries []fs.DirEntry, bufLen uint32) (bufused, direntCount uint
// We haven't room to write the entry, and docs say to write the
// header. This helps especially when there is an entry with a very
// long filename. Ex if bufLen is 4096 and the filename is 4096,
// we need to write direntSize(24) + 4096 bytes to write the entry.
// In this case, we only write up to direntSize(24) to allow the
// we need to write DirentSize(24) + 4096 bytes to write the entry.
// In this case, we only write up to DirentSize(24) to allow the
// caller to resize.
// bufused == bufLen means more entries exist, which is the case
@@ -839,7 +799,7 @@ func writeDirents(
nameLen := uint32(len(e.Name()))
writeDirent(dirents[pos:], d_next, nameLen, e.IsDir())
pos += direntSize
pos += DirentSize
copy(dirents[pos:], e.Name())
pos += nameLen
@@ -851,7 +811,7 @@ func writeDirents(
}
// Write a dirent without its name
dirent := make([]byte, direntSize)
dirent := make([]byte, DirentSize)
e := entries[i]
writeDirent(dirent, d_next, uint32(len(e.Name())), e.IsDir())
@@ -859,21 +819,21 @@ func writeDirents(
copy(dirents[pos:], dirent)
}
// writeDirent writes direntSize bytes
// writeDirent writes DirentSize bytes
func writeDirent(buf []byte, dNext uint64, dNamlen uint32, dType bool) {
le.PutUint64(buf, dNext) // d_next
le.PutUint64(buf[8:], 0) // no d_ino
le.PutUint32(buf[16:], dNamlen) // d_namlen
filetype := wasi_snapshot_preview1.FILETYPE_REGULAR_FILE
filetype := FILETYPE_REGULAR_FILE
if dType {
filetype = wasi_snapshot_preview1.FILETYPE_DIRECTORY
filetype = FILETYPE_DIRECTORY
}
le.PutUint32(buf[20:], uint32(filetype)) // d_type
}
// openedDir returns the directory and ErrnoSuccess if the fd points to a readable directory.
func openedDir(fsc *internalsys.FSContext, fd uint32) (fs.ReadDirFile, *internalsys.ReadDir, Errno) {
func openedDir(fsc *sys.FSContext, fd uint32) (fs.ReadDirFile, *sys.ReadDir, Errno) {
if f, ok := fsc.OpenedFile(fd); !ok {
return nil, nil, ErrnoBadf
} else if d, ok := f.File.(fs.ReadDirFile); !ok {
@@ -886,19 +846,19 @@ func openedDir(fsc *internalsys.FSContext, fd uint32) (fs.ReadDirFile, *internal
return nil, nil, ErrnoBadf
} else {
if f.ReadDir == nil {
f.ReadDir = &internalsys.ReadDir{}
f.ReadDir = &sys.ReadDir{}
}
return d, f.ReadDir, ErrnoSuccess
}
}
// fdRenumber is the WASI function named fdRenumberName which atomically
// fdRenumber is the WASI function named FdRenumberName which atomically
// replaces a file descriptor by renumbering another file descriptor.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_renumberfd-fd-to-fd---errno
var fdRenumber = stubFunction(fdRenumberName, []wasm.ValueType{i32, i32}, "fd", "to")
var fdRenumber = stubFunction(FdRenumberName, []wasm.ValueType{i32, i32}, "fd", "to")
// fdSeek is the WASI function named fdSeekName which moves the offset of a
// fdSeek is the WASI function named FdSeekName which moves the offset of a
// file descriptor.
//
// # Parameters
@@ -936,7 +896,7 @@ var fdRenumber = stubFunction(fdRenumberName, []wasm.ValueType{i32, i32}, "fd",
// See io.Seeker
// and https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_seek
var fdSeek = newHostFunc(
fdSeekName, fdSeekFn,
FdSeekName, fdSeekFn,
[]api.ValueType{i32, i64, i32, i32},
"fd", "offset", "whence", "result.newoffset",
)
@@ -948,7 +908,7 @@ func fdSeekFn(_ context.Context, mod api.Module, params []uint64) Errno {
whence := uint32(params[2])
resultNewoffset := uint32(params[3])
if fd == internalsys.FdRoot {
if fd == sys.FdRoot {
return ErrnoBadf // cannot seek a directory
}
@@ -976,19 +936,19 @@ func fdSeekFn(_ context.Context, mod api.Module, params []uint64) Errno {
return ErrnoSuccess
}
// fdSync is the WASI function named fdSyncName which synchronizes the data
// fdSync is the WASI function named FdSyncName which synchronizes the data
// and metadata of a file to disk.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_syncfd-fd---errno
var fdSync = stubFunction(fdSyncName, []api.ValueType{i32}, "fd")
var fdSync = stubFunction(FdSyncName, []api.ValueType{i32}, "fd")
// fdTell is the WASI function named fdTellName which returns the current
// fdTell is the WASI function named FdTellName which returns the current
// offset of a file descriptor.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_tellfd-fd---errno-filesize
var fdTell = stubFunction(fdTellName, []wasm.ValueType{i32, i32}, "fd", "result.offset")
var fdTell = stubFunction(FdTellName, []wasm.ValueType{i32, i32}, "fd", "result.offset")
// fdWrite is the WASI function named fdWriteName which writes to a file
// fdWrite is the WASI function named FdWriteName which writes to a file
// descriptor.
//
// # Parameters
@@ -1047,7 +1007,7 @@ var fdTell = stubFunction(fdTellName, []wasm.ValueType{i32, i32}, "fd", "result.
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#ciovec
// and https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_write
var fdWrite = newHostFunc(
fdWriteName, fdWriteFn,
FdWriteName, fdWriteFn,
[]api.ValueType{i32, i32, i32, i32},
"fd", "iovs", "iovs_len", "result.nwritten",
)
@@ -1100,17 +1060,17 @@ func fdWriteFn(ctx context.Context, mod api.Module, params []uint64) Errno {
return ErrnoSuccess
}
// pathCreateDirectory is the WASI function named pathCreateDirectoryName
// pathCreateDirectory is the WASI function named PathCreateDirectoryName
// which creates a directory.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_create_directoryfd-fd-path-string---errno
var pathCreateDirectory = stubFunction(
pathCreateDirectoryName,
PathCreateDirectoryName,
[]wasm.ValueType{i32, i32, i32},
"fd", "path", "path_len",
)
// pathFilestatGet is the WASI function named pathFilestatGetName which
// pathFilestatGet is the WASI function named PathFilestatGetName which
// returns the stat attributes of a file or directory.
//
// # Parameters
@@ -1139,7 +1099,7 @@ var pathCreateDirectory = stubFunction(
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_filestat_getfd-fd-flags-lookupflags-path-string---errno-filestat
// and https://linux.die.net/man/2/fstatat
var pathFilestatGet = newHostFunc(
pathFilestatGetName, pathFilestatGetFn,
PathFilestatGetName, pathFilestatGetFn,
[]api.ValueType{i32, i32, i32, i32, i32},
"fd", "flags", "path", "path_len", "result.filestat",
)
@@ -1192,27 +1152,27 @@ func pathFilestatGetFn(_ context.Context, mod api.Module, params []uint64) Errno
return ErrnoSuccess
}
// pathFilestatSetTimes is the WASI function named pathFilestatSetTimesName
// pathFilestatSetTimes is the WASI function named PathFilestatSetTimesName
// which adjusts the timestamps of a file or directory.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_filestat_set_timesfd-fd-flags-lookupflags-path-string-atim-timestamp-mtim-timestamp-fst_flags-fstflags---errno
var pathFilestatSetTimes = stubFunction(
pathFilestatSetTimesName,
PathFilestatSetTimesName,
[]wasm.ValueType{i32, i32, i32, i32, i64, i64, i32},
"fd", "flags", "path", "path_len", "atim", "mtim", "fst_flags",
)
// pathLink is the WASI function named pathLinkName which adjusts the
// pathLink is the WASI function named PathLinkName which adjusts the
// timestamps of a file or directory.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#path_link
var pathLink = stubFunction(
pathLinkName,
PathLinkName,
[]wasm.ValueType{i32, i32, i32, i32, i32, i32, i32},
"old_fd", "old_flags", "old_path", "old_path_len", "new_fd", "new_path", "new_path_len",
)
// pathOpen is the WASI function named pathOpenName which opens a file or
// pathOpen is the WASI function named PathOpenName which opens a file or
// directory. This returns ErrnoBadf if the fd is invalid.
//
// # Parameters
@@ -1266,7 +1226,7 @@ var pathLink = stubFunction(
//
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#path_open
var pathOpen = newHostFunc(
pathOpenName, pathOpenFn,
PathOpenName, pathOpenFn,
[]api.ValueType{i32, i32, i32, i32, i32, i64, i64, i32, i32},
"fd", "dirflags", "path", "path_len", "oflags", "fs_rights_base", "fs_rights_inheriting", "fdflags", "result.opened_fd",
)
@@ -1319,14 +1279,14 @@ func pathOpenFn(_ context.Context, mod api.Module, params []uint64) Errno {
pathName := string(b)
var newFD uint32
var err error
if isDir && oflags&wasi_snapshot_preview1.O_CREAT != 0 {
if isDir && oflags&O_CREAT != 0 {
newFD, err = fsc.Mkdir(pathName, 0o700)
} else {
newFD, err = fsc.OpenFile(pathName, fileOpenFlags, 0o600)
}
if err != nil {
return toErrno(err)
return ToErrno(err)
}
// Check any flags that require the file to evaluate.
@@ -1344,9 +1304,9 @@ func pathOpenFn(_ context.Context, mod api.Module, params []uint64) Errno {
}
func openFlags(oflags, fdflags uint16) (openFlags int, isDir bool) {
isDir = oflags&wasi_snapshot_preview1.O_DIRECTORY != 0
isDir = oflags&O_DIRECTORY != 0
openFlags = os.O_RDONLY
if oflags&wasi_snapshot_preview1.O_CREAT != 0 {
if oflags&O_CREAT != 0 {
if !isDir { // assume read write
openFlags = os.O_RDWR
}
@@ -1355,19 +1315,19 @@ func openFlags(oflags, fdflags uint16) (openFlags int, isDir bool) {
if isDir {
return
}
if oflags&wasi_snapshot_preview1.O_EXCL != 0 {
if oflags&O_EXCL != 0 {
openFlags |= os.O_EXCL
}
if oflags&wasi_snapshot_preview1.O_TRUNC != 0 {
if oflags&O_TRUNC != 0 {
openFlags |= os.O_TRUNC
}
if fdflags&wasi_snapshot_preview1.FD_APPEND != 0 {
if fdflags&FD_APPEND != 0 {
openFlags |= os.O_APPEND
}
return
}
func failIfNotDirectory(fsc *internalsys.FSContext, fd uint32) Errno {
func failIfNotDirectory(fsc *sys.FSContext, fd uint32) Errno {
// Lookup the previous file
if f, ok := fsc.OpenedFile(fd); !ok {
return ErrnoBadf
@@ -1378,86 +1338,61 @@ func failIfNotDirectory(fsc *internalsys.FSContext, fd uint32) Errno {
return ErrnoSuccess
}
// pathReadlink is the WASI function named pathReadlinkName that reads the
// pathReadlink is the WASI function named PathReadlinkName that reads the
// contents of a symbolic link.
//
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_readlinkfd-fd-path-string-buf-pointeru8-buf_len-size---errno-size
var pathReadlink = stubFunction(
pathReadlinkName,
PathReadlinkName,
[]wasm.ValueType{i32, i32, i32, i32, i32, i32},
"fd", "path", "path_len", "buf", "buf_len", "result.bufused",
)
// pathRemoveDirectory is the WASI function named pathRemoveDirectoryName
// pathRemoveDirectory is the WASI function named PathRemoveDirectoryName
// which removes a directory.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_remove_directoryfd-fd-path-string---errno
var pathRemoveDirectory = stubFunction(
pathRemoveDirectoryName,
PathRemoveDirectoryName,
[]wasm.ValueType{i32, i32, i32},
"fd", "path", "path_len",
)
// pathRename is the WASI function named pathRenameName which renames a
// pathRename is the WASI function named PathRenameName which renames a
// file or directory.
var pathRename = stubFunction(
pathRenameName,
PathRenameName,
[]wasm.ValueType{i32, i32, i32, i32, i32, i32},
"fd", "old_path", "old_path_len", "new_fd", "new_path", "new_path_len",
)
// pathSymlink is the WASI function named pathSymlinkName which creates a
// pathSymlink is the WASI function named PathSymlinkName which creates a
// symbolic link.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#path_symlink
var pathSymlink = stubFunction(
pathSymlinkName,
PathSymlinkName,
[]wasm.ValueType{i32, i32, i32, i32, i32},
"old_path", "old_path_len", "fd", "new_path", "new_path_len",
)
// pathUnlinkFile is the WASI function named pathUnlinkFileName which
// pathUnlinkFile is the WASI function named PathUnlinkFileName which
// unlinks a file.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_unlink_filefd-fd-path-string---errno
var pathUnlinkFile = stubFunction(
pathUnlinkFileName,
PathUnlinkFileName,
[]wasm.ValueType{i32, i32, i32},
"fd", "path", "path_len",
)
// statFile attempts to stat the file at the given path. Errors coerce to WASI
// Errno.
func statFile(fsc *internalsys.FSContext, name string) (stat fs.FileInfo, errno Errno) {
func statFile(fsc *sys.FSContext, name string) (stat fs.FileInfo, errno Errno) {
var err error
stat, err = fsc.StatPath(name)
if err != nil {
errno = toErrno(err)
errno = ToErrno(err)
}
return
}
// toErrno coerces the error to a WASI Errno.
//
// Note: Coercion isn't centralized in sys.FSContext because ABI use different
// error codes. For example, wasi-filesystem and GOOS=js don't map to these
// Errno.
func toErrno(err error) Errno {
// handle all the cases of FS.Open or internal to FSContext.OpenFile
switch {
case errors.Is(err, syscall.ENOSYS):
return ErrnoNosys
case errors.Is(err, fs.ErrInvalid):
return ErrnoInval
case errors.Is(err, fs.ErrNotExist):
// fs.FS is allowed to return this instead of ErrInvalid on an invalid path
return ErrnoNoent
case errors.Is(err, fs.ErrExist):
return ErrnoExist
case errors.Is(err, syscall.EBADF):
// fsc.OpenFile currently returns this on out of file descriptors
return ErrnoBadf
default:
return ErrnoIo
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,361 @@
package wasi_snapshot_preview1
import (
"io"
"io/fs"
"testing"
"testing/fstest"
"github.com/tetratelabs/wazero/internal/sys"
"github.com/tetratelabs/wazero/internal/testing/require"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
)
func Test_fdRead_shouldContinueRead(t *testing.T) {
tests := []struct {
name string
n, l uint32
err error
expectedOk bool
expectedErrno Errno
}{
{
name: "break when nothing to read",
n: 0,
l: 0,
},
{
name: "break when nothing read",
n: 0,
l: 4,
},
{
name: "break on partial read",
n: 3,
l: 4,
},
{
name: "continue on full read",
n: 4,
l: 4,
expectedOk: true,
},
{
name: "break on EOF on nothing to read",
err: io.EOF,
},
{
name: "break on EOF on nothing read",
l: 4,
err: io.EOF,
},
{
name: "break on EOF on partial read",
n: 3,
l: 4,
err: io.EOF,
},
{
name: "break on EOF on full read",
n: 4,
l: 4,
err: io.EOF,
},
{
name: "return ErrnoIo on error on nothing to read",
err: io.ErrClosedPipe,
expectedErrno: ErrnoIo,
},
{
name: "return ErrnoIo on error on nothing read",
l: 4,
err: io.ErrClosedPipe,
expectedErrno: ErrnoIo,
},
{ // Special case, allows processing data before err
name: "break on error on partial read",
n: 3,
l: 4,
err: io.ErrClosedPipe,
},
{ // Special case, allows processing data before err
name: "break on error on full read",
n: 4,
l: 4,
err: io.ErrClosedPipe,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
ok, errno := fdRead_shouldContinueRead(tc.n, tc.l, tc.err)
require.Equal(t, tc.expectedOk, ok)
require.Equal(t, tc.expectedErrno, errno)
})
}
}
func Test_lastDirEntries(t *testing.T) {
tests := []struct {
name string
f *sys.ReadDir
cookie int64
expectedEntries []fs.DirEntry
expectedErrno Errno
}{
{
name: "no prior call",
},
{
name: "no prior call, but passed a cookie",
cookie: 1,
expectedErrno: ErrnoInval,
},
{
name: "cookie is negative",
f: &sys.ReadDir{
CountRead: 3,
Entries: testDirEntries,
},
cookie: -1,
expectedErrno: ErrnoInval,
},
{
name: "cookie is greater than last d_next",
f: &sys.ReadDir{
CountRead: 3,
Entries: testDirEntries,
},
cookie: 5,
expectedErrno: ErrnoInval,
},
{
name: "cookie is last pos",
f: &sys.ReadDir{
CountRead: 3,
Entries: testDirEntries,
},
cookie: 3,
expectedEntries: nil,
},
{
name: "cookie is one before last pos",
f: &sys.ReadDir{
CountRead: 3,
Entries: testDirEntries,
},
cookie: 2,
expectedEntries: testDirEntries[2:],
},
{
name: "cookie is before current entries",
f: &sys.ReadDir{
CountRead: 5,
Entries: testDirEntries,
},
cookie: 1,
expectedErrno: ErrnoNosys, // not implemented
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
f := tc.f
if f == nil {
f = &sys.ReadDir{}
}
entries, errno := lastDirEntries(f, tc.cookie)
require.Equal(t, tc.expectedErrno, errno)
require.Equal(t, tc.expectedEntries, entries)
})
}
}
func Test_maxDirents(t *testing.T) {
tests := []struct {
name string
entries []fs.DirEntry
maxLen uint32
expectedCount uint32
expectedwriteTruncatedEntry bool
expectedBufused uint32
}{
{
name: "no entries",
},
{
name: "can't fit one",
entries: testDirEntries,
maxLen: 23,
expectedBufused: 23,
expectedwriteTruncatedEntry: false,
},
{
name: "only fits header",
entries: testDirEntries,
maxLen: 24,
expectedBufused: 24,
expectedwriteTruncatedEntry: true,
},
{
name: "one",
entries: testDirEntries,
maxLen: 25,
expectedCount: 1,
expectedBufused: 25,
},
{
name: "one but not room for two's name",
entries: testDirEntries,
maxLen: 25 + 25,
expectedCount: 1,
expectedwriteTruncatedEntry: true, // can write DirentSize
expectedBufused: 25 + 25,
},
{
name: "two",
entries: testDirEntries,
maxLen: 25 + 26,
expectedCount: 2,
expectedBufused: 25 + 26,
},
{
name: "two but not three's dirent",
entries: testDirEntries,
maxLen: 25 + 26 + 20,
expectedCount: 2,
expectedwriteTruncatedEntry: false, // 20 + 4 == DirentSize
expectedBufused: 25 + 26 + 20,
},
{
name: "two but not three's name",
entries: testDirEntries,
maxLen: 25 + 26 + 26,
expectedCount: 2,
expectedwriteTruncatedEntry: true, // can write DirentSize
expectedBufused: 25 + 26 + 26,
},
{
name: "three",
entries: testDirEntries,
maxLen: 25 + 26 + 27,
expectedCount: 3,
expectedwriteTruncatedEntry: false, // end of dir
expectedBufused: 25 + 26 + 27,
},
{
name: "max",
entries: testDirEntries,
maxLen: 100,
expectedCount: 3,
expectedwriteTruncatedEntry: false, // end of dir
expectedBufused: 25 + 26 + 27,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
bufused, direntCount, writeTruncatedEntry := maxDirents(tc.entries, tc.maxLen)
require.Equal(t, tc.expectedCount, direntCount)
require.Equal(t, tc.expectedwriteTruncatedEntry, writeTruncatedEntry)
require.Equal(t, tc.expectedBufused, bufused)
})
}
}
var (
fdReadDirFs = fstest.MapFS{
"notdir": {},
"emptydir": {Mode: fs.ModeDir},
"dir": {Mode: fs.ModeDir},
"dir/-": {}, // len = 24+1 = 25
"dir/a-": {Mode: fs.ModeDir}, // len = 24+2 = 26
"dir/ab-": {}, // len = 24+3 = 27
}
testDirEntries = func() []fs.DirEntry {
entries, err := fdReadDirFs.ReadDir("dir")
if err != nil {
panic(err)
}
return entries
}()
dirent1 = []byte{
1, 0, 0, 0, 0, 0, 0, 0, // d_next = 1
0, 0, 0, 0, 0, 0, 0, 0, // d_ino = 0
1, 0, 0, 0, // d_namlen = 1 character
4, 0, 0, 0, // d_type = regular_file
'-', // name
}
dirent2 = []byte{
2, 0, 0, 0, 0, 0, 0, 0, // d_next = 2
0, 0, 0, 0, 0, 0, 0, 0, // d_ino = 0
2, 0, 0, 0, // d_namlen = 1 character
3, 0, 0, 0, // d_type = directory
'a', '-', // name
}
dirent3 = []byte{
3, 0, 0, 0, 0, 0, 0, 0, // d_next = 3
0, 0, 0, 0, 0, 0, 0, 0, // d_ino = 0
3, 0, 0, 0, // d_namlen = 3 characters
4, 0, 0, 0, // d_type = regular_file
'a', 'b', '-', // name
}
)
func Test_writeDirents(t *testing.T) {
tests := []struct {
name string
entries []fs.DirEntry
entryCount uint32
writeTruncatedEntry bool
expectedEntriesBuf []byte
}{
{
name: "none",
entries: testDirEntries,
},
{
name: "one",
entries: testDirEntries,
entryCount: 1,
expectedEntriesBuf: dirent1,
},
{
name: "two",
entries: testDirEntries,
entryCount: 2,
expectedEntriesBuf: append(dirent1, dirent2...),
},
{
name: "two with truncated",
entries: testDirEntries,
entryCount: 2,
writeTruncatedEntry: true,
expectedEntriesBuf: append(append(dirent1, dirent2...), dirent3[0:10]...),
},
{
name: "three",
entries: testDirEntries,
entryCount: 3,
expectedEntriesBuf: append(append(dirent1, dirent2...), dirent3...),
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
cookie := uint64(1)
entriesBuf := make([]byte, len(tc.expectedEntriesBuf))
writeDirents(tc.entries, tc.entryCount, tc.writeTruncatedEntry, entriesBuf, cookie)
require.Equal(t, tc.expectedEntriesBuf, entriesBuf)
})
}
}

View File

@@ -4,22 +4,11 @@ import (
"context"
"github.com/tetratelabs/wazero/api"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/wasm"
)
const pollOneoffName = "poll_oneoff"
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-eventtype-enumu8
const (
// eventTypeClock is the timeout event named "name".
eventTypeClock = iota
// eventTypeFdRead is the data available event named "fd_read".
eventTypeFdRead
// eventTypeFdWrite is the capacity available event named "fd_write".
eventTypeFdWrite
)
// pollOneoff is the WASI function named pollOneoffName that concurrently
// pollOneoff is the WASI function named PollOneoffName that concurrently
// polls for the occurrence of a set of events.
//
// # Parameters
@@ -46,7 +35,7 @@ const (
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#poll_oneoff
// See https://linux.die.net/man/3/poll
var pollOneoff = newHostFunc(
pollOneoffName, pollOneoffFn,
PollOneoffName, pollOneoffFn,
[]api.ValueType{i32, i32, i32, i32},
"in", "out", "nsubscriptions", "result.nevents",
)
@@ -87,10 +76,10 @@ func pollOneoffFn(ctx context.Context, mod api.Module, params []uint64) Errno {
eventType := inBuf[inOffset+8] // +8 past userdata
var errno Errno // errno for this specific event
switch eventType {
case eventTypeClock: // handle later
case EventTypeClock: // handle later
// +8 past userdata +8 name alignment
errno = processClockEvent(ctx, mod, inBuf[inOffset+8+8:])
case eventTypeFdRead, eventTypeFdWrite:
case EventTypeFdRead, EventTypeFdWrite:
// +8 past userdata +4 FD alignment
errno = processFDEvent(mod, eventType, inBuf[inOffset+8+4:])
default:
@@ -110,7 +99,7 @@ func pollOneoffFn(ctx context.Context, mod api.Module, params []uint64) Errno {
// processClockEvent supports only relative name events, as that's what's used
// to implement sleep in various compilers including Rust, Zig and TinyGo.
func processClockEvent(ctx context.Context, mod api.Module, inBuf []byte) Errno {
func processClockEvent(_ context.Context, mod api.Module, inBuf []byte) Errno {
_ /* ID */ = le.Uint32(inBuf[0:8]) // See below
timeout := le.Uint64(inBuf[8:16]) // nanos if relative
_ /* precision */ = le.Uint64(inBuf[16:24]) // Unused
@@ -143,9 +132,9 @@ func processFDEvent(mod api.Module, eventType byte, inBuf []byte) Errno {
// Choose the best error, which falls back to unsupported, until we support
// files.
errno := ErrnoNotsup
if eventType == eventTypeFdRead && fsc.FdReader(fd) == nil {
if eventType == EventTypeFdRead && fsc.FdReader(fd) == nil {
errno = ErrnoBadf
} else if eventType == eventTypeFdWrite && fsc.FdWriter(fd) == nil {
} else if eventType == EventTypeFdWrite && fsc.FdWriter(fd) == nil {
errno = ErrnoBadf
}

View File

@@ -1,11 +1,12 @@
package wasi_snapshot_preview1
package wasi_snapshot_preview1_test
import (
"testing"
"github.com/tetratelabs/wazero"
internalsys "github.com/tetratelabs/wazero/internal/sys"
"github.com/tetratelabs/wazero/internal/sys"
"github.com/tetratelabs/wazero/internal/testing/require"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/wasm"
)
@@ -15,8 +16,8 @@ func Test_pollOneoff(t *testing.T) {
mem := []byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
eventTypeClock, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // event type and padding
clockIDMonotonic, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // clockID
EventTypeClock, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // event type and padding
ClockIDMonotonic, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // clockID
0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // timeout (ns)
0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // precision (ns)
0x00, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // flags (relative)
@@ -26,7 +27,7 @@ func Test_pollOneoff(t *testing.T) {
expectedMem := []byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
byte(ErrnoSuccess), 0x0, // errno is 16 bit
eventTypeClock, 0x0, 0x0, 0x0, // 4 bytes for type enum
EventTypeClock, 0x0, 0x0, 0x0, // 4 bytes for type enum
'?', // stopped after encoding
}
@@ -38,7 +39,7 @@ func Test_pollOneoff(t *testing.T) {
maskMemory(t, mod, 1024)
mod.Memory().Write(in, mem)
requireErrno(t, ErrnoSuccess, mod, pollOneoffName, uint64(in), uint64(out), uint64(nsubscriptions),
requireErrno(t, ErrnoSuccess, mod, PollOneoffName, uint64(in), uint64(out), uint64(nsubscriptions),
uint64(resultNevents))
require.Equal(t, `
==> wasi_snapshot_preview1.poll_oneoff(in=0,out=128,nsubscriptions=1,result.nevents=512)
@@ -110,12 +111,12 @@ func Test_pollOneoff_Errors(t *testing.T) {
`,
},
{
name: "unsupported eventTypeFdRead",
name: "unsupported EventTypeFdRead",
nsubscriptions: 1,
mem: []byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
eventTypeFdRead, 0x0, 0x0, 0x0,
byte(internalsys.FdStdin), 0x0, 0x0, 0x0, // valid readable FD
EventTypeFdRead, 0x0, 0x0, 0x0,
byte(sys.FdStdin), 0x0, 0x0, 0x0, // valid readable FD
'?', // stopped after encoding
},
expectedErrno: ErrnoSuccess,
@@ -124,7 +125,7 @@ func Test_pollOneoff_Errors(t *testing.T) {
expectedMem: []byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
byte(ErrnoNotsup), 0x0, // errno is 16 bit
eventTypeFdRead, 0x0, 0x0, 0x0, // 4 bytes for type enum
EventTypeFdRead, 0x0, 0x0, 0x0, // 4 bytes for type enum
'?', // stopped after encoding
},
expectedLog: `
@@ -145,7 +146,7 @@ func Test_pollOneoff_Errors(t *testing.T) {
mod.Memory().Write(tc.in, tc.mem)
}
requireErrno(t, tc.expectedErrno, mod, pollOneoffName, uint64(tc.in), uint64(tc.out),
requireErrno(t, tc.expectedErrno, mod, PollOneoffName, uint64(tc.in), uint64(tc.out),
uint64(tc.nsubscriptions), uint64(tc.resultNevents))
require.Equal(t, tc.expectedLog, "\n"+log.String())

View File

@@ -4,16 +4,12 @@ import (
"context"
"github.com/tetratelabs/wazero/api"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/wasm"
"github.com/tetratelabs/wazero/sys"
)
const (
procExitName = "proc_exit"
procRaiseName = "proc_raise"
)
// procExit is the WASI function named procExitName that terminates the
// procExit is the WASI function named ProcExitName that terminates the
// execution of the module with an exit code. The only successful exit code is
// zero.
//
@@ -23,8 +19,8 @@ const (
//
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#proc_exit
var procExit = &wasm.HostFunc{
ExportNames: []string{procExitName},
Name: procExitName,
ExportNames: []string{ProcExitName},
Name: ProcExitName,
ParamTypes: []api.ValueType{i32},
ParamNames: []string{"rval"},
Code: &wasm.Code{
@@ -48,4 +44,4 @@ func procExitFn(ctx context.Context, mod api.Module, params []uint64) {
// procRaise is stubbed and will never be supported, as it was removed.
//
// See https://github.com/WebAssembly/WASI/pull/136
var procRaise = stubFunction(procRaiseName, []api.ValueType{i32}, "sig")
var procRaise = stubFunction(ProcRaiseName, []api.ValueType{i32}, "sig")

View File

@@ -1,10 +1,11 @@
package wasi_snapshot_preview1
package wasi_snapshot_preview1_test
import (
"testing"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/internal/testing/require"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/sys"
)
@@ -40,7 +41,7 @@ func Test_procExit(t *testing.T) {
defer log.Reset()
// Since procExit panics, any opcodes afterwards cannot be reached.
_, err := mod.ExportedFunction(procExitName).Call(testCtx, uint64(tc.exitCode))
_, err := mod.ExportedFunction(ProcExitName).Call(testCtx, uint64(tc.exitCode))
require.Error(t, err)
sysErr, ok := err.(*sys.ExitError)
require.True(t, ok, err)
@@ -52,7 +53,7 @@ func Test_procExit(t *testing.T) {
// Test_procRaise only tests it is stubbed for GrainLang per #271
func Test_procRaise(t *testing.T) {
log := requireErrnoNosys(t, procRaiseName, 0)
log := requireErrnoNosys(t, ProcRaiseName, 0)
require.Equal(t, `
--> wasi_snapshot_preview1.proc_raise(sig=0)
<-- errno=ENOSYS

View File

@@ -5,12 +5,11 @@ import (
"io"
"github.com/tetratelabs/wazero/api"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/wasm"
)
const randomGetName = "random_get"
// randomGet is the WASI function named randomGetName which writes random
// randomGet is the WASI function named RandomGetName which writes random
// data to a buffer.
//
// # Parameters
@@ -34,7 +33,7 @@ const randomGetName = "random_get"
// buf --^
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-bufLen-size---errno
var randomGet = newHostFunc(randomGetName, randomGetFn, []api.ValueType{i32, i32}, "buf", "buf_len")
var randomGet = newHostFunc(RandomGetName, randomGetFn, []api.ValueType{i32, i32}, "buf", "buf_len")
func randomGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
sysCtx := mod.(*wasm.CallContext).Sys

View File

@@ -1,4 +1,4 @@
package wasi_snapshot_preview1
package wasi_snapshot_preview1_test
import (
"bytes"
@@ -9,6 +9,7 @@ import (
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/internal/testing/require"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
)
func Test_randomGet(t *testing.T) {
@@ -27,7 +28,7 @@ func Test_randomGet(t *testing.T) {
maskMemory(t, mod, len(expectedMemory))
// Invoke randomGet and check the memory side effects!
requireErrno(t, ErrnoSuccess, mod, randomGetName, uint64(offset), uint64(length))
requireErrno(t, ErrnoSuccess, mod, RandomGetName, uint64(offset), uint64(length))
require.Equal(t, `
==> wasi_snapshot_preview1.random_get(buf=1,buf_len=5)
<== errno=ESUCCESS
@@ -75,7 +76,7 @@ func Test_randomGet_Errors(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
defer log.Reset()
requireErrno(t, ErrnoFault, mod, randomGetName, uint64(tc.offset), uint64(tc.length))
requireErrno(t, ErrnoFault, mod, RandomGetName, uint64(tc.offset), uint64(tc.length))
require.Equal(t, tc.expectedLog, "\n"+log.String())
})
}
@@ -112,7 +113,7 @@ func Test_randomGet_SourceError(t *testing.T) {
WithRandSource(tc.randSource))
defer r.Close(testCtx)
requireErrno(t, ErrnoIo, mod, randomGetName, uint64(1), uint64(5)) // arbitrary offset and length
requireErrno(t, ErrnoIo, mod, RandomGetName, uint64(1), uint64(5)) // arbitrary offset and length
require.Equal(t, tc.expectedLog, "\n"+log.String())
})
}

View File

@@ -1,9 +1,11 @@
package wasi_snapshot_preview1
const schedYieldName = "sched_yield"
import (
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
)
// schedYield is the WASI function named schedYieldName which temporarily
// schedYield is the WASI function named SchedYieldName which temporarily
// yields execution of the calling thread.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sched_yield---errno
var schedYield = stubFunction(schedYieldName, nil)
var schedYield = stubFunction(SchedYieldName, nil)

View File

@@ -1,14 +1,15 @@
package wasi_snapshot_preview1
package wasi_snapshot_preview1_test
import (
"testing"
"github.com/tetratelabs/wazero/internal/testing/require"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
)
// Test_schedYield only tests it is stubbed for GrainLang per #271
func Test_schedYield(t *testing.T) {
log := requireErrnoNosys(t, schedYieldName)
log := requireErrnoNosys(t, SchedYieldName)
require.Equal(t, `
--> wasi_snapshot_preview1.sched_yield()
<-- errno=ENOSYS

View File

@@ -1,47 +1,43 @@
package wasi_snapshot_preview1
import "github.com/tetratelabs/wazero/internal/wasm"
const (
sockAcceptName = "sock_accept"
sockRecvName = "sock_recv"
sockSendName = "sock_send"
sockShutdownName = "sock_shutdown"
import (
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/wasm"
)
// sockAccept is the WASI function named sockAcceptName which accepts a new
// sockAccept is the WASI function named SockAcceptName which accepts a new
// incoming connection.
//
// See: https://github.com/WebAssembly/WASI/blob/0ba0c5e2e37625ca5a6d3e4255a998dfaa3efc52/phases/snapshot/docs.md#sock_accept
// and https://github.com/WebAssembly/WASI/pull/458
var sockAccept = stubFunction(
sockAcceptName,
SockAcceptName,
[]wasm.ValueType{i32, i32, i32},
"fd", "flags", "result.fd",
)
// sockRecv is the WASI function named sockRecvName which receives a
// sockRecv is the WASI function named SockRecvName which receives a
// message from a socket.
//
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_recvfd-fd-ri_data-iovec_array-ri_flags-riflags---errno-size-roflags
var sockRecv = stubFunction(
sockRecvName,
SockRecvName,
[]wasm.ValueType{i32, i32, i32, i32, i32, i32},
"fd", "ri_data", "ri_data_count", "ri_flags", "result.ro_datalen", "result.ro_flags",
)
// sockSend is the WASI function named sockSendName which sends a message
// sockSend is the WASI function named SockSendName which sends a message
// on a socket.
//
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_sendfd-fd-si_data-ciovec_array-si_flags-siflags---errno-size
var sockSend = stubFunction(
sockSendName,
SockSendName,
[]wasm.ValueType{i32, i32, i32, i32, i32},
"fd", "si_data", "si_data_count", "si_flags", "result.so_datalen",
)
// sockShutdown is the WASI function named sockShutdownName which shuts
// sockShutdown is the WASI function named SockShutdownName which shuts
// down socket send and receive channels.
//
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_shutdownfd-fd-how-sdflags---errno
var sockShutdown = stubFunction(sockShutdownName, []wasm.ValueType{i32, i32}, "fd", "how")
var sockShutdown = stubFunction(SockShutdownName, []wasm.ValueType{i32, i32}, "fd", "how")

View File

@@ -1,14 +1,15 @@
package wasi_snapshot_preview1
package wasi_snapshot_preview1_test
import (
"testing"
"github.com/tetratelabs/wazero/internal/testing/require"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
)
// Test_sockAccept only tests it is stubbed for GrainLang per #271
func Test_sockAccept(t *testing.T) {
log := requireErrnoNosys(t, sockAcceptName, 0, 0, 0)
log := requireErrnoNosys(t, SockAcceptName, 0, 0, 0)
require.Equal(t, `
--> wasi_snapshot_preview1.sock_accept(fd=0,flags=0,result.fd=0)
<-- errno=ENOSYS
@@ -17,7 +18,7 @@ func Test_sockAccept(t *testing.T) {
// Test_sockRecv only tests it is stubbed for GrainLang per #271
func Test_sockRecv(t *testing.T) {
log := requireErrnoNosys(t, sockRecvName, 0, 0, 0, 0, 0, 0)
log := requireErrnoNosys(t, SockRecvName, 0, 0, 0, 0, 0, 0)
require.Equal(t, `
--> wasi_snapshot_preview1.sock_recv(fd=0,ri_data=0,ri_data_count=0,ri_flags=0,result.ro_datalen=0,result.ro_flags=0)
<-- errno=ENOSYS
@@ -26,7 +27,7 @@ func Test_sockRecv(t *testing.T) {
// Test_sockSend only tests it is stubbed for GrainLang per #271
func Test_sockSend(t *testing.T) {
log := requireErrnoNosys(t, sockSendName, 0, 0, 0, 0, 0)
log := requireErrnoNosys(t, SockSendName, 0, 0, 0, 0, 0)
require.Equal(t, `
--> wasi_snapshot_preview1.sock_send(fd=0,si_data=0,si_data_count=0,si_flags=0,result.so_datalen=0)
<-- errno=ENOSYS
@@ -35,7 +36,7 @@ func Test_sockSend(t *testing.T) {
// Test_sockShutdown only tests it is stubbed for GrainLang per #271
func Test_sockShutdown(t *testing.T) {
log := requireErrnoNosys(t, sockShutdownName, 0, 0)
log := requireErrnoNosys(t, SockShutdownName, 0, 0)
require.Equal(t, `
--> wasi_snapshot_preview1.sock_shutdown(fd=0,how=0)
<-- errno=ENOSYS

View File

@@ -22,17 +22,16 @@ import (
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/wasm"
)
// ModuleName is the module name WASI functions are exported into.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md
const (
ModuleName = wasi_snapshot_preview1.ModuleName
i32, i64 = wasm.ValueTypeI32, wasm.ValueTypeI64
)
const ModuleName = InternalModuleName
const i32, i64 = wasm.ValueTypeI32, wasm.ValueTypeI64
var le = binary.LittleEndian

View File

@@ -1,4 +1,4 @@
package wasi_snapshot_preview1
package wasi_snapshot_preview1_test
import (
"embed"
@@ -8,8 +8,10 @@ import (
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/sys"
"github.com/tetratelabs/wazero/internal/testing/proxy"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/wasm"
)
@@ -30,10 +32,10 @@ func Benchmark_ArgsEnviron(b *testing.B) {
}
for _, n := range []string{
argsGetName,
argsSizesGetName,
environGetName,
environSizesGetName,
ArgsGetName,
ArgsSizesGetName,
EnvironGetName,
EnvironSizesGetName,
} {
n := n
fn := mod.ExportedFunction(n)
@@ -69,7 +71,7 @@ func Benchmark_fdRead(b *testing.B) {
if err != nil {
b.Fatal(err)
}
fn := mod.ExportedFunction(fdReadName)
fn := mod.ExportedFunction(FdReadName)
mod.Memory().Write(0, []byte{
32, 0, 0, 0, // = iovs[0].offset
@@ -168,7 +170,7 @@ func Benchmark_fdReaddir(b *testing.B) {
b.Fatal(err)
}
fn := mod.ExportedFunction(fdReaddirName)
fn := mod.ExportedFunction(FdReaddirName)
// Open the root directory as a file-descriptor.
fsc := mod.(*wasm.CallContext).Sys.FS()
@@ -285,7 +287,7 @@ func Benchmark_pathFilestat(b *testing.B) {
defer fsc.CloseFile(fd)
}
fn := mod.ExportedFunction(pathFilestatGetName)
fn := mod.ExportedFunction(PathFilestatGetName)
b.ResetTimer()
b.ReportAllocs()
@@ -338,7 +340,7 @@ func Benchmark_fdWrite(b *testing.B) {
if err != nil {
b.Fatal(err)
}
fn := mod.ExportedFunction(fdWriteName)
fn := mod.ExportedFunction(FdWriteName)
iovs := uint32(1) // arbitrary offset
mod.Memory().Write(0, []byte{
@@ -389,7 +391,7 @@ func Benchmark_fdWrite(b *testing.B) {
// instantiateProxyModule instantiates a guest that re-exports WASI functions.
func instantiateProxyModule(r wazero.Runtime, config wazero.ModuleConfig) (api.Module, error) {
wasiModuleCompiled, err := (&builder{r}).hostModuleBuilder().Compile(testCtx)
wasiModuleCompiled, err := wasi_snapshot_preview1.NewBuilder(r).Compile(testCtx)
if err != nil {
return nil, err
}
@@ -398,7 +400,7 @@ func instantiateProxyModule(r wazero.Runtime, config wazero.ModuleConfig) (api.M
return nil, err
}
proxyBin := proxy.NewModuleBinary(ModuleName, wasiModuleCompiled)
proxyBin := proxy.NewModuleBinary(wasi_snapshot_preview1.ModuleName, wasiModuleCompiled)
proxyCompiled, err := r.CompileModule(testCtx, proxyBin)
if err != nil {

View File

@@ -1,6 +1,4 @@
// package wasi_snapshot_preview1 ensures that the behavior we've implemented
// not only matches the wasi spec, but also at least two compilers use of sdks.
package wasi_snapshot_preview1
package wasi_snapshot_preview1_test
import (
"bytes"
@@ -12,10 +10,14 @@ import (
"testing/fstest"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/testing/require"
"github.com/tetratelabs/wazero/sys"
)
// This file ensures that the behavior we've implemented not only the wasi
// spec, but also at least two compilers use of sdks.
// wasmCargoWasi was compiled from testdata/cargo-wasi/wasi.rs
//
//go:embed testdata/cargo-wasi/wasi.wasm
@@ -126,7 +128,7 @@ func compileAndRun(t *testing.T, config wazero.ModuleConfig, bin []byte) (consol
r := wazero.NewRuntime(testCtx)
defer r.Close(testCtx)
_, err := Instantiate(testCtx, r)
_, err := wasi_snapshot_preview1.Instantiate(testCtx, r)
require.NoError(t, err)
compiled, err := r.CompileModule(testCtx, bin)

View File

@@ -1,4 +1,4 @@
package wasi_snapshot_preview1
package wasi_snapshot_preview1_test
import (
"bytes"
@@ -9,8 +9,10 @@ import (
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
. "github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/testing/proxy"
"github.com/tetratelabs/wazero/internal/testing/require"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/sys"
)
@@ -34,7 +36,7 @@ func TestNewFunctionExporter(t *testing.T) {
// Instantiate the current WASI functions under the wasi_unstable
// instead of wasi_snapshot_preview1.
wasiBuilder := r.NewHostModuleBuilder("wasi_unstable")
NewFunctionExporter().ExportFunctions(wasiBuilder)
wasi_snapshot_preview1.NewFunctionExporter().ExportFunctions(wasiBuilder)
_, err := wasiBuilder.Instantiate(testCtx, r)
require.NoError(t, err)
@@ -50,8 +52,8 @@ func TestNewFunctionExporter(t *testing.T) {
defer r.Close(testCtx)
// Export the default WASI functions
wasiBuilder := r.NewHostModuleBuilder(ModuleName)
NewFunctionExporter().ExportFunctions(wasiBuilder)
wasiBuilder := r.NewHostModuleBuilder(wasi_snapshot_preview1.ModuleName)
wasi_snapshot_preview1.NewFunctionExporter().ExportFunctions(wasiBuilder)
// Override proc_exit to prove the point that you can add or replace
// functions like this.
@@ -88,13 +90,13 @@ func requireProxyModule(t *testing.T, config wazero.ModuleConfig) (api.Module, a
r := wazero.NewRuntime(ctx)
wasiModuleCompiled, err := (&builder{r}).hostModuleBuilder().Compile(ctx)
wasiModuleCompiled, err := wasi_snapshot_preview1.NewBuilder(r).Compile(ctx)
require.NoError(t, err)
_, err = r.InstantiateModule(ctx, wasiModuleCompiled, config)
require.NoError(t, err)
proxyBin := proxy.NewModuleBinary(ModuleName, wasiModuleCompiled)
proxyBin := proxy.NewModuleBinary(wasi_snapshot_preview1.ModuleName, wasiModuleCompiled)
proxyCompiled, err := r.CompileModule(ctx, proxyBin)
require.NoError(t, err)
@@ -118,13 +120,13 @@ func requireErrnoNosys(t *testing.T, funcName string, params ...uint64) string {
defer r.Close(ctx)
// Instantiate the wasi module.
wasiModuleCompiled, err := (&builder{r}).hostModuleBuilder().Compile(ctx)
wasiModuleCompiled, err := wasi_snapshot_preview1.NewBuilder(r).Compile(ctx)
require.NoError(t, err)
_, err = r.InstantiateModule(ctx, wasiModuleCompiled, wazero.NewModuleConfig())
require.NoError(t, err)
proxyBin := proxy.NewModuleBinary(ModuleName, wasiModuleCompiled)
proxyBin := proxy.NewModuleBinary(wasi_snapshot_preview1.ModuleName, wasiModuleCompiled)
proxyCompiled, err := r.CompileModule(ctx, proxyBin)
require.NoError(t, err)

View File

@@ -14,6 +14,7 @@ import (
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/internal/testing/require"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
)
var testCtx = context.Background()
@@ -64,7 +65,7 @@ func (fs *wasiFs) Open(name string) (fs.File, error) {
uint64(fd), uint64(dirflags), uint64(pathPtr), uint64(pathLen), uint64(oflags),
fsRightsBase, fsRightsInheriting, uint64(fdflags), uint64(resultOpenedFd))
require.NoError(fs.t, err)
require.Equal(fs.t, uint64(wasi_snapshot_preview1.ErrnoSuccess), res[0])
require.Equal(fs.t, uint64(ErrnoSuccess), res[0])
resFd, ok := fs.memory.ReadUint32Le(resultOpenedFd)
require.True(fs.t, ok)
@@ -105,7 +106,7 @@ func (f *wasiFile) Read(bytes []byte) (int, error) {
res, err := f.fs.fdRead.Call(testCtx, uint64(f.fd), uint64(iovsOff), uint64(iovsCount), uint64(resultSizeOff))
require.NoError(f.fs.t, err)
require.NotEqual(f.fs.t, uint64(wasi_snapshot_preview1.ErrnoFault), res[0])
require.NotEqual(f.fs.t, uint64(ErrnoFault), res[0])
numRead, ok := f.fs.memory.ReadUint32Le(resultSizeOff)
require.True(f.fs.t, ok)
@@ -114,7 +115,7 @@ func (f *wasiFile) Read(bytes []byte) (int, error) {
if len(bytes) == 0 {
return 0, nil
}
if wasi_snapshot_preview1.Errno(res[0]) == wasi_snapshot_preview1.ErrnoSuccess {
if Errno(res[0]) == ErrnoSuccess {
return 0, io.EOF
} else {
return 0, fmt.Errorf("could not read from file")
@@ -130,7 +131,7 @@ func (f *wasiFile) Read(bytes []byte) (int, error) {
func (f *wasiFile) Close() error {
res, err := f.fs.fdClose.Call(testCtx, uint64(f.fd))
require.NoError(f.fs.t, err)
require.NotEqual(f.fs.t, uint64(wasi_snapshot_preview1.ErrnoFault), res[0])
require.NotEqual(f.fs.t, uint64(ErrnoFault), res[0])
return nil
}
@@ -140,7 +141,7 @@ func (f *wasiFile) Seek(offset int64, whence int) (int64, error) {
res, err := f.fs.fdSeek.Call(testCtx, uint64(f.fd), uint64(offset), uint64(whence), uint64(resultNewoffsetOff))
require.NoError(f.fs.t, err)
require.NotEqual(f.fs.t, uint64(wasi_snapshot_preview1.ErrnoFault), res[0])
require.NotEqual(f.fs.t, uint64(ErrnoFault), res[0])
newOffset, ok := f.fs.memory.ReadUint32Le(resultNewoffsetOff)
require.True(f.fs.t, ok)

View File

@@ -0,0 +1,6 @@
package wasi_snapshot_preview1
const (
ArgsGetName = "args_get"
ArgsSizesGetName = "args_sizes_get"
)

View File

@@ -0,0 +1,16 @@
package wasi_snapshot_preview1
const (
ClockResGetName = "clock_res_get"
ClockTimeGetName = "clock_time_get"
)
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clockid-enumu32
const (
// ClockIDRealtime is the name ID named "realtime" like sys.Walltime
ClockIDRealtime = iota
// ClockIDMonotonic is the name ID named "monotonic" like sys.Nanotime
ClockIDMonotonic
// Note: clockIDProcessCputime and clockIDThreadCputime were removed by
// WASI maintainers: https://github.com/WebAssembly/wasi-libc/pull/294
)

View File

@@ -0,0 +1,6 @@
package wasi_snapshot_preview1
const (
EnvironGetName = "environ_get"
EnvironSizesGetName = "environ_sizes_get"
)

View File

@@ -1,24 +1,22 @@
package wasi_snapshot_preview1
import (
internalwasi "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
"errors"
"fmt"
"io/fs"
"syscall"
)
// Errno are the error codes returned by WASI functions.
//
// # Notes
//
// - This is not always an error, as ErrnoSuccess is a valid code.
// - Codes are defined even when not relevant to WASI for use in higher-level
// libraries or alignment with POSIX.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-errno-enumu16 and
// https://linux.die.net/man/3/errno
type Errno = uint32 // neither uint16 nor an alias for parity with wasm.ValueType
// Errno is neither uint16 nor an alias for parity with wasm.ValueType.
type Errno = uint32
// ErrnoName returns the POSIX error code name, except ErrnoSuccess, which is not an error. e.g. Errno2big -> "E2BIG"
func ErrnoName(errno Errno) string {
return internalwasi.ErrnoName(errno)
// ErrnoName returns the POSIX error code name, except ErrnoSuccess, which is
// not an error. e.g. Errno2big -> "E2BIG"
func ErrnoName(errno uint32) string {
if int(errno) < len(errnoToString) {
return errnoToString[errno]
}
return fmt.Sprintf("errno(%d)", errno)
}
// Note: Below prefers POSIX symbol names over WASI ones, even if the docs are from WASI.
@@ -181,3 +179,108 @@ const (
// Note: ErrnoNotcapable was removed by WASI maintainers.
// See https://github.com/WebAssembly/wasi-libc/pull/294
)
var errnoToString = [...]string{
"ESUCCESS",
"E2BIG",
"EACCES",
"EADDRINUSE",
"EADDRNOTAVAIL",
"EAFNOSUPPORT",
"EAGAIN",
"EALREADY",
"EBADF",
"EBADMSG",
"EBUSY",
"ECANCELED",
"ECHILD",
"ECONNABORTED",
"ECONNREFUSED",
"ECONNRESET",
"EDEADLK",
"EDESTADDRREQ",
"EDOM",
"EDQUOT",
"EEXIST",
"EFAULT",
"EFBIG",
"EHOSTUNREACH",
"EIDRM",
"EILSEQ",
"EINPROGRESS",
"EINTR",
"EINVAL",
"EIO",
"EISCONN",
"EISDIR",
"ELOOP",
"EMFILE",
"EMLINK",
"EMSGSIZE",
"EMULTIHOP",
"ENAMETOOLONG",
"ENETDOWN",
"ENETRESET",
"ENETUNREACH",
"ENFILE",
"ENOBUFS",
"ENODEV",
"ENOENT",
"ENOEXEC",
"ENOLCK",
"ENOLINK",
"ENOMEM",
"ENOMSG",
"ENOPROTOOPT",
"ENOSPC",
"ENOSYS",
"ENOTCONN",
"ENOTDIR",
"ENOTEMPTY",
"ENOTRECOVERABLE",
"ENOTSOCK",
"ENOTSUP",
"ENOTTY",
"ENXIO",
"EOVERFLOW",
"EOWNERDEAD",
"EPERM",
"EPIPE",
"EPROTO",
"EPROTONOSUPPORT",
"EPROTOTYPE",
"ERANGE",
"EROFS",
"ESPIPE",
"ESRCH",
"ESTALE",
"ETIMEDOUT",
"ETXTBSY",
"EXDEV",
"ENOTCAPABLE",
}
// ToErrno coerces the error to a WASI Errno.
//
// Note: Coercion isn't centralized in sys.FSContext because ABI use different
// error codes. For example, wasi-filesystem and GOOS=js don't map to these
// Errno.
func ToErrno(err error) Errno {
// handle all the cases of FS.Open or wasi_snapshot_preview1 to FSContext.OpenFile
switch {
case errors.Is(err, syscall.ENOSYS):
return ErrnoNosys
case errors.Is(err, fs.ErrInvalid):
return ErrnoInval
case errors.Is(err, fs.ErrNotExist):
// fs.FS is allowed to return this instead of ErrInvalid on an invalid path
return ErrnoNoent
case errors.Is(err, fs.ErrExist):
return ErrnoExist
case errors.Is(err, syscall.EBADF):
// fsc.OpenFile currently returns this on out of file descriptors
return ErrnoBadf
default:
return ErrnoIo
}
}

View File

@@ -0,0 +1,135 @@
package wasi_snapshot_preview1
import (
"fmt"
)
const (
FdAdviseName = "fd_advise"
FdAllocateName = "fd_allocate"
FdCloseName = "fd_close"
FdDatasyncName = "fd_datasync"
FdFdstatGetName = "fd_fdstat_get"
FdFdstatSetFlagsName = "fd_fdstat_set_flags"
FdFdstatSetRightsName = "fd_fdstat_set_rights"
FdFilestatGetName = "fd_filestat_get"
FdFilestatSetSizeName = "fd_filestat_set_size"
FdFilestatSetTimesName = "fd_filestat_set_times"
FdPreadName = "fd_pread"
FdPrestatGetName = "fd_prestat_get"
FdPrestatDirNameName = "fd_prestat_dir_name"
FdPwriteName = "fd_pwrite"
FdReadName = "fd_read"
FdReaddirName = "fd_readdir"
FdRenumberName = "fd_renumber"
FdSeekName = "fd_seek"
FdSyncName = "fd_sync"
FdTellName = "fd_tell"
FdWriteName = "fd_write"
PathCreateDirectoryName = "path_create_directory"
PathFilestatGetName = "path_filestat_get"
PathFilestatSetTimesName = "path_filestat_set_times"
PathLinkName = "path_link"
PathOpenName = "path_open"
PathReadlinkName = "path_readlink"
PathRemoveDirectoryName = "path_remove_directory"
PathRenameName = "path_rename"
PathSymlinkName = "path_symlink"
PathUnlinkFileName = "path_unlink_file"
)
// oflags are open flags used by path_open
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-oflags-flagsu16
const (
// O_CREAT creates a file if it does not exist.
O_CREAT uint16 = 1 << iota //nolint
// O_DIRECTORY fails if not a directory.
O_DIRECTORY
// O_EXCL fails if file already exists.
O_EXCL //nolint
// O_TRUNC truncates the file to size 0.
O_TRUNC //nolint
)
func OflagsString(oflags int) string {
return flagsString(oflagNames[:], oflags)
}
var oflagNames = [...]string{
"CREAT",
"DIRECTORY",
"EXCL",
"TRUNC",
}
// file descriptor flags
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fdflags
const (
FD_APPEND uint16 = 1 << iota //nolint
FD_DSYNC
FD_NONBLOCK
FD_RSYNC
FD_SYNC
)
func FdFlagsString(fdflags int) string {
return flagsString(fdflagNames[:], fdflags)
}
var fdflagNames = [...]string{
"APPEND",
"DSYNC",
"NONBLOCK",
"RSYNC",
"SYNC",
}
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#lookupflags
const (
// LOOKUP_SYMLINK_FOLLOW expands a path if it resolves into a symbolic
// link.
LOOKUP_SYMLINK_FOLLOW uint16 = 1 << iota //nolint
)
var lookupflagNames = [...]string{
"SYMLINK_FOLLOW",
}
func LookupflagsString(lookupflags int) string {
return flagsString(lookupflagNames[:], lookupflags)
}
// DirentSize is the size of the dirent struct, which should be followed by the
// length of a file name.
const DirentSize = uint32(24)
const (
FILETYPE_UNKNOWN uint8 = iota
FILETYPE_BLOCK_DEVICE
FILETYPE_CHARACTER_DEVICE
FILETYPE_DIRECTORY
FILETYPE_REGULAR_FILE
FILETYPE_SOCKET_DGRAM
FILETYPE_SOCKET_STREAM
FILETYPE_SYMBOLIC_LINK
)
// FiletypeName returns string name of the file type.
func FiletypeName(filetype uint8) string {
if int(filetype) < len(filetypeToString) {
return filetypeToString[filetype]
}
return fmt.Sprintf("filetype(%d)", filetype)
}
var filetypeToString = [...]string{
"UNKNOWN",
"BLOCK_DEVICE",
"CHARACTER_DEVICE",
"DIRECTORY",
"REGULAR_FILE",
"SOCKET_DGRAM",
"SOCKET_STREAM",
"SYMBOLIC_LINK",
}

View File

@@ -8,7 +8,7 @@ import (
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/logging"
"github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
)
var le = binary.LittleEndian
@@ -25,11 +25,11 @@ func IsFilesystemFunction(fnd api.FunctionDefinition) bool {
func Config(fnd api.FunctionDefinition) (pLoggers []logging.ParamLogger, rLoggers []logging.ResultLogger) {
switch fnd.Name() {
case "fd_prestat_get":
case FdPrestatGetName:
pLoggers = []logging.ParamLogger{logging.NewParamLogger(0, "fd", logging.ValueTypeI32)}
rLoggers = []logging.ResultLogger{resultParamLogger("prestat", logPrestat(1).Log), logErrno}
return
case "proc_exit":
case ProcExitName:
return logging.ValueLoggers(fnd)
}
@@ -94,18 +94,18 @@ func Config(fnd api.FunctionDefinition) (pLoggers []logging.ParamLogger, rLogger
func isLookupFlags(fnd api.FunctionDefinition, name string) bool {
switch fnd.Name() {
case "path_filestat_get", "path_filestat_set_times":
case PathFilestatGetName, PathFilestatSetTimesName:
return name == "flags"
case "path_link":
case PathLinkName:
return name == "old_flags"
case "path_open":
case PathOpenName:
return name == "dirflags"
}
return false
}
func logErrno(_ context.Context, _ api.Module, w logging.Writer, _, results []uint64) {
errno := wasi_snapshot_preview1.ErrnoName(uint32(results[0]))
errno := ErrnoName(uint32(results[0]))
w.WriteString("errno=") //nolint
w.WriteString(errno) //nolint
}
@@ -123,9 +123,9 @@ type logFilestat uint32
func (i logFilestat) Log(_ context.Context, mod api.Module, w logging.Writer, params []uint64) {
offset, byteCount := uint32(params[i]), uint32(64)
if buf, ok := mod.Memory().Read(offset, byteCount); ok {
w.WriteString("{filetype=") //nolint
w.WriteString(wasi_snapshot_preview1.FiletypeName(buf[16])) //nolint
w.WriteString(",size=") //nolint
w.WriteString("{filetype=") //nolint
w.WriteString(FiletypeName(buf[16])) //nolint
w.WriteString(",size=") //nolint
writeI64(w, le.Uint64(buf[32:]))
w.WriteString(",mtim=") //nolint
writeI64(w, le.Uint64(buf[40:]))
@@ -138,15 +138,15 @@ type logFdstat uint32
func (i logFdstat) Log(_ context.Context, mod api.Module, w logging.Writer, params []uint64) {
offset, byteCount := uint32(params[i]), uint32(24)
if buf, ok := mod.Memory().Read(offset, byteCount); ok {
w.WriteString("{filetype=") //nolint
w.WriteString(wasi_snapshot_preview1.FiletypeName(buf[0])) //nolint
w.WriteString(",fdflags=") //nolint
writeFlags(w, fdflagNames[:], int(le.Uint16(buf[2:])))
w.WriteString(",fs_rights_base=") //nolint
writeFlags(w, rightNames[:], int(le.Uint16(buf[8:])))
w.WriteString(",fs_rights_inheriting=") //nolint
writeFlags(w, rightNames[:], int(le.Uint16(buf[16:])))
w.WriteString("}") //nolint
w.WriteString("{filetype=") //nolint
w.WriteString(FiletypeName(buf[0])) //nolint
w.WriteString(",fdflags=") //nolint
w.WriteString(FdFlagsString(int(le.Uint16(buf[2:])))) //nolint
w.WriteString(",fs_rights_base=") //nolint
w.WriteString(RightsString(int(le.Uint16(buf[8:])))) //nolint
w.WriteString(",fs_rights_inheriting=") //nolint
w.WriteString(RightsString(int(le.Uint16(buf[16:])))) //nolint
w.WriteString("}") //nolint
}
}
@@ -177,7 +177,7 @@ func resultParamLogger(name string, pLogger logging.ParamLogger) logging.ResultL
prefix := name + "="
return func(ctx context.Context, mod api.Module, w logging.Writer, params, results []uint64) {
w.WriteString(prefix) //nolint
if results[0] == 0 { // ESUCCESS
if Errno(results[0]) == ErrnoSuccess {
pLogger(ctx, mod, w, params)
}
}
@@ -186,8 +186,8 @@ func resultParamLogger(name string, pLogger logging.ParamLogger) logging.ResultL
type logFdflags int
func (i logFdflags) Log(_ context.Context, _ api.Module, w logging.Writer, params []uint64) {
w.WriteString("fdflags=") //nolint
writeFlags(w, fdflagNames[:], int(params[i]))
w.WriteString("fdflags=") //nolint
w.WriteString(FdFlagsString(int(params[i]))) //nolint
}
type logLookupflags struct {
@@ -196,96 +196,30 @@ type logLookupflags struct {
}
func (l *logLookupflags) Log(_ context.Context, _ api.Module, w logging.Writer, params []uint64) {
w.WriteString(l.name) //nolint
w.WriteByte('=') //nolint
writeFlags(w, lookupflagNames[:], int(params[l.i]))
w.WriteString(l.name) //nolint
w.WriteByte('=') //nolint
w.WriteString(LookupflagsString(int(params[l.i]))) //nolint
}
type logFsRightsBase uint32
func (i logFsRightsBase) Log(_ context.Context, _ api.Module, w logging.Writer, params []uint64) {
w.WriteString("fs_rights_base=") //nolint
writeFlags(w, rightNames[:], int(params[i]))
w.WriteString("fs_rights_base=") //nolint
w.WriteString(RightsString(int(params[i]))) //nolint
}
type logFsRightsInheriting uint32
func (i logFsRightsInheriting) Log(_ context.Context, _ api.Module, w logging.Writer, params []uint64) {
w.WriteString("fs_rights_inheriting=") //nolint
writeFlags(w, rightNames[:], int(params[i]))
w.WriteString("fs_rights_inheriting=") //nolint
w.WriteString(RightsString(int(params[i]))) //nolint
}
type logOflags int
func (i logOflags) Log(_ context.Context, _ api.Module, w logging.Writer, params []uint64) {
w.WriteString("oflags=") //nolint
writeFlags(w, oflagNames[:], int(params[i]))
}
func writeFlags(w logging.Writer, names []string, f int) {
first := true
for i, sf := range names {
target := 1 << i
if target&f != 0 {
if !first {
w.WriteByte('|') //nolint
} else {
first = false
}
w.WriteString(sf) //nolint
}
}
}
var oflagNames = [...]string{
"CREAT",
"DIRECTORY",
"EXCL",
"TRUNC",
}
var fdflagNames = [...]string{
"APPEND",
"DSYNC",
"NONBLOCK",
"RSYNC",
"SYNC",
}
var lookupflagNames = [...]string{
"SYMLINK_FOLLOW",
}
var rightNames = [...]string{
"FD_DATASYNC",
"FD_READ",
"FD_SEEK",
"FDSTAT_SET_FLAGS",
"FD_SYNC",
"FD_TELL",
"FD_WRITE",
"FD_ADVISE",
"FD_ALLOCATE",
"PATH_CREATE_DIRECTORY",
"PATH_CREATE_FILE",
"PATH_LINK_SOURCE",
"PATH_LINK_TARGET",
"PATH_OPEN",
"FD_READDIR",
"PATH_READLINK",
"PATH_RENAME_SOURCE",
"PATH_RENAME_TARGET",
"PATH_FILESTAT_GET",
"PATH_FILESTAT_SET_SIZE",
"PATH_FILESTAT_SET_TIMES",
"FD_FILESTAT_GET",
"FD_FILESTAT_SET_SIZE",
"FD_FILESTAT_SET_TIMES",
"PATH_SYMLINK",
"PATH_REMOVE_DIRECTORY",
"PATH_UNLINK_FILE",
"POLL_FD_READWRITE",
"SOCK_SHUTDOWN",
w.WriteString("oflags=") //nolint
w.WriteString(OflagsString(int(params[i]))) //nolint
}
func resultParamName(name string) string {

View File

@@ -0,0 +1,15 @@
package wasi_snapshot_preview1
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-eventtype-enumu8
const (
// EventTypeClock is the timeout event named "name".
EventTypeClock = iota
// EventTypeFdRead is the data available event named "fd_read".
EventTypeFdRead
// EventTypeFdWrite is the capacity available event named "fd_write".
EventTypeFdWrite
)
const (
PollOneoffName = "poll_oneoff"
)

View File

@@ -0,0 +1,6 @@
package wasi_snapshot_preview1
const (
ProcExitName = "proc_exit"
ProcRaiseName = "proc_raise"
)

View File

@@ -0,0 +1,3 @@
package wasi_snapshot_preview1
const RandomGetName = "random_get"

View File

@@ -0,0 +1,148 @@
package wasi_snapshot_preview1
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-rights-flagsu64
const (
// RIGHT_FD_DATASYNC is the right to invoke fd_datasync. If RIGHT_PATH_OPEN
// is set, includes the right to invoke path_open with FD_DSYNC.
RIGHT_FD_DATASYNC uint32 = 1 << iota //nolint
// RIGHT_FD_READ is he right to invoke fd_read and sock_recv. If
// RIGHT_FD_SYNC is set, includes the right to invoke fd_pread.
RIGHT_FD_READ
// RIGHT_FD_SEEK is the right to invoke fd_seek. This flag implies
// RIGHT_FD_TELL.
RIGHT_FD_SEEK
// RIGHT_FDSTAT_SET_FLAGS is the right to invoke fd_fdstat_set_flags.
RIGHT_FDSTAT_SET_FLAGS
// RIGHT_FD_SYNC The right to invoke fd_sync. If path_open is set, includes
// the right to invoke path_open with FD_RSYNC and FD_DSYNC.
RIGHT_FD_SYNC
// RIGHT_FD_TELL is the right to invoke fd_seek in such a way that the file
// offset remains unaltered (i.e., whence::cur with offset zero), or to
// invoke fd_tell.
RIGHT_FD_TELL
// RIGHT_FD_WRITE is the right to invoke fd_write and sock_send. If
// RIGHT_FD_SEEK is set, includes the right to invoke fd_pwrite.
RIGHT_FD_WRITE
// RIGHT_FD_ADVISE is the right to invoke fd_advise.
RIGHT_FD_ADVISE
// RIGHT_FD_ALLOCATE is the right to invoke fd_allocate.
RIGHT_FD_ALLOCATE
// RIGHT_PATH_CREATE_DIRECTORY is the right to invoke
// path_create_directory.
RIGHT_PATH_CREATE_DIRECTORY
// RIGHT_PATH_CREATE_FILE when RIGHT_PATH_OPEN is set, the right to invoke
// path_open with O_CREATE.
RIGHT_PATH_CREATE_FILE
// RIGHT_PATH_LINK_SOURCE is the right to invoke path_link with the file
// descriptor as the source directory.
RIGHT_PATH_LINK_SOURCE
// RIGHT_PATH_LINK_TARGET is the right to invoke path_link with the file
// descriptor as the target directory.
RIGHT_PATH_LINK_TARGET
// RIGHT_PATH_OPEN is the right to invoke path_open.
RIGHT_PATH_OPEN
// RIGHT_FD_READDIR is the right to invoke fd_readdir.
RIGHT_FD_READDIR
// RIGHT_PATH_READLINK is the right to invoke path_readlink.
RIGHT_PATH_READLINK
// RIGHT_PATH_RENAME_SOURCE is the right to invoke path_rename with the
// file descriptor as the source directory.
RIGHT_PATH_RENAME_SOURCE
// RIGHT_PATH_RENAME_TARGET is the right to invoke path_rename with the
// file descriptor as the target directory.
RIGHT_PATH_RENAME_TARGET
// RIGHT_PATH_FILESTAT_GET is the right to invoke path_filestat_get.
RIGHT_PATH_FILESTAT_GET
// RIGHT_PATH_FILESTAT_SET_SIZE is the right to change a file's size (there
// is no path_filestat_set_size). If RIGHT_PATH_OPEN is set, includes the
// right to invoke path_open with O_TRUNC.
RIGHT_PATH_FILESTAT_SET_SIZE
// RIGHT_PATH_FILESTAT_SET_TIMES is the right to invoke
// path_filestat_set_times.
RIGHT_PATH_FILESTAT_SET_TIMES
// RIGHT_FD_FILESTAT_GET is the right to invoke fd_filestat_get.
RIGHT_FD_FILESTAT_GET
// RIGHT_FD_FILESTAT_SET_SIZE is the right to invoke fd_filestat_set_size.
RIGHT_FD_FILESTAT_SET_SIZE
// RIGHT_FD_FILESTAT_SET_TIMES is the right to invoke
// fd_filestat_set_times.
RIGHT_FD_FILESTAT_SET_TIMES
// RIGHT_PATH_SYMLINK is the right to invoke path_symlink.
RIGHT_PATH_SYMLINK
// RIGHT_PATH_REMOVE_DIRECTORY is the right to invoke
// path_remove_directory.
RIGHT_PATH_REMOVE_DIRECTORY
// RIGHT_PATH_UNLINK_FILE is the right to invoke path_unlink_file.
RIGHT_PATH_UNLINK_FILE
// RIGHT_POLL_FD_READWRITE when RIGHT_FD_READ is set, includes the right to
// invoke poll_oneoff to subscribe to eventtype::fd_read. If RIGHT_FD_WRITE
// is set, includes the right to invoke poll_oneoff to subscribe to
// eventtype::fd_write.
RIGHT_POLL_FD_READWRITE
// RIGHT_SOCK_SHUTDOWN is the right to invoke sock_shutdown.
RIGHT_SOCK_SHUTDOWN
)
func RightsString(rights int) string {
return flagsString(rightNames[:], rights)
}
var rightNames = [...]string{
"FD_DATASYNC",
"FD_READ",
"FD_SEEK",
"FDSTAT_SET_FLAGS",
"FD_SYNC",
"FD_TELL",
"FD_WRITE",
"FD_ADVISE",
"FD_ALLOCATE",
"PATH_CREATE_DIRECTORY",
"PATH_CREATE_FILE",
"PATH_LINK_SOURCE",
"PATH_LINK_TARGET",
"PATH_OPEN",
"FD_READDIR",
"PATH_READLINK",
"PATH_RENAME_SOURCE",
"PATH_RENAME_TARGET",
"PATH_FILESTAT_GET",
"PATH_FILESTAT_SET_SIZE",
"PATH_FILESTAT_SET_TIMES",
"FD_FILESTAT_GET",
"FD_FILESTAT_SET_SIZE",
"FD_FILESTAT_SET_TIMES",
"PATH_SYMLINK",
"PATH_REMOVE_DIRECTORY",
"PATH_UNLINK_FILE",
"POLL_FD_READWRITE",
"SOCK_SHUTDOWN",
}

View File

@@ -0,0 +1,3 @@
package wasi_snapshot_preview1
const SchedYieldName = "sched_yield"

View File

@@ -0,0 +1,8 @@
package wasi_snapshot_preview1
const (
SockAcceptName = "sock_accept"
SockRecvName = "sock_recv"
SockSendName = "sock_send"
SockShutdownName = "sock_shutdown"
)

View File

@@ -1,268 +1,27 @@
// Package wasi_snapshot_preview1 is an internal helper to remove package
// cycles re-using errno
// Package wasi_snapshot_preview1 is a helper to remove package cycles re-using
// constants.
package wasi_snapshot_preview1
import (
"fmt"
"strings"
)
const ModuleName = "wasi_snapshot_preview1"
// InternalModuleName is not named ModuleName, to avoid a clash on dot imports.
const InternalModuleName = "wasi_snapshot_preview1"
// ErrnoName returns the POSIX error code name, except ErrnoSuccess, which is not an error. e.g. Errno2big -> "E2BIG"
func ErrnoName(errno uint32) string {
if int(errno) < len(errnoToString) {
return errnoToString[errno]
func flagsString(names []string, f int) string {
var builder strings.Builder
first := true
for i, sf := range names {
target := 1 << i
if target&f != 0 {
if !first {
builder.WriteByte('|')
} else {
first = false
}
builder.WriteString(sf)
}
}
return fmt.Sprintf("errno(%d)", errno)
}
var errnoToString = [...]string{
"ESUCCESS",
"E2BIG",
"EACCES",
"EADDRINUSE",
"EADDRNOTAVAIL",
"EAFNOSUPPORT",
"EAGAIN",
"EALREADY",
"EBADF",
"EBADMSG",
"EBUSY",
"ECANCELED",
"ECHILD",
"ECONNABORTED",
"ECONNREFUSED",
"ECONNRESET",
"EDEADLK",
"EDESTADDRREQ",
"EDOM",
"EDQUOT",
"EEXIST",
"EFAULT",
"EFBIG",
"EHOSTUNREACH",
"EIDRM",
"EILSEQ",
"EINPROGRESS",
"EINTR",
"EINVAL",
"EIO",
"EISCONN",
"EISDIR",
"ELOOP",
"EMFILE",
"EMLINK",
"EMSGSIZE",
"EMULTIHOP",
"ENAMETOOLONG",
"ENETDOWN",
"ENETRESET",
"ENETUNREACH",
"ENFILE",
"ENOBUFS",
"ENODEV",
"ENOENT",
"ENOEXEC",
"ENOLCK",
"ENOLINK",
"ENOMEM",
"ENOMSG",
"ENOPROTOOPT",
"ENOSPC",
"ENOSYS",
"ENOTCONN",
"ENOTDIR",
"ENOTEMPTY",
"ENOTRECOVERABLE",
"ENOTSOCK",
"ENOTSUP",
"ENOTTY",
"ENXIO",
"EOVERFLOW",
"EOWNERDEAD",
"EPERM",
"EPIPE",
"EPROTO",
"EPROTONOSUPPORT",
"EPROTOTYPE",
"ERANGE",
"EROFS",
"ESPIPE",
"ESRCH",
"ESTALE",
"ETIMEDOUT",
"ETXTBSY",
"EXDEV",
"ENOTCAPABLE",
}
// oflags are open flags used by path_open
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-oflags-flagsu16
const (
// O_CREAT creates a file if it does not exist.
O_CREAT uint16 = 1 << iota //nolint
// O_DIRECTORY fails if not a directory.
O_DIRECTORY
// O_EXCL fails if file already exists.
O_EXCL //nolint
// O_TRUNC truncates the file to size 0.
O_TRUNC //nolint
)
// file descriptor flags
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fdflags
const (
FD_APPEND uint16 = 1 << iota //nolint
FD_DSYNC
FD_NONBLOCK
FD_RSYNC
FD_SYNC
)
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#lookupflags
const (
// LOOKUP_SYMLINK_FOLLOW expands a path if it resolves into a symbolic
// link.
LOOKUP_SYMLINK_FOLLOW uint16 = 1 << iota //nolint
)
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-rights-flagsu64
const (
// RIGHT_FD_DATASYNC is the right to invoke fd_datasync. If RIGHT_PATH_OPEN
// is set, includes the right to invoke path_open with FD_DSYNC.
RIGHT_FD_DATASYNC uint32 = 1 << iota //nolint
// RIGHT_FD_READ is he right to invoke fd_read and sock_recv. If
// RIGHT_FD_SYNC is set, includes the right to invoke fd_pread.
RIGHT_FD_READ
// RIGHT_FD_SEEK is the right to invoke fd_seek. This flag implies
// RIGHT_FD_TELL.
RIGHT_FD_SEEK
// RIGHT_FDSTAT_SET_FLAGS is the right to invoke fd_fdstat_set_flags.
RIGHT_FDSTAT_SET_FLAGS
// RIGHT_FD_SYNC The right to invoke fd_sync. If path_open is set, includes
// the right to invoke path_open with FD_RSYNC and FD_DSYNC.
RIGHT_FD_SYNC
// RIGHT_FD_TELL is the right to invoke fd_seek in such a way that the file
// offset remains unaltered (i.e., whence::cur with offset zero), or to
// invoke fd_tell.
RIGHT_FD_TELL
// RIGHT_FD_WRITE is the right to invoke fd_write and sock_send. If
// RIGHT_FD_SEEK is set, includes the right to invoke fd_pwrite.
RIGHT_FD_WRITE
// RIGHT_FD_ADVISE is the right to invoke fd_advise.
RIGHT_FD_ADVISE
// RIGHT_FD_ALLOCATE is the right to invoke fd_allocate.
RIGHT_FD_ALLOCATE
// RIGHT_PATH_CREATE_DIRECTORY is the right to invoke
// path_create_directory.
RIGHT_PATH_CREATE_DIRECTORY
// RIGHT_PATH_CREATE_FILE when RIGHT_PATH_OPEN is set, the right to invoke
// path_open with O_CREATE.
RIGHT_PATH_CREATE_FILE
// RIGHT_PATH_LINK_SOURCE is the right to invoke path_link with the file
// descriptor as the source directory.
RIGHT_PATH_LINK_SOURCE
// RIGHT_PATH_LINK_TARGET is the right to invoke path_link with the file
// descriptor as the target directory.
RIGHT_PATH_LINK_TARGET
// RIGHT_PATH_OPEN is the right to invoke path_open.
RIGHT_PATH_OPEN
// RIGHT_FD_READDIR is the right to invoke fd_readdir.
RIGHT_FD_READDIR
// RIGHT_PATH_READLINK is the right to invoke path_readlink.
RIGHT_PATH_READLINK
// RIGHT_PATH_RENAME_SOURCE is the right to invoke path_rename with the
// file descriptor as the source directory.
RIGHT_PATH_RENAME_SOURCE
// RIGHT_PATH_RENAME_TARGET is the right to invoke path_rename with the
// file descriptor as the target directory.
RIGHT_PATH_RENAME_TARGET
// RIGHT_PATH_FILESTAT_GET is the right to invoke path_filestat_get.
RIGHT_PATH_FILESTAT_GET
// RIGHT_PATH_FILESTAT_SET_SIZE is the right to change a file's size (there
// is no path_filestat_set_size). If RIGHT_PATH_OPEN is set, includes the
// right to invoke path_open with O_TRUNC.
RIGHT_PATH_FILESTAT_SET_SIZE
// RIGHT_PATH_FILESTAT_SET_TIMES is the right to invoke
// path_filestat_set_times.
RIGHT_PATH_FILESTAT_SET_TIMES
// RIGHT_FD_FILESTAT_GET is the right to invoke fd_filestat_get.
RIGHT_FD_FILESTAT_GET
// RIGHT_FD_FILESTAT_SET_SIZE is the right to invoke fd_filestat_set_size.
RIGHT_FD_FILESTAT_SET_SIZE
// RIGHT_FD_FILESTAT_SET_TIMES is the right to invoke
// fd_filestat_set_times.
RIGHT_FD_FILESTAT_SET_TIMES
// RIGHT_PATH_SYMLINK is the right to invoke path_symlink.
RIGHT_PATH_SYMLINK
// RIGHT_PATH_REMOVE_DIRECTORY is the right to invoke
// path_remove_directory.
RIGHT_PATH_REMOVE_DIRECTORY
// RIGHT_PATH_UNLINK_FILE is the right to invoke path_unlink_file.
RIGHT_PATH_UNLINK_FILE
// RIGHT_POLL_FD_READWRITE when RIGHT_FD_READ is set, includes the right to
// invoke poll_oneoff to subscribe to eventtype::fd_read. If RIGHT_FD_WRITE
// is set, includes the right to invoke poll_oneoff to subscribe to
// eventtype::fd_write.
RIGHT_POLL_FD_READWRITE
// RIGHT_SOCK_SHUTDOWN is the right to invoke sock_shutdown.
RIGHT_SOCK_SHUTDOWN
)
const (
FILETYPE_UNKNOWN uint8 = iota
FILETYPE_BLOCK_DEVICE
FILETYPE_CHARACTER_DEVICE
FILETYPE_DIRECTORY
FILETYPE_REGULAR_FILE
FILETYPE_SOCKET_DGRAM
FILETYPE_SOCKET_STREAM
FILETYPE_SYMBOLIC_LINK
)
// FiletypeName returns string name of the file type.
func FiletypeName(filetype uint8) string {
if int(filetype) < len(filetypeToString) {
return filetypeToString[filetype]
}
return fmt.Sprintf("filetype(%d)", filetype)
}
var filetypeToString = [...]string{
"UNKNOWN",
"BLOCK_DEVICE",
"CHARACTER_DEVICE",
"DIRECTORY",
"REGULAR_FILE",
"SOCKET_DGRAM",
"SOCKET_STREAM",
"SYMBOLIC_LINK",
return builder.String()
}

View File

@@ -6,7 +6,7 @@ import (
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/testing/require"
"github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
)
func argsSizesGet(ctx context.Context, mod api.Module, resultArgc, resultArgvBufSize uint32) uint32 {
@@ -22,8 +22,6 @@ func swap(ctx context.Context, x, y uint32) (uint32, uint32) {
}
func TestNewHostModule(t *testing.T) {
argsSizesGetName := "args_sizes_get"
fdWriteName := "fd_write"
swapName := "swap"
tests := []struct {
@@ -43,19 +41,19 @@ func TestNewHostModule(t *testing.T) {
},
{
name: "funcs",
moduleName: wasi_snapshot_preview1.ModuleName,
moduleName: InternalModuleName,
nameToGoFunc: map[string]interface{}{
argsSizesGetName: argsSizesGet,
fdWriteName: fdWrite,
ArgsSizesGetName: argsSizesGet,
FdWriteName: fdWrite,
},
funcToNames: map[string]*HostFuncNames{
argsSizesGetName: {
Name: argsSizesGetName,
ArgsSizesGetName: {
Name: ArgsSizesGetName,
ParamNames: []string{"result.argc", "result.argv_len"},
ResultNames: []string{"errno"},
},
fdWriteName: {
Name: fdWriteName,
FdWriteName: {
Name: FdWriteName,
ParamNames: []string{"fd", "iovs", "iovs_len", "result.size"},
ResultNames: []string{"errno"},
},
@@ -68,14 +66,14 @@ func TestNewHostModule(t *testing.T) {
FunctionSection: []Index{0, 1},
CodeSection: []*Code{MustParseGoReflectFuncCode(argsSizesGet), MustParseGoReflectFuncCode(fdWrite)},
ExportSection: []*Export{
{Name: "args_sizes_get", Type: ExternTypeFunc, Index: 0},
{Name: "fd_write", Type: ExternTypeFunc, Index: 1},
{Name: ArgsSizesGetName, Type: ExternTypeFunc, Index: 0},
{Name: FdWriteName, Type: ExternTypeFunc, Index: 1},
},
NameSection: &NameSection{
ModuleName: wasi_snapshot_preview1.ModuleName,
ModuleName: InternalModuleName,
FunctionNames: NameMap{
{Index: 0, Name: "args_sizes_get"},
{Index: 1, Name: "fd_write"},
{Index: 0, Name: ArgsSizesGetName},
{Index: 1, Name: FdWriteName},
},
LocalNames: IndirectNameMap{
{Index: 0, NameMap: NameMap{