mirror of
https://github.com/wazero/wazero
synced 2026-06-21 14:12:37 +00:00
adds experimental sys.Errno to begin decoupling from the syscall package (#1582)
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
@@ -540,7 +540,7 @@ Consider switching to GOOS=wasip1.
|
||||
==> go.runtime.getRandomData(r_len=8)
|
||||
<==
|
||||
==> go.syscall/js.valueCall(fs.open(path=/bear.txt,flags=,perm=----------))
|
||||
<== (err=function not implemented,fd=0)
|
||||
<== (err=functionality not supported,fd=0)
|
||||
`, // Test only shows logging happens in two scopes; it is ok to fail.
|
||||
expectedExitCode: 1,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package sys
|
||||
|
||||
import "strconv"
|
||||
|
||||
// Errno is a subset of POSIX errno used by wazero interfaces. Zero is not an
|
||||
// error. Other values should not be interpreted numerically, rather by constants
|
||||
// prefixed with 'E'.
|
||||
//
|
||||
// See https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
|
||||
type Errno uint16
|
||||
|
||||
// ^-- Note: This will eventually move to the public /sys package. It is
|
||||
// experimental until we audit the socket related APIs to ensure we have all
|
||||
// the Errno it returns, and we export fs.FS. This is not in /internal/sys as
|
||||
// that would introduce a package cycle.
|
||||
|
||||
// This is a subset of errors to reduce implementation burden. `wasip` defines
|
||||
// almost all POSIX error numbers, but not all are used in practice. wazero
|
||||
// will add ones needed in POSIX order, as needed by functions that explicitly
|
||||
// document returning them.
|
||||
//
|
||||
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-errno-enumu16
|
||||
const (
|
||||
EACCES Errno = iota + 1
|
||||
EAGAIN
|
||||
EBADF
|
||||
EEXIST
|
||||
EFAULT
|
||||
EINTR
|
||||
EINVAL
|
||||
EIO
|
||||
EISDIR
|
||||
ELOOP
|
||||
ENAMETOOLONG
|
||||
ENOENT
|
||||
ENOSYS
|
||||
ENOTDIR
|
||||
ENOTEMPTY
|
||||
ENOTSOCK
|
||||
ENOTSUP
|
||||
EPERM
|
||||
EROFS
|
||||
|
||||
// NOTE ENOTCAPABLE is defined in wasip1, but not in POSIX. wasi-libc
|
||||
// converts it to EBADF, ESPIPE or EINVAL depending on the call site.
|
||||
// It isn't known if compilers who don't use ENOTCAPABLE would crash on it.
|
||||
)
|
||||
|
||||
// Error implements error
|
||||
func (e Errno) Error() string {
|
||||
switch e {
|
||||
case 0: // not an error
|
||||
return "success"
|
||||
case EACCES:
|
||||
return "permission denied"
|
||||
case EAGAIN:
|
||||
return "resource unavailable, try again"
|
||||
case EBADF:
|
||||
return "bad file descriptor"
|
||||
case EEXIST:
|
||||
return "file exists"
|
||||
case EFAULT:
|
||||
return "bad address"
|
||||
case EINTR:
|
||||
return "interrupted function"
|
||||
case EINVAL:
|
||||
return "invalid argument"
|
||||
case EIO:
|
||||
return "input/output error"
|
||||
case EISDIR:
|
||||
return "is a directory"
|
||||
case ELOOP:
|
||||
return "too many levels of symbolic links"
|
||||
case ENAMETOOLONG:
|
||||
return "filename too long"
|
||||
case ENOENT:
|
||||
return "no such file or directory"
|
||||
case ENOSYS:
|
||||
return "functionality not supported"
|
||||
case ENOTDIR:
|
||||
return "not a directory or a symbolic link to a directory"
|
||||
case ENOTEMPTY:
|
||||
return "directory not empty"
|
||||
case ENOTSOCK:
|
||||
return "not a socket"
|
||||
case ENOTSUP:
|
||||
return "not supported (may be the same value as [EOPNOTSUPP])"
|
||||
case EPERM:
|
||||
return "operation not permitted"
|
||||
case EROFS:
|
||||
return "read-only file system"
|
||||
default:
|
||||
return "Errno(" + strconv.Itoa(int(e)) + ")"
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,32 @@
|
||||
package platform
|
||||
package sys
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// UnwrapOSError returns a syscall.Errno or zero if the input is nil.
|
||||
func UnwrapOSError(err error) syscall.Errno {
|
||||
// UnwrapOSError returns an Errno or zero if the input is nil.
|
||||
func UnwrapOSError(err error) Errno {
|
||||
if err == nil {
|
||||
return 0
|
||||
}
|
||||
err = underlyingError(err)
|
||||
if se, ok := err.(syscall.Errno); ok {
|
||||
return adjustErrno(se)
|
||||
}
|
||||
// Below are all the fs.ErrXXX in fs.go.
|
||||
//
|
||||
// Note: Once we have our own file type, we should never see these.
|
||||
switch err {
|
||||
case nil, io.EOF:
|
||||
return 0 // EOF is not a syscall.Errno
|
||||
return 0 // EOF is not a Errno
|
||||
case fs.ErrInvalid:
|
||||
return syscall.EINVAL
|
||||
return EINVAL
|
||||
case fs.ErrPermission:
|
||||
return syscall.EPERM
|
||||
return EPERM
|
||||
case fs.ErrExist:
|
||||
return syscall.EEXIST
|
||||
return EEXIST
|
||||
case fs.ErrNotExist:
|
||||
return syscall.ENOENT
|
||||
return ENOENT
|
||||
case fs.ErrClosed:
|
||||
return syscall.EBADF
|
||||
return EBADF
|
||||
}
|
||||
return syscall.EIO
|
||||
return errorToErrno(err)
|
||||
}
|
||||
|
||||
// underlyingError returns the underlying error if a well-known OS error type.
|
||||
@@ -1,4 +1,4 @@
|
||||
package platform
|
||||
package sys
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -6,17 +6,14 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
|
||||
func TestUnwrapOSError(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input error
|
||||
expected syscall.Errno
|
||||
expected Errno
|
||||
}{
|
||||
{
|
||||
name: "io.EOF is not an error",
|
||||
@@ -26,64 +23,69 @@ func TestUnwrapOSError(t *testing.T) {
|
||||
{
|
||||
name: "LinkError ErrInvalid",
|
||||
input: &os.LinkError{Err: fs.ErrInvalid},
|
||||
expected: syscall.EINVAL,
|
||||
expected: EINVAL,
|
||||
},
|
||||
{
|
||||
name: "PathError ErrInvalid",
|
||||
input: &os.PathError{Err: fs.ErrInvalid},
|
||||
expected: syscall.EINVAL,
|
||||
expected: EINVAL,
|
||||
},
|
||||
{
|
||||
name: "SyscallError ErrInvalid",
|
||||
input: &os.SyscallError{Err: fs.ErrInvalid},
|
||||
expected: syscall.EINVAL,
|
||||
expected: EINVAL,
|
||||
},
|
||||
{
|
||||
name: "PathError ErrPermission",
|
||||
input: &os.PathError{Err: os.ErrPermission},
|
||||
expected: syscall.EPERM,
|
||||
expected: EPERM,
|
||||
},
|
||||
{
|
||||
name: "PathError ErrExist",
|
||||
input: &os.PathError{Err: os.ErrExist},
|
||||
expected: syscall.EEXIST,
|
||||
expected: EEXIST,
|
||||
},
|
||||
{
|
||||
name: "PathError syscall.ErrnotExist",
|
||||
name: "PathError ErrnotExist",
|
||||
input: &os.PathError{Err: os.ErrNotExist},
|
||||
expected: syscall.ENOENT,
|
||||
expected: ENOENT,
|
||||
},
|
||||
{
|
||||
name: "PathError ErrClosed",
|
||||
input: &os.PathError{Err: os.ErrClosed},
|
||||
expected: syscall.EBADF,
|
||||
expected: EBADF,
|
||||
},
|
||||
{
|
||||
name: "PathError unknown == syscall.EIO",
|
||||
name: "PathError unknown == EIO",
|
||||
input: &os.PathError{Err: errors.New("ice cream")},
|
||||
expected: syscall.EIO,
|
||||
expected: EIO,
|
||||
},
|
||||
{
|
||||
name: "unknown == syscall.EIO",
|
||||
name: "unknown == EIO",
|
||||
input: errors.New("ice cream"),
|
||||
expected: syscall.EIO,
|
||||
expected: EIO,
|
||||
},
|
||||
{
|
||||
name: "very wrapped unknown == syscall.EIO",
|
||||
name: "very wrapped unknown == EIO",
|
||||
input: fmt.Errorf("%w", fmt.Errorf("%w", fmt.Errorf("%w", errors.New("ice cream")))),
|
||||
expected: syscall.EIO,
|
||||
expected: EIO,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
errno := UnwrapOSError(tc.input)
|
||||
require.EqualErrno(t, tc.expected, errno)
|
||||
// don't use require package as that introduces a package cycle
|
||||
if want, have := tc.expected, UnwrapOSError(tc.input); have != want {
|
||||
t.Fatalf("unexpected errno: %v != %v", have, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("nil -> zero", func(t *testing.T) {
|
||||
require.Zero(t, UnwrapOSError(nil))
|
||||
// don't use require package as that introduces a package cycle
|
||||
if want, have := Errno(0), UnwrapOSError(nil); have != want {
|
||||
t.Fatalf("unexpected errno: %v != %v", have, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package sys
|
||||
|
||||
import "syscall"
|
||||
|
||||
func syscallToErrno(errno syscall.Errno) Errno {
|
||||
switch errno {
|
||||
case 0:
|
||||
return 0
|
||||
case syscall.EACCES:
|
||||
return EACCES
|
||||
case syscall.EAGAIN:
|
||||
return EAGAIN
|
||||
case syscall.EBADF:
|
||||
return EBADF
|
||||
case syscall.EEXIST:
|
||||
return EEXIST
|
||||
case syscall.EFAULT:
|
||||
return EFAULT
|
||||
case syscall.EINTR:
|
||||
return EINTR
|
||||
case syscall.EINVAL:
|
||||
return EINVAL
|
||||
case syscall.EIO:
|
||||
return EIO
|
||||
case syscall.EISDIR:
|
||||
return EISDIR
|
||||
case syscall.ELOOP:
|
||||
return ELOOP
|
||||
case syscall.ENAMETOOLONG:
|
||||
return ENAMETOOLONG
|
||||
case syscall.ENOENT:
|
||||
return ENOENT
|
||||
case syscall.ENOSYS:
|
||||
return ENOSYS
|
||||
case syscall.ENOTDIR:
|
||||
return ENOTDIR
|
||||
case syscall.ENOTEMPTY:
|
||||
return ENOTEMPTY
|
||||
case syscall.ENOTSOCK:
|
||||
return ENOTSOCK
|
||||
case syscall.ENOTSUP:
|
||||
return ENOTSUP
|
||||
case syscall.EPERM:
|
||||
return EPERM
|
||||
case syscall.EROFS:
|
||||
return EROFS
|
||||
default:
|
||||
return EIO
|
||||
}
|
||||
}
|
||||
|
||||
// Unwrap is a convenience for runtime.GOOS which define syscall.Errno.
|
||||
func (e Errno) Unwrap() error {
|
||||
switch e {
|
||||
case 0:
|
||||
return nil
|
||||
case EACCES:
|
||||
return syscall.EACCES
|
||||
case EAGAIN:
|
||||
return syscall.EAGAIN
|
||||
case EBADF:
|
||||
return syscall.EBADF
|
||||
case EEXIST:
|
||||
return syscall.EEXIST
|
||||
case EFAULT:
|
||||
return syscall.EFAULT
|
||||
case EINTR:
|
||||
return syscall.EINTR
|
||||
case EINVAL:
|
||||
return syscall.EINVAL
|
||||
case EIO:
|
||||
return syscall.EIO
|
||||
case EISDIR:
|
||||
return syscall.EISDIR
|
||||
case ELOOP:
|
||||
return syscall.ELOOP
|
||||
case ENAMETOOLONG:
|
||||
return syscall.ENAMETOOLONG
|
||||
case ENOENT:
|
||||
return syscall.ENOENT
|
||||
case ENOSYS:
|
||||
return syscall.ENOSYS
|
||||
case ENOTDIR:
|
||||
return syscall.ENOTDIR
|
||||
case ENOTEMPTY:
|
||||
return syscall.ENOTEMPTY
|
||||
case ENOTSOCK:
|
||||
return syscall.ENOTSOCK
|
||||
case ENOTSUP:
|
||||
return syscall.ENOTSUP
|
||||
case EPERM:
|
||||
return syscall.EPERM
|
||||
case EROFS:
|
||||
return syscall.EROFS
|
||||
default:
|
||||
return syscall.EIO
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//go:build !windows
|
||||
|
||||
package sys
|
||||
|
||||
import "syscall"
|
||||
|
||||
func errorToErrno(err error) Errno {
|
||||
switch err := err.(type) {
|
||||
case Errno:
|
||||
return err
|
||||
case syscall.Errno:
|
||||
return syscallToErrno(err)
|
||||
default:
|
||||
return EIO
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package sys
|
||||
|
||||
import "syscall"
|
||||
|
||||
// These are errors not defined in the syscall package. They are prefixed with
|
||||
// underscore to avoid exporting them.
|
||||
//
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
|
||||
const (
|
||||
// _ERROR_INVALID_HANDLE is a Windows error returned by syscall.Write
|
||||
// instead of syscall.EBADF
|
||||
_ERROR_INVALID_HANDLE = syscall.Errno(6)
|
||||
|
||||
// _ERROR_INVALID_NAME is a Windows error returned by open when a file
|
||||
// path has a trailing slash
|
||||
_ERROR_INVALID_NAME = syscall.Errno(0x7B)
|
||||
|
||||
// _ERROR_NEGATIVE_SEEK is a Windows error returned by os.Truncate
|
||||
// instead of syscall.EINVAL
|
||||
_ERROR_NEGATIVE_SEEK = syscall.Errno(0x83)
|
||||
|
||||
// _ERROR_DIRECTORY is a Windows error returned by syscall.Rmdir
|
||||
// instead of syscall.ENOTDIR
|
||||
_ERROR_DIRECTORY = syscall.Errno(0x10B)
|
||||
)
|
||||
|
||||
func errorToErrno(err error) Errno {
|
||||
switch err := err.(type) {
|
||||
case Errno:
|
||||
return err
|
||||
case syscall.Errno:
|
||||
// Note: In windows, _ERROR_PATH_NOT_FOUND(0x3) maps to syscall.ENOTDIR
|
||||
switch err {
|
||||
case syscall.ERROR_ALREADY_EXISTS:
|
||||
return EEXIST
|
||||
case _ERROR_DIRECTORY:
|
||||
return ENOTDIR
|
||||
case syscall.ERROR_DIR_NOT_EMPTY:
|
||||
return ENOTEMPTY
|
||||
case syscall.ERROR_FILE_EXISTS:
|
||||
return EEXIST
|
||||
case _ERROR_INVALID_HANDLE:
|
||||
return EBADF
|
||||
case syscall.ERROR_ACCESS_DENIED:
|
||||
// POSIX read and write functions expect EBADF, not EACCES when not
|
||||
// open for reading or writing.
|
||||
return EBADF
|
||||
case syscall.ERROR_PRIVILEGE_NOT_HELD:
|
||||
return EPERM
|
||||
case _ERROR_NEGATIVE_SEEK, _ERROR_INVALID_NAME:
|
||||
return EINVAL
|
||||
}
|
||||
return syscallToErrno(err)
|
||||
default:
|
||||
return EIO
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is ErrnoSuccess except the following error conditions:
|
||||
// - syscall.EFAULT: there is not enough memory to write results
|
||||
// - sys.EFAULT: there is not enough memory to write results
|
||||
//
|
||||
// For example, if argsSizesGet wrote argc=2 and argvLen=5 for arguments:
|
||||
// "a" and "bc" parameters argv=7 and argvBuf=1, this function writes the below
|
||||
@@ -43,7 +43,7 @@ import (
|
||||
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||
var argsGet = newHostFunc(wasip1.ArgsGetName, argsGetFn, []api.ValueType{i32, i32}, "argv", "argv_buf")
|
||||
|
||||
func argsGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func argsGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||
argv, argvBuf := uint32(params[0]), uint32(params[1])
|
||||
return writeOffsetsAndNullTerminatedValues(mod.Memory(), sysCtx.Args(), argv, argvBuf, sysCtx.ArgsSize())
|
||||
@@ -61,7 +61,7 @@ func argsGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is ErrnoSuccess except the following error conditions:
|
||||
// - syscall.EFAULT: there is not enough memory to write results
|
||||
// - sys.EFAULT: there is not enough memory to write results
|
||||
//
|
||||
// For example, if args are "a", "bc" and parameters resultArgc=1 and
|
||||
// resultArgvLen=6, this function writes the below to api.Memory:
|
||||
@@ -80,7 +80,7 @@ func argsGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno
|
||||
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||
var argsSizesGet = newHostFunc(wasip1.ArgsSizesGetName, argsSizesGetFn, []api.ValueType{i32, i32}, "result.argc", "result.argv_len")
|
||||
|
||||
func argsSizesGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func argsSizesGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||
mem := mod.Memory()
|
||||
resultArgc, resultArgvLen := uint32(params[0]), uint32(params[1])
|
||||
@@ -88,10 +88,10 @@ func argsSizesGetFn(_ context.Context, mod api.Module, params []uint64) syscall.
|
||||
// argc and argv_len offsets are not necessarily sequential, so we have to
|
||||
// write them independently.
|
||||
if !mem.WriteUint32Le(resultArgc, uint32(len(sysCtx.Args()))) {
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
if !mem.WriteUint32Le(resultArgvLen, sysCtx.ArgsSize()) {
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
@@ -21,9 +21,9 @@ import (
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.ENOTSUP: the clock ID is not supported.
|
||||
// - syscall.EINVAL: the clock ID is invalid.
|
||||
// - syscall.EFAULT: there is not enough memory to write results
|
||||
// - sys.ENOTSUP: the clock ID is not supported.
|
||||
// - sys.EINVAL: the clock ID is invalid.
|
||||
// - sys.EFAULT: there is not enough memory to write results
|
||||
//
|
||||
// For example, if the resolution is 100ns, this function writes the below to
|
||||
// api.Memory:
|
||||
@@ -39,7 +39,7 @@ import (
|
||||
// See https://linux.die.net/man/3/clock_getres
|
||||
var clockResGet = newHostFunc(wasip1.ClockResGetName, clockResGetFn, []api.ValueType{i32, i32}, "id", "result.resolution")
|
||||
|
||||
func clockResGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func clockResGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||
id, resultResolution := uint32(params[0]), uint32(params[1])
|
||||
|
||||
@@ -50,11 +50,11 @@ func clockResGetFn(_ context.Context, mod api.Module, params []uint64) syscall.E
|
||||
case wasip1.ClockIDMonotonic:
|
||||
resolution = uint64(sysCtx.NanotimeResolution())
|
||||
default:
|
||||
return syscall.EINVAL
|
||||
return sys.EINVAL
|
||||
}
|
||||
|
||||
if !mod.Memory().WriteUint64Le(resultResolution, resolution) {
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -73,9 +73,9 @@ func clockResGetFn(_ context.Context, mod api.Module, params []uint64) syscall.E
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.ENOTSUP: the clock ID is not supported.
|
||||
// - syscall.EINVAL: the clock ID is invalid.
|
||||
// - syscall.EFAULT: there is not enough memory to write results
|
||||
// - sys.ENOTSUP: the clock ID is not supported.
|
||||
// - sys.EINVAL: the clock ID is invalid.
|
||||
// - sys.EFAULT: there is not enough memory to write results
|
||||
//
|
||||
// For example, if time.Now returned exactly midnight UTC 2022-01-01
|
||||
// (1640995200000000000), and parameters resultTimestamp=1, this function
|
||||
@@ -92,7 +92,7 @@ func clockResGetFn(_ context.Context, mod api.Module, params []uint64) syscall.E
|
||||
// See https://linux.die.net/man/3/clock_gettime
|
||||
var clockTimeGet = newHostFunc(wasip1.ClockTimeGetName, clockTimeGetFn, []api.ValueType{i32, i64, i32}, "id", "precision", "result.timestamp")
|
||||
|
||||
func clockTimeGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func clockTimeGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||
id := uint32(params[0])
|
||||
// TODO: precision is currently ignored.
|
||||
@@ -106,11 +106,11 @@ func clockTimeGetFn(_ context.Context, mod api.Module, params []uint64) syscall.
|
||||
case wasip1.ClockIDMonotonic:
|
||||
val = sysCtx.Nanotime()
|
||||
default:
|
||||
return syscall.EINVAL
|
||||
return sys.EINVAL
|
||||
}
|
||||
|
||||
if !mod.Memory().WriteUint64Le(resultTimestamp, uint64(val)) {
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EFAULT: there is not enough memory to write results
|
||||
// - sys.EFAULT: there is not enough memory to write results
|
||||
//
|
||||
// For example, if environSizesGet wrote environc=2 and environLen=9 for
|
||||
// environment variables: "a=b", "b=cd" and parameters environ=11 and
|
||||
@@ -43,7 +43,7 @@ import (
|
||||
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||
var environGet = newHostFunc(wasip1.EnvironGetName, environGetFn, []api.ValueType{i32, i32}, "environ", "environ_buf")
|
||||
|
||||
func environGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func environGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||
environ, environBuf := uint32(params[0]), uint32(params[1])
|
||||
|
||||
@@ -63,7 +63,7 @@ func environGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EFAULT: there is not enough memory to write results
|
||||
// - sys.EFAULT: there is not enough memory to write results
|
||||
//
|
||||
// For example, if environ are "a=b","b=cd" and parameters resultEnvironc=1 and
|
||||
// resultEnvironvLen=6, this function writes the below to api.Memory:
|
||||
@@ -83,7 +83,7 @@ func environGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
// and https://en.wikipedia.org/wiki/Null-terminated_string
|
||||
var environSizesGet = newHostFunc(wasip1.EnvironSizesGetName, environSizesGetFn, []api.ValueType{i32, i32}, "result.environc", "result.environv_len")
|
||||
|
||||
func environSizesGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func environSizesGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||
mem := mod.Memory()
|
||||
resultEnvironc, resultEnvironvLen := uint32(params[0]), uint32(params[1])
|
||||
@@ -91,10 +91,10 @@ func environSizesGetFn(_ context.Context, mod api.Module, params []uint64) sysca
|
||||
// environc and environv_len offsets are not necessarily sequential, so we
|
||||
// have to write them independently.
|
||||
if !mem.WriteUint32Le(resultEnvironc, uint32(len(sysCtx.Environ()))) {
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
if !mem.WriteUint32Le(resultEnvironvLen, sysCtx.EnvironSize()) {
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
socketapi "github.com/tetratelabs/wazero/internal/sock"
|
||||
"github.com/tetratelabs/wazero/internal/sys"
|
||||
@@ -30,7 +31,7 @@ var fdAdvise = newHostFunc(
|
||||
"fd", "offset", "len", "advice",
|
||||
)
|
||||
|
||||
func fdAdviseFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdAdviseFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fd := int32(params[0])
|
||||
_ = params[1]
|
||||
_ = params[2]
|
||||
@@ -39,7 +40,7 @@ func fdAdviseFn(_ context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
|
||||
_, ok := fsc.LookupFile(fd)
|
||||
if !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
}
|
||||
|
||||
switch advice {
|
||||
@@ -50,7 +51,7 @@ func fdAdviseFn(_ context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
wasip1.FdAdviceDontNeed,
|
||||
wasip1.FdAdviceNoReuse:
|
||||
default:
|
||||
return syscall.EINVAL
|
||||
return experimentalsys.EINVAL
|
||||
}
|
||||
|
||||
// FdAdvice corresponds to posix_fadvise, but it can only be supported on linux.
|
||||
@@ -73,7 +74,7 @@ var fdAllocate = newHostFunc(
|
||||
"fd", "offset", "len",
|
||||
)
|
||||
|
||||
func fdAllocateFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdAllocateFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fd := int32(params[0])
|
||||
offset := params[1]
|
||||
length := params[2]
|
||||
@@ -81,12 +82,12 @@ func fdAllocateFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
f, ok := fsc.LookupFile(fd)
|
||||
if !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
}
|
||||
|
||||
tail := int64(offset + length)
|
||||
if tail < 0 {
|
||||
return syscall.EINVAL
|
||||
return experimentalsys.EINVAL
|
||||
}
|
||||
|
||||
st, errno := f.File.Stat()
|
||||
@@ -111,15 +112,15 @@ func fdAllocateFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: the fd was not open.
|
||||
// - syscall.ENOTSUP: the fs was a pre-open
|
||||
// - sys.EBADF: the fd was not open.
|
||||
// - sys.ENOTSUP: the fs was a pre-open
|
||||
//
|
||||
// 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(wasip1.FdCloseName, fdCloseFn, []api.ValueType{i32}, "fd")
|
||||
|
||||
func fdCloseFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdCloseFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
fd := int32(params[0])
|
||||
|
||||
@@ -132,13 +133,13 @@ func fdCloseFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_datasyncfd-fd---errno
|
||||
var fdDatasync = newHostFunc(wasip1.FdDatasyncName, fdDatasyncFn, []api.ValueType{i32}, "fd")
|
||||
|
||||
func fdDatasyncFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdDatasyncFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
fd := int32(params[0])
|
||||
|
||||
// Check to see if the file descriptor is available
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
} else {
|
||||
return f.File.Datasync()
|
||||
}
|
||||
@@ -155,8 +156,8 @@ func fdDatasyncFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` is invalid
|
||||
// - syscall.EFAULT: `resultFdstat` points to an offset out of memory
|
||||
// - sys.EBADF: `fd` is invalid
|
||||
// - sys.EFAULT: `resultFdstat` points to an offset out of memory
|
||||
//
|
||||
// fdstat byte layout is 24-byte size, with the following fields:
|
||||
// - fs_filetype 1 byte: the file type
|
||||
@@ -185,7 +186,7 @@ var fdFdstatGet = newHostFunc(wasip1.FdFdstatGetName, fdFdstatGetFn, []api.Value
|
||||
|
||||
// fdFdstatGetFn cannot currently use proxyResultParams because fdstat is larger
|
||||
// than api.ValueTypeI64 (i64 == 8 bytes, but fdstat is 24).
|
||||
func fdFdstatGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdFdstatGetFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
fd, resultFdstat := int32(params[0]), uint32(params[1])
|
||||
@@ -193,15 +194,15 @@ func fdFdstatGetFn(_ context.Context, mod api.Module, params []uint64) syscall.E
|
||||
// Ensure we can write the fdstat
|
||||
buf, ok := mod.Memory().Read(resultFdstat, 24)
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
|
||||
var fdflags uint16
|
||||
var st sysapi.Stat_t
|
||||
var errno syscall.Errno
|
||||
var errno experimentalsys.Errno
|
||||
f, ok := fsc.LookupFile(fd)
|
||||
if !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
} else if st, errno = f.File.Stat(); errno != 0 {
|
||||
return errno
|
||||
} else if f.File.IsAppend() {
|
||||
@@ -300,17 +301,17 @@ func writeFdstat(buf []byte, fileType uint8, fdflags uint16, fsRightsBase, fsRig
|
||||
// adjusts the flags associated with a file descriptor.
|
||||
var fdFdstatSetFlags = newHostFunc(wasip1.FdFdstatSetFlagsName, fdFdstatSetFlagsFn, []wasm.ValueType{i32, i32}, "fd", "flags")
|
||||
|
||||
func fdFdstatSetFlagsFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdFdstatSetFlagsFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fd, wasiFlag := int32(params[0]), uint16(params[1])
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
// Currently we only support APPEND and NONBLOCK.
|
||||
if wasip1.FD_DSYNC&wasiFlag != 0 || wasip1.FD_RSYNC&wasiFlag != 0 || wasip1.FD_SYNC&wasiFlag != 0 {
|
||||
return syscall.EINVAL
|
||||
return experimentalsys.EINVAL
|
||||
}
|
||||
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
} else {
|
||||
nonblock := wasip1.FD_NONBLOCK&wasiFlag != 0
|
||||
errno := f.File.SetNonblock(nonblock)
|
||||
@@ -347,9 +348,9 @@ var fdFdstatSetRights = stubFunction(
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` is invalid
|
||||
// - syscall.EIO: could not stat `fd` on filesystem
|
||||
// - syscall.EFAULT: `resultFilestat` points to an offset out of memory
|
||||
// - sys.EBADF: `fd` is invalid
|
||||
// - sys.EIO: could not stat `fd` on filesystem
|
||||
// - sys.EFAULT: `resultFilestat` points to an offset out of memory
|
||||
//
|
||||
// filestat byte layout is 64-byte size, with the following fields:
|
||||
// - dev 8 bytes: the device ID of device containing the file
|
||||
@@ -387,22 +388,22 @@ var fdFilestatGet = newHostFunc(wasip1.FdFilestatGetName, fdFilestatGetFn, []api
|
||||
|
||||
// fdFilestatGetFn cannot currently use proxyResultParams because filestat is
|
||||
// larger than api.ValueTypeI64 (i64 == 8 bytes, but filestat is 64).
|
||||
func fdFilestatGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdFilestatGetFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
return fdFilestatGetFunc(mod, int32(params[0]), uint32(params[1]))
|
||||
}
|
||||
|
||||
func fdFilestatGetFunc(mod api.Module, fd int32, resultBuf uint32) syscall.Errno {
|
||||
func fdFilestatGetFunc(mod api.Module, fd int32, resultBuf uint32) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
// Ensure we can write the filestat
|
||||
buf, ok := mod.Memory().Read(resultBuf, 64)
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
|
||||
f, ok := fsc.LookupFile(fd)
|
||||
if !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
}
|
||||
|
||||
st, errno := f.File.Stat()
|
||||
@@ -446,7 +447,7 @@ func getWasiFiletype(fm fs.FileMode) uint8 {
|
||||
}
|
||||
}
|
||||
|
||||
func writeFilestat(buf []byte, st *sysapi.Stat_t, ftype uint8) (errno syscall.Errno) {
|
||||
func writeFilestat(buf []byte, st *sysapi.Stat_t, ftype uint8) (errno experimentalsys.Errno) {
|
||||
le.PutUint64(buf, st.Dev)
|
||||
le.PutUint64(buf[8:], st.Ino)
|
||||
le.PutUint64(buf[16:], uint64(ftype))
|
||||
@@ -464,7 +465,7 @@ func writeFilestat(buf []byte, st *sysapi.Stat_t, ftype uint8) (errno syscall.Er
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_filestat_set_sizefd-fd-size-filesize---errno
|
||||
var fdFilestatSetSize = newHostFunc(wasip1.FdFilestatSetSizeName, fdFilestatSetSizeFn, []wasm.ValueType{i32, i64}, "fd", "size")
|
||||
|
||||
func fdFilestatSetSizeFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdFilestatSetSizeFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fd := int32(params[0])
|
||||
size := uint32(params[1])
|
||||
|
||||
@@ -472,7 +473,7 @@ func fdFilestatSetSizeFn(_ context.Context, mod api.Module, params []uint64) sys
|
||||
|
||||
// Check to see if the file descriptor is available
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
} else {
|
||||
return f.File.Truncate(int64(size))
|
||||
}
|
||||
@@ -488,7 +489,7 @@ var fdFilestatSetTimes = newHostFunc(
|
||||
"fd", "atim", "mtim", "fst_flags",
|
||||
)
|
||||
|
||||
func fdFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fd := int32(params[0])
|
||||
atim := int64(params[1])
|
||||
mtim := int64(params[2])
|
||||
@@ -499,7 +500,7 @@ func fdFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) sy
|
||||
|
||||
f, ok := fsc.LookupFile(fd)
|
||||
if !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
}
|
||||
|
||||
times, errno := toTimes(atim, mtim, fstFlags)
|
||||
@@ -512,19 +513,19 @@ func fdFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) sy
|
||||
|
||||
// Fall back to path based, despite it being less precise.
|
||||
switch errno {
|
||||
case syscall.EPERM, syscall.ENOSYS:
|
||||
case experimentalsys.EPERM, experimentalsys.ENOSYS:
|
||||
errno = f.FS.Utimens(f.Name, ×, true)
|
||||
}
|
||||
|
||||
return errno
|
||||
}
|
||||
|
||||
func toTimes(atim, mtime int64, fstFlags uint16) (times [2]syscall.Timespec, errno syscall.Errno) {
|
||||
func toTimes(atim, mtime int64, fstFlags uint16) (times [2]syscall.Timespec, errno experimentalsys.Errno) {
|
||||
// times[0] == atim, times[1] == mtim
|
||||
|
||||
// coerce atim into a timespec
|
||||
if set, now := fstFlags&wasip1.FstflagsAtim != 0, fstFlags&wasip1.FstflagsAtimNow != 0; set && now {
|
||||
errno = syscall.EINVAL
|
||||
errno = experimentalsys.EINVAL
|
||||
return
|
||||
} else if set {
|
||||
times[0] = syscall.NsecToTimespec(atim)
|
||||
@@ -536,7 +537,7 @@ func toTimes(atim, mtime int64, fstFlags uint16) (times [2]syscall.Timespec, err
|
||||
|
||||
// coerce mtim into a timespec
|
||||
if set, now := fstFlags&wasip1.FstflagsMtim != 0, fstFlags&wasip1.FstflagsMtimNow != 0; set && now {
|
||||
errno = syscall.EINVAL
|
||||
errno = experimentalsys.EINVAL
|
||||
return
|
||||
} else if set {
|
||||
times[1] = syscall.NsecToTimespec(mtime)
|
||||
@@ -560,7 +561,7 @@ var fdPread = newHostFunc(
|
||||
"fd", "iovs", "iovs_len", "offset", "result.nread",
|
||||
)
|
||||
|
||||
func fdPreadFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdPreadFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
return fdReadOrPread(mod, params, true)
|
||||
}
|
||||
|
||||
@@ -575,8 +576,8 @@ func fdPreadFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` is invalid or the `fd` is not a pre-opened directory
|
||||
// - syscall.EFAULT: `resultPrestat` points to an offset out of memory
|
||||
// - sys.EBADF: `fd` is invalid or the `fd` is not a pre-opened directory
|
||||
// - sys.EFAULT: `resultPrestat` points to an offset out of memory
|
||||
//
|
||||
// prestat byte layout is 8 bytes, beginning with an 8-bit tag and 3 pad bytes.
|
||||
// The only valid tag is `prestat_dir`, which is tag zero. This simplifies the
|
||||
@@ -597,7 +598,7 @@ func fdPreadFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno
|
||||
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#prestat
|
||||
var fdPrestatGet = newHostFunc(wasip1.FdPrestatGetName, fdPrestatGetFn, []api.ValueType{i32, i32}, "fd", "result.prestat")
|
||||
|
||||
func fdPrestatGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdPrestatGetFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
fd, resultPrestat := int32(params[0]), uint32(params[1])
|
||||
|
||||
@@ -610,7 +611,7 @@ func fdPrestatGetFn(_ context.Context, mod api.Module, params []uint64) syscall.
|
||||
// * Zero-value 8-bit tag, and 3-byte zero-value padding
|
||||
prestat := uint64(len(name) << 32)
|
||||
if !mod.Memory().WriteUint64Le(resultPrestat, prestat) {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -629,9 +630,9 @@ func fdPrestatGetFn(_ context.Context, mod api.Module, params []uint64) syscall.
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` is invalid
|
||||
// - syscall.EFAULT: `path` points to an offset out of memory
|
||||
// - syscall.ENAMETOOLONG: `pathLen` is longer than the actual length of the result
|
||||
// - sys.EBADF: `fd` is invalid
|
||||
// - sys.EFAULT: `path` points to an offset out of memory
|
||||
// - sys.ENAMETOOLONG: `pathLen` is longer than the actual length of the result
|
||||
//
|
||||
// For example, the directory name corresponding with `fd` was "/tmp" and
|
||||
// # Parameters path=1 pathLen=4 (correct), this function will write the below to
|
||||
@@ -651,7 +652,7 @@ var fdPrestatDirName = newHostFunc(
|
||||
"fd", "result.path", "result.path_len",
|
||||
)
|
||||
|
||||
func fdPrestatDirNameFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdPrestatDirNameFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
fd, path, pathLen := int32(params[0]), uint32(params[1]), uint32(params[2])
|
||||
|
||||
@@ -662,11 +663,11 @@ func fdPrestatDirNameFn(_ context.Context, mod api.Module, params []uint64) sysc
|
||||
|
||||
// Some runtimes may have another semantics. See /RATIONALE.md
|
||||
if uint32(len(name)) < pathLen {
|
||||
return syscall.ENAMETOOLONG
|
||||
return experimentalsys.ENAMETOOLONG
|
||||
}
|
||||
|
||||
if !mod.Memory().Write(path, []byte(name)[:pathLen]) {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -683,7 +684,7 @@ var fdPwrite = newHostFunc(
|
||||
"fd", "iovs", "iovs_len", "offset", "result.nwritten",
|
||||
)
|
||||
|
||||
func fdPwriteFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdPwriteFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
return fdWriteOrPwrite(mod, params, true)
|
||||
}
|
||||
|
||||
@@ -703,9 +704,9 @@ func fdPwriteFn(_ context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` is invalid
|
||||
// - syscall.EFAULT: `iovs` or `resultNread` point to an offset out of memory
|
||||
// - syscall.EIO: a file system error
|
||||
// - sys.EBADF: `fd` is invalid
|
||||
// - sys.EFAULT: `iovs` or `resultNread` point to an offset out of memory
|
||||
// - sys.EIO: a file system error
|
||||
//
|
||||
// For example, this function needs to first read `iovs` to determine where
|
||||
// to write contents. If parameters iovs=1 iovsCount=2, this function reads two
|
||||
@@ -749,7 +750,7 @@ type preader struct {
|
||||
}
|
||||
|
||||
// Read implements the same function as documented on fsapi.File.
|
||||
func (w *preader) Read(buf []byte) (n int, errno syscall.Errno) {
|
||||
func (w *preader) Read(buf []byte) (n int, errno experimentalsys.Errno) {
|
||||
if len(buf) == 0 {
|
||||
return 0, 0 // less overhead on zero-length reads.
|
||||
}
|
||||
@@ -759,11 +760,11 @@ func (w *preader) Read(buf []byte) (n int, errno syscall.Errno) {
|
||||
return n, err
|
||||
}
|
||||
|
||||
func fdReadFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdReadFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
return fdReadOrPread(mod, params, false)
|
||||
}
|
||||
|
||||
func fdReadOrPread(mod api.Module, params []uint64, isPread bool) syscall.Errno {
|
||||
func fdReadOrPread(mod api.Module, params []uint64, isPread bool) experimentalsys.Errno {
|
||||
mem := mod.Memory()
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
@@ -772,9 +773,9 @@ func fdReadOrPread(mod api.Module, params []uint64, isPread bool) syscall.Errno
|
||||
iovsCount := uint32(params[2])
|
||||
|
||||
var resultNread uint32
|
||||
var reader func(buf []byte) (n int, errno syscall.Errno)
|
||||
var reader func(buf []byte) (n int, errno experimentalsys.Errno)
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
} else if isPread {
|
||||
offset := int64(params[3])
|
||||
reader = (&preader{f: f.File, offset: offset}).Read
|
||||
@@ -789,18 +790,18 @@ func fdReadOrPread(mod api.Module, params []uint64, isPread bool) syscall.Errno
|
||||
return errno
|
||||
}
|
||||
if !mem.WriteUint32Le(resultNread, nread) {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func readv(mem api.Memory, iovs uint32, iovsCount uint32, reader func(buf []byte) (nread int, errno syscall.Errno)) (uint32, syscall.Errno) {
|
||||
func readv(mem api.Memory, iovs uint32, iovsCount uint32, reader func(buf []byte) (nread int, errno experimentalsys.Errno)) (uint32, experimentalsys.Errno) {
|
||||
var nread uint32
|
||||
iovsStop := iovsCount << 3 // iovsCount * 8
|
||||
iovsBuf, ok := mem.Read(iovs, iovsStop)
|
||||
if !ok {
|
||||
return 0, syscall.EFAULT
|
||||
return 0, experimentalsys.EFAULT
|
||||
}
|
||||
|
||||
for iovsPos := uint32(0); iovsPos < iovsStop; iovsPos += 8 {
|
||||
@@ -813,14 +814,14 @@ func readv(mem api.Memory, iovs uint32, iovsCount uint32, reader func(buf []byte
|
||||
|
||||
b, ok := mem.Read(offset, l)
|
||||
if !ok {
|
||||
return 0, syscall.EFAULT
|
||||
return 0, experimentalsys.EFAULT
|
||||
}
|
||||
|
||||
n, errno := reader(b)
|
||||
nread += uint32(n)
|
||||
|
||||
if errno == syscall.ENOSYS {
|
||||
return 0, syscall.EBADF // e.g. unimplemented for read
|
||||
if errno == experimentalsys.ENOSYS {
|
||||
return 0, experimentalsys.EBADF // e.g. unimplemented for read
|
||||
} else if errno != 0 {
|
||||
return 0, errno
|
||||
} else if n < int(l) {
|
||||
@@ -839,11 +840,11 @@ func readv(mem api.Memory, iovs uint32, iovsCount uint32, reader func(buf []byte
|
||||
// # Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following known error conditions:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the file was closed or not a directory.
|
||||
// - syscall.EFAULT: `buf` or `buf_len` point to an offset out of memory.
|
||||
// - syscall.ENOENT: `cookie` was invalid.
|
||||
// - syscall.EINVAL: `buf_len` was not large enough to write a dirent header.
|
||||
// - sys.ENOSYS: the implementation does not support this function.
|
||||
// - sys.EBADF: the file was closed or not a directory.
|
||||
// - sys.EFAULT: `buf` or `buf_len` point to an offset out of memory.
|
||||
// - sys.ENOENT: `cookie` was invalid.
|
||||
// - sys.EINVAL: `buf_len` was not large enough to write a dirent header.
|
||||
//
|
||||
// # End of Directory (EOF)
|
||||
//
|
||||
@@ -856,7 +857,7 @@ var fdReaddir = newHostFunc(
|
||||
"fd", "buf", "buf_len", "cookie", "result.bufused",
|
||||
)
|
||||
|
||||
func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
mem := mod.Memory()
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
@@ -870,7 +871,7 @@ func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) syscall.Err
|
||||
if bufLen < wasip1.DirentSize {
|
||||
// This is a bug in the caller, as unless `buf_len` is large enough to
|
||||
// write a dirent, it can't read the `d_namlen` from it.
|
||||
return syscall.EINVAL
|
||||
return experimentalsys.EINVAL
|
||||
}
|
||||
|
||||
// Get or open a dirent cache for this file descriptor.
|
||||
@@ -916,7 +917,7 @@ func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) syscall.Err
|
||||
|
||||
buf, ok := mem.Read(buf, bufToWrite)
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
|
||||
writeDirents(buf, dirents, d_next, direntCount, truncatedLen)
|
||||
@@ -930,7 +931,7 @@ func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) syscall.Err
|
||||
}
|
||||
|
||||
if !mem.WriteUint32Le(resultBufused, bufused) {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -1029,19 +1030,19 @@ func writeDirent(buf []byte, dNext uint64, ino sysapi.Inode, dNamlen uint32, dTy
|
||||
|
||||
// direntCache lazy opens a sys.DirentCache for this directory or returns an
|
||||
// error.
|
||||
func direntCache(fsc *sys.FSContext, fd int32) (*sys.DirentCache, syscall.Errno) {
|
||||
func direntCache(fsc *sys.FSContext, fd int32) (*sys.DirentCache, experimentalsys.Errno) {
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return nil, syscall.EBADF
|
||||
return nil, experimentalsys.EBADF
|
||||
} else if dir, errno := f.DirentCache(); errno == 0 {
|
||||
return dir, 0
|
||||
} else if errno == syscall.ENOTDIR {
|
||||
// fd_readdir docs don't indicate whether to return syscall.ENOTDIR or
|
||||
// syscall.EBADF. It has been noticed that rust will crash on syscall.ENOTDIR,
|
||||
} else if errno == experimentalsys.ENOTDIR {
|
||||
// fd_readdir docs don't indicate whether to return sys.ENOTDIR or
|
||||
// sys.EBADF. It has been noticed that rust will crash on sys.ENOTDIR,
|
||||
// and POSIX C ref seems to not return this, so we don't either.
|
||||
//
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_readdir
|
||||
// and https://en.wikibooks.org/wiki/C_Programming/POSIX_Reference/dirent.h
|
||||
return nil, syscall.EBADF
|
||||
return nil, experimentalsys.EBADF
|
||||
} else {
|
||||
return nil, errno
|
||||
}
|
||||
@@ -1053,7 +1054,7 @@ func direntCache(fsc *sys.FSContext, fd int32) (*sys.DirentCache, syscall.Errno)
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_renumberfd-fd-to-fd---errno
|
||||
var fdRenumber = newHostFunc(wasip1.FdRenumberName, fdRenumberFn, []wasm.ValueType{i32, i32}, "fd", "to")
|
||||
|
||||
func fdRenumberFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdRenumberFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
from := int32(params[0])
|
||||
@@ -1083,11 +1084,11 @@ func fdRenumberFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` is invalid
|
||||
// - syscall.EFAULT: `resultNewoffset` points to an offset out of memory
|
||||
// - syscall.EINVAL: `whence` is an invalid value
|
||||
// - syscall.EIO: a file system error
|
||||
// - syscall.EISDIR: the file was a directory.
|
||||
// - sys.EBADF: `fd` is invalid
|
||||
// - sys.EFAULT: `resultNewoffset` points to an offset out of memory
|
||||
// - sys.EINVAL: `whence` is an invalid value
|
||||
// - sys.EIO: a file system error
|
||||
// - sys.EISDIR: the file was a directory.
|
||||
//
|
||||
// For example, if fd 3 is a file with offset 0, and parameters fd=3, offset=4,
|
||||
// whence=0 (=io.SeekStart), resultNewOffset=1, this function writes the below
|
||||
@@ -1109,7 +1110,7 @@ var fdSeek = newHostFunc(
|
||||
"fd", "offset", "whence", "result.newoffset",
|
||||
)
|
||||
|
||||
func fdSeekFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdSeekFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
fd := int32(params[0])
|
||||
offset := params[1]
|
||||
@@ -1117,13 +1118,13 @@ func fdSeekFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno
|
||||
resultNewoffset := uint32(params[3])
|
||||
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
} else if isDir, _ := f.File.IsDir(); isDir {
|
||||
return syscall.EISDIR // POSIX doesn't forbid seeking a directory, but wasi-testsuite does.
|
||||
return experimentalsys.EISDIR // POSIX doesn't forbid seeking a directory, but wasi-testsuite does.
|
||||
} else if newOffset, errno := f.File.Seek(int64(offset), int(whence)); errno != 0 {
|
||||
return errno
|
||||
} else if !mod.Memory().WriteUint64Le(resultNewoffset, uint64(newOffset)) {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -1134,13 +1135,13 @@ func fdSeekFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_syncfd-fd---errno
|
||||
var fdSync = newHostFunc(wasip1.FdSyncName, fdSyncFn, []api.ValueType{i32}, "fd")
|
||||
|
||||
func fdSyncFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdSyncFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
fd := int32(params[0])
|
||||
|
||||
// Check to see if the file descriptor is available
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
} else {
|
||||
return f.File.Sync()
|
||||
}
|
||||
@@ -1152,7 +1153,7 @@ func fdSyncFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_tellfd-fd---errno-filesize
|
||||
var fdTell = newHostFunc(wasip1.FdTellName, fdTellFn, []api.ValueType{i32, i32}, "fd", "result.offset")
|
||||
|
||||
func fdTellFn(ctx context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdTellFn(ctx context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fd := params[0]
|
||||
offset := uint64(0)
|
||||
whence := uint64(io.SeekCurrent)
|
||||
@@ -1179,9 +1180,9 @@ func fdTellFn(ctx context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` is invalid
|
||||
// - syscall.EFAULT: `iovs` or `resultNwritten` point to an offset out of memory
|
||||
// - syscall.EIO: a file system error
|
||||
// - sys.EBADF: `fd` is invalid
|
||||
// - sys.EFAULT: `iovs` or `resultNwritten` point to an offset out of memory
|
||||
// - sys.EIO: a file system error
|
||||
//
|
||||
// For example, this function needs to first read `iovs` to determine what to
|
||||
// write to `fd`. If parameters iovs=1 iovsCount=2, this function reads two
|
||||
@@ -1226,7 +1227,7 @@ var fdWrite = newHostFunc(
|
||||
"fd", "iovs", "iovs_len", "result.nwritten",
|
||||
)
|
||||
|
||||
func fdWriteFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func fdWriteFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
return fdWriteOrPwrite(mod, params, false)
|
||||
}
|
||||
|
||||
@@ -1237,7 +1238,7 @@ type pwriter struct {
|
||||
}
|
||||
|
||||
// Write implements the same function as documented on fsapi.File.
|
||||
func (w *pwriter) Write(buf []byte) (n int, errno syscall.Errno) {
|
||||
func (w *pwriter) Write(buf []byte) (n int, errno experimentalsys.Errno) {
|
||||
if len(buf) == 0 {
|
||||
return 0, 0 // less overhead on zero-length writes.
|
||||
}
|
||||
@@ -1247,7 +1248,7 @@ func (w *pwriter) Write(buf []byte) (n int, errno syscall.Errno) {
|
||||
return n, err
|
||||
}
|
||||
|
||||
func fdWriteOrPwrite(mod api.Module, params []uint64, isPwrite bool) syscall.Errno {
|
||||
func fdWriteOrPwrite(mod api.Module, params []uint64, isPwrite bool) experimentalsys.Errno {
|
||||
mem := mod.Memory()
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
@@ -1256,9 +1257,9 @@ func fdWriteOrPwrite(mod api.Module, params []uint64, isPwrite bool) syscall.Err
|
||||
iovsCount := uint32(params[2])
|
||||
|
||||
var resultNwritten uint32
|
||||
var writer func(buf []byte) (n int, errno syscall.Errno)
|
||||
var writer func(buf []byte) (n int, errno experimentalsys.Errno)
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
} else if isPwrite {
|
||||
offset := int64(params[3])
|
||||
writer = (&pwriter{f: f.File, offset: offset}).Write
|
||||
@@ -1274,17 +1275,17 @@ func fdWriteOrPwrite(mod api.Module, params []uint64, isPwrite bool) syscall.Err
|
||||
}
|
||||
|
||||
if !mod.Memory().WriteUint32Le(resultNwritten, nwritten) {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func writev(mem api.Memory, iovs uint32, iovsCount uint32, writer func(buf []byte) (n int, errno syscall.Errno)) (uint32, syscall.Errno) {
|
||||
func writev(mem api.Memory, iovs uint32, iovsCount uint32, writer func(buf []byte) (n int, errno experimentalsys.Errno)) (uint32, experimentalsys.Errno) {
|
||||
var nwritten uint32
|
||||
iovsStop := iovsCount << 3 // iovsCount * 8
|
||||
iovsBuf, ok := mem.Read(iovs, iovsStop)
|
||||
if !ok {
|
||||
return 0, syscall.EFAULT
|
||||
return 0, experimentalsys.EFAULT
|
||||
}
|
||||
|
||||
for iovsPos := uint32(0); iovsPos < iovsStop; iovsPos += 8 {
|
||||
@@ -1293,12 +1294,12 @@ func writev(mem api.Memory, iovs uint32, iovsCount uint32, writer func(buf []byt
|
||||
|
||||
b, ok := mem.Read(offset, l)
|
||||
if !ok {
|
||||
return 0, syscall.EFAULT
|
||||
return 0, experimentalsys.EFAULT
|
||||
}
|
||||
n, errno := writer(b)
|
||||
nwritten += uint32(n)
|
||||
if errno == syscall.ENOSYS {
|
||||
return 0, syscall.EBADF // e.g. unimplemented for write
|
||||
if errno == experimentalsys.ENOSYS {
|
||||
return 0, experimentalsys.EBADF // e.g. unimplemented for write
|
||||
} else if errno != 0 {
|
||||
return 0, errno
|
||||
}
|
||||
@@ -1318,9 +1319,9 @@ func writev(mem api.Memory, iovs uint32, iovsCount uint32, writer func(buf []byt
|
||||
// # Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` is invalid
|
||||
// - syscall.ENOENT: `path` does not exist.
|
||||
// - syscall.ENOTDIR: `path` is a file
|
||||
// - sys.EBADF: `fd` is invalid
|
||||
// - sys.ENOENT: `path` does not exist.
|
||||
// - sys.ENOTDIR: `path` is a file
|
||||
//
|
||||
// # Notes
|
||||
// - This is similar to mkdirat in POSIX.
|
||||
@@ -1333,7 +1334,7 @@ var pathCreateDirectory = newHostFunc(
|
||||
"fd", "path", "path_len",
|
||||
)
|
||||
|
||||
func pathCreateDirectoryFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func pathCreateDirectoryFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
fd := int32(params[0])
|
||||
@@ -1366,13 +1367,13 @@ func pathCreateDirectoryFn(_ context.Context, mod api.Module, params []uint64) s
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` is invalid
|
||||
// - syscall.ENOTDIR: `fd` points to a file not a directory
|
||||
// - syscall.EIO: could not stat `fd` on filesystem
|
||||
// - syscall.EINVAL: the path contained "../"
|
||||
// - syscall.ENAMETOOLONG: `path` + `path_len` is out of memory
|
||||
// - syscall.EFAULT: `resultFilestat` points to an offset out of memory
|
||||
// - syscall.ENOENT: could not find the path
|
||||
// - sys.EBADF: `fd` is invalid
|
||||
// - sys.ENOTDIR: `fd` points to a file not a directory
|
||||
// - sys.EIO: could not stat `fd` on filesystem
|
||||
// - sys.EINVAL: the path contained "../"
|
||||
// - sys.ENAMETOOLONG: `path` + `path_len` is out of memory
|
||||
// - sys.EFAULT: `resultFilestat` points to an offset out of memory
|
||||
// - sys.ENOENT: could not find the path
|
||||
//
|
||||
// The rest of this implementation matches that of fdFilestatGet, so is not
|
||||
// repeated here.
|
||||
@@ -1386,7 +1387,7 @@ var pathFilestatGet = newHostFunc(
|
||||
"fd", "flags", "path", "path_len", "result.filestat",
|
||||
)
|
||||
|
||||
func pathFilestatGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func pathFilestatGetFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
fd := int32(params[0])
|
||||
@@ -1415,7 +1416,7 @@ func pathFilestatGetFn(_ context.Context, mod api.Module, params []uint64) sysca
|
||||
resultBuf := uint32(params[4])
|
||||
buf, ok := mod.Memory().Read(resultBuf, 64)
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
|
||||
filetype := getWasiFiletype(st.Mode)
|
||||
@@ -1432,7 +1433,7 @@ var pathFilestatSetTimes = newHostFunc(
|
||||
"fd", "flags", "path", "path_len", "atim", "mtim", "fst_flags",
|
||||
)
|
||||
|
||||
func pathFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func pathFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fd := int32(params[0])
|
||||
flags := uint16(params[1])
|
||||
path := uint32(params[2])
|
||||
@@ -1468,7 +1469,7 @@ var pathLink = newHostFunc(
|
||||
"old_fd", "old_flags", "old_path", "old_path_len", "new_fd", "new_path", "new_path_len",
|
||||
)
|
||||
|
||||
func pathLinkFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func pathLinkFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
mem := mod.Memory()
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
@@ -1493,14 +1494,14 @@ func pathLinkFn(_ context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
}
|
||||
|
||||
if oldFS != newFS { // TODO: handle link across filesystems
|
||||
return syscall.ENOSYS
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
return oldFS.Link(oldName, newName)
|
||||
}
|
||||
|
||||
// pathOpen is the WASI function named PathOpenName which opens a file or
|
||||
// directory. This returns syscall.EBADF if the fd is invalid.
|
||||
// directory. This returns sys.EBADF if the fd is invalid.
|
||||
//
|
||||
// # Parameters
|
||||
//
|
||||
@@ -1520,12 +1521,12 @@ func pathLinkFn(_ context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` is invalid
|
||||
// - syscall.EFAULT: `resultOpenedFD` points to an offset out of memory
|
||||
// - syscall.ENOENT: `path` does not exist.
|
||||
// - syscall.EEXIST: `path` exists, while `oFlags` requires that it must not.
|
||||
// - syscall.ENOTDIR: `path` is not a directory, while `oFlags` requires it.
|
||||
// - syscall.EIO: a file system error
|
||||
// - sys.EBADF: `fd` is invalid
|
||||
// - sys.EFAULT: `resultOpenedFD` points to an offset out of memory
|
||||
// - sys.ENOENT: `path` does not exist.
|
||||
// - sys.EEXIST: `path` exists, while `oFlags` requires that it must not.
|
||||
// - sys.ENOTDIR: `path` is not a directory, while `oFlags` requires it.
|
||||
// - sys.EIO: a file system error
|
||||
//
|
||||
// For example, this function needs to first read `path` to determine the file
|
||||
// to open. If parameters `path` = 1, `pathLen` = 6, and the path is "wazero",
|
||||
@@ -1558,7 +1559,7 @@ var pathOpen = newHostFunc(
|
||||
"fd", "dirflags", "path", "path_len", "oflags", "fs_rights_base", "fs_rights_inheriting", "fdflags", "result.opened_fd",
|
||||
)
|
||||
|
||||
func pathOpenFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func pathOpenFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
preopenFD := int32(params[0])
|
||||
@@ -1588,7 +1589,7 @@ func pathOpenFn(_ context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
isDir := fileOpenFlags&fsapi.O_DIRECTORY != 0
|
||||
|
||||
if isDir && oflags&wasip1.O_CREAT != 0 {
|
||||
return syscall.EINVAL // use pathCreateDirectory!
|
||||
return experimentalsys.EINVAL // use pathCreateDirectory!
|
||||
}
|
||||
|
||||
newFD, errno := fsc.OpenFile(preopen, pathName, fileOpenFlags, 0o600)
|
||||
@@ -1599,19 +1600,19 @@ func pathOpenFn(_ context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
// Check any flags that require the file to evaluate.
|
||||
if isDir {
|
||||
if f, ok := fsc.LookupFile(newFD); !ok {
|
||||
return syscall.EBADF // unexpected
|
||||
return experimentalsys.EBADF // unexpected
|
||||
} else if isDir, errno := f.File.IsDir(); errno != 0 {
|
||||
_ = fsc.CloseFile(newFD)
|
||||
return errno
|
||||
} else if !isDir {
|
||||
_ = fsc.CloseFile(newFD)
|
||||
return syscall.ENOTDIR
|
||||
return experimentalsys.ENOTDIR
|
||||
}
|
||||
}
|
||||
|
||||
if !mod.Memory().WriteUint32Le(resultOpenedFD, uint32(newFD)) {
|
||||
_ = fsc.CloseFile(newFD)
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -1632,10 +1633,10 @@ func pathOpenFn(_ context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
//
|
||||
// See https://github.com/WebAssembly/wasi-libc/blob/659ff414560721b1660a19685110e484a081c3d4/libc-bottom-half/sources/at_fdcwd.c
|
||||
// See https://linux.die.net/man/2/openat
|
||||
func atPath(fsc *sys.FSContext, mem api.Memory, fd int32, p, pathLen uint32) (fsapi.FS, string, syscall.Errno) {
|
||||
func atPath(fsc *sys.FSContext, mem api.Memory, fd int32, p, pathLen uint32) (fsapi.FS, string, experimentalsys.Errno) {
|
||||
b, ok := mem.Read(p, pathLen)
|
||||
if !ok {
|
||||
return nil, "", syscall.EFAULT
|
||||
return nil, "", experimentalsys.EFAULT
|
||||
}
|
||||
pathName := string(b)
|
||||
|
||||
@@ -1650,7 +1651,7 @@ func atPath(fsc *sys.FSContext, mem api.Memory, fd int32, p, pathLen uint32) (fs
|
||||
// interesting_paths wants to break on root paths or anything that escapes.
|
||||
// This part is the same as fs.FS.Open()
|
||||
if !fs.ValidPath(pathName) {
|
||||
return nil, "", syscall.EPERM
|
||||
return nil, "", experimentalsys.EPERM
|
||||
}
|
||||
|
||||
// add the trailing slash back
|
||||
@@ -1659,11 +1660,11 @@ func atPath(fsc *sys.FSContext, mem api.Memory, fd int32, p, pathLen uint32) (fs
|
||||
}
|
||||
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return nil, "", syscall.EBADF // closed or invalid
|
||||
return nil, "", experimentalsys.EBADF // closed or invalid
|
||||
} else if isDir, errno := f.File.IsDir(); errno != 0 {
|
||||
return nil, "", errno
|
||||
} else if !isDir {
|
||||
return nil, "", syscall.ENOTDIR
|
||||
return nil, "", experimentalsys.ENOTDIR
|
||||
} else if f.IsPreopen { // don't append the pre-open name
|
||||
return f.FS, pathName, 0
|
||||
} else {
|
||||
@@ -1672,11 +1673,11 @@ func atPath(fsc *sys.FSContext, mem api.Memory, fd int32, p, pathLen uint32) (fs
|
||||
}
|
||||
}
|
||||
|
||||
func preopenPath(fsc *sys.FSContext, fd int32) (string, syscall.Errno) {
|
||||
func preopenPath(fsc *sys.FSContext, fd int32) (string, experimentalsys.Errno) {
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return "", syscall.EBADF // closed
|
||||
return "", experimentalsys.EBADF // closed
|
||||
} else if !f.IsPreopen {
|
||||
return "", syscall.EBADF
|
||||
return "", experimentalsys.EBADF
|
||||
} else if isDir, errno := f.File.IsDir(); errno != 0 || !isDir {
|
||||
// In wasip1, only directories can be returned by fd_prestat_get as
|
||||
// there are no prestat types defined for files or sockets.
|
||||
@@ -1713,7 +1714,7 @@ func openFlags(dirflags, oflags, fdflags uint16, rights uint32) (openFlags int)
|
||||
defaultMode = syscall.O_RDWR
|
||||
}
|
||||
if fdflags&wasip1.FD_NONBLOCK != 0 {
|
||||
openFlags |= syscall.O_NONBLOCK
|
||||
openFlags |= fsapi.O_NONBLOCK
|
||||
}
|
||||
if fdflags&wasip1.FD_APPEND != 0 {
|
||||
openFlags |= syscall.O_APPEND
|
||||
@@ -1749,7 +1750,7 @@ var pathReadlink = newHostFunc(
|
||||
"fd", "path", "path_len", "buf", "buf_len", "result.bufused",
|
||||
)
|
||||
|
||||
func pathReadlinkFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func pathReadlinkFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
fd := int32(params[0])
|
||||
@@ -1760,7 +1761,7 @@ func pathReadlinkFn(_ context.Context, mod api.Module, params []uint64) syscall.
|
||||
resultBufused := uint32(params[5])
|
||||
|
||||
if pathLen == 0 || bufLen == 0 {
|
||||
return syscall.EINVAL
|
||||
return experimentalsys.EINVAL
|
||||
}
|
||||
|
||||
mem := mod.Memory()
|
||||
@@ -1775,11 +1776,11 @@ func pathReadlinkFn(_ context.Context, mod api.Module, params []uint64) syscall.
|
||||
}
|
||||
|
||||
if ok := mem.WriteString(buf, dst); !ok {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
|
||||
if !mem.WriteUint32Le(resultBufused, uint32(len(dst))) {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -1796,10 +1797,10 @@ func pathReadlinkFn(_ context.Context, mod api.Module, params []uint64) syscall.
|
||||
// # Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` is invalid
|
||||
// - syscall.ENOENT: `path` does not exist.
|
||||
// - syscall.ENOTEMPTY: `path` is not empty
|
||||
// - syscall.ENOTDIR: `path` is a file
|
||||
// - sys.EBADF: `fd` is invalid
|
||||
// - sys.ENOENT: `path` does not exist.
|
||||
// - sys.ENOTEMPTY: `path` is not empty
|
||||
// - sys.ENOTDIR: `path` is a file
|
||||
//
|
||||
// # Notes
|
||||
// - This is similar to unlinkat with AT_REMOVEDIR in POSIX.
|
||||
@@ -1812,7 +1813,7 @@ var pathRemoveDirectory = newHostFunc(
|
||||
"fd", "path", "path_len",
|
||||
)
|
||||
|
||||
func pathRemoveDirectoryFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func pathRemoveDirectoryFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
fd := int32(params[0])
|
||||
@@ -1842,10 +1843,10 @@ func pathRemoveDirectoryFn(_ context.Context, mod api.Module, params []uint64) s
|
||||
// # Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` or `new_fd` are invalid
|
||||
// - syscall.ENOENT: `old_path` does not exist.
|
||||
// - syscall.ENOTDIR: `old` is a directory and `new` exists, but is a file.
|
||||
// - syscall.EISDIR: `old` is a file and `new` exists, but is a directory.
|
||||
// - sys.EBADF: `fd` or `new_fd` are invalid
|
||||
// - sys.ENOENT: `old_path` does not exist.
|
||||
// - sys.ENOTDIR: `old` is a directory and `new` exists, but is a file.
|
||||
// - sys.EISDIR: `old` is a file and `new` exists, but is a directory.
|
||||
//
|
||||
// # Notes
|
||||
// - This is similar to unlinkat in POSIX.
|
||||
@@ -1858,7 +1859,7 @@ var pathRename = newHostFunc(
|
||||
"fd", "old_path", "old_path_len", "new_fd", "new_path", "new_path_len",
|
||||
)
|
||||
|
||||
func pathRenameFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func pathRenameFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
fd := int32(params[0])
|
||||
@@ -1880,7 +1881,7 @@ func pathRenameFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
}
|
||||
|
||||
if oldFS != newFS { // TODO: handle renames across filesystems
|
||||
return syscall.ENOSYS
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
return oldFS.Rename(oldPathName, newPathName)
|
||||
@@ -1896,7 +1897,7 @@ var pathSymlink = newHostFunc(
|
||||
"old_path", "old_path_len", "fd", "new_path", "new_path_len",
|
||||
)
|
||||
|
||||
func pathSymlinkFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func pathSymlinkFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
oldPath := uint32(params[0])
|
||||
@@ -1909,25 +1910,25 @@ func pathSymlinkFn(_ context.Context, mod api.Module, params []uint64) syscall.E
|
||||
|
||||
dir, ok := fsc.LookupFile(fd)
|
||||
if !ok {
|
||||
return syscall.EBADF // closed
|
||||
return experimentalsys.EBADF // closed
|
||||
} else if isDir, errno := dir.File.IsDir(); errno != 0 {
|
||||
return errno
|
||||
} else if !isDir {
|
||||
return syscall.ENOTDIR
|
||||
return experimentalsys.ENOTDIR
|
||||
}
|
||||
|
||||
if oldPathLen == 0 || newPathLen == 0 {
|
||||
return syscall.EINVAL
|
||||
return experimentalsys.EINVAL
|
||||
}
|
||||
|
||||
oldPathBuf, ok := mem.Read(oldPath, oldPathLen)
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
|
||||
newPathBuf, ok := mem.Read(newPath, newPathLen)
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return experimentalsys.EFAULT
|
||||
}
|
||||
|
||||
return dir.FS.Symlink(
|
||||
@@ -1956,9 +1957,9 @@ func bufToStr(buf []byte) string {
|
||||
// # Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EBADF: `fd` is invalid
|
||||
// - syscall.ENOENT: `path` does not exist.
|
||||
// - syscall.EISDIR: `path` is a directory
|
||||
// - sys.EBADF: `fd` is invalid
|
||||
// - sys.ENOENT: `path` does not exist.
|
||||
// - sys.EISDIR: `path` is a directory
|
||||
//
|
||||
// # Notes
|
||||
// - This is similar to unlinkat without AT_REMOVEDIR in POSIX.
|
||||
@@ -1971,7 +1972,7 @@ var pathUnlinkFile = newHostFunc(
|
||||
"fd", "path", "path_len",
|
||||
)
|
||||
|
||||
func pathUnlinkFileFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func pathUnlinkFileFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
fd := int32(params[0])
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/fstest"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
@@ -3520,7 +3521,7 @@ func Test_pathFilestatSetTimes(t *testing.T) {
|
||||
fsc := sys.FS()
|
||||
|
||||
var oldSt sysapi.Stat_t
|
||||
var errno syscall.Errno
|
||||
var errno experimentalsys.Errno
|
||||
if tc.expectedErrno == wasip1.ErrnoSuccess {
|
||||
oldSt, errno = fsc.RootFS().Stat(pathName)
|
||||
require.EqualErrno(t, 0, errno)
|
||||
|
||||
@@ -2,10 +2,10 @@ package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
internalsys "github.com/tetratelabs/wazero/internal/sys"
|
||||
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
@@ -18,15 +18,15 @@ import (
|
||||
//
|
||||
// - in: pointer to the subscriptions (48 bytes each)
|
||||
// - out: pointer to the resulting events (32 bytes each)
|
||||
// - nsubscriptions: count of subscriptions, zero returns syscall.EINVAL.
|
||||
// - nsubscriptions: count of subscriptions, zero returns sys.EINVAL.
|
||||
// - resultNevents: count of events.
|
||||
//
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EINVAL: the parameters are invalid
|
||||
// - syscall.ENOTSUP: a parameters is valid, but not yet supported.
|
||||
// - syscall.EFAULT: there is not enough memory to read the subscriptions or
|
||||
// - sys.EINVAL: the parameters are invalid
|
||||
// - sys.ENOTSUP: a parameters is valid, but not yet supported.
|
||||
// - sys.EFAULT: there is not enough memory to read the subscriptions or
|
||||
// write results.
|
||||
//
|
||||
// # Notes
|
||||
@@ -49,14 +49,14 @@ type event struct {
|
||||
outOffset uint32
|
||||
}
|
||||
|
||||
func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||
in := uint32(params[0])
|
||||
out := uint32(params[1])
|
||||
nsubscriptions := uint32(params[2])
|
||||
resultNevents := uint32(params[3])
|
||||
|
||||
if nsubscriptions == 0 {
|
||||
return syscall.EINVAL
|
||||
return sys.EINVAL
|
||||
}
|
||||
|
||||
mem := mod.Memory()
|
||||
@@ -64,7 +64,7 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
// Ensure capacity prior to the read loop to reduce error handling.
|
||||
inBuf, ok := mem.Read(in, nsubscriptions*48)
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
outBuf, ok := mem.Read(out, nsubscriptions*32)
|
||||
// zero-out all buffer before writing
|
||||
@@ -73,13 +73,13 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
|
||||
// Eagerly write the number of events which will equal subscriptions unless
|
||||
// there's a fault in parsing (not processing).
|
||||
if !mod.Memory().WriteUint32Le(resultNevents, nsubscriptions) {
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
|
||||
// Loop through all subscriptions and write their output.
|
||||
@@ -129,7 +129,7 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
case wasip1.EventTypeFdRead:
|
||||
fd := int32(le.Uint32(argBuf))
|
||||
if fd < 0 {
|
||||
return syscall.EBADF
|
||||
return sys.EBADF
|
||||
}
|
||||
if file, ok := fsc.LookupFile(fd); !ok {
|
||||
evt.errno = wasip1.ErrnoBadf
|
||||
@@ -147,7 +147,7 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
case wasip1.EventTypeFdWrite:
|
||||
fd := int32(le.Uint32(argBuf))
|
||||
if fd < 0 {
|
||||
return syscall.EBADF
|
||||
return sys.EBADF
|
||||
}
|
||||
if _, ok := fsc.LookupFile(fd); ok {
|
||||
evt.errno = wasip1.ErrnoNotsup
|
||||
@@ -157,7 +157,7 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
readySubs++
|
||||
writeEvent(outBuf, evt)
|
||||
default:
|
||||
return syscall.EINVAL
|
||||
return sys.EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
if len(blockingStdinSubs) > 0 {
|
||||
stdin, ok := fsc.LookupFile(internalsys.FdStdin)
|
||||
if !ok {
|
||||
return syscall.EBADF
|
||||
return sys.EBADF
|
||||
}
|
||||
// Wait for the timeout to expire, or for some data to become available on Stdin.
|
||||
stdinReady, errno := stdin.File.PollRead(&timeout)
|
||||
@@ -195,7 +195,7 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
|
||||
if readySubs != nsubscriptions {
|
||||
if !mod.Memory().WriteUint32Le(resultNevents, readySubs+clockEvents) {
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,20 +204,20 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
|
||||
// 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(inBuf []byte) (time.Duration, syscall.Errno) {
|
||||
func processClockEvent(inBuf []byte) (time.Duration, sys.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
|
||||
flags := le.Uint16(inBuf[24:32])
|
||||
|
||||
var err syscall.Errno
|
||||
var err sys.Errno
|
||||
// subclockflags has only one flag defined: subscription_clock_abstime
|
||||
switch flags {
|
||||
case 0: // relative time
|
||||
case 1: // subscription_clock_abstime
|
||||
err = syscall.ENOTSUP
|
||||
err = sys.ENOTSUP
|
||||
default: // subclockflags has only one flag defined.
|
||||
err = syscall.EINVAL
|
||||
err = sys.EINVAL
|
||||
}
|
||||
|
||||
if err != 0 {
|
||||
|
||||
@@ -3,12 +3,12 @@ package wasi_snapshot_preview1_test
|
||||
import (
|
||||
"io/fs"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/sys"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
@@ -537,7 +537,7 @@ var fdReadSub = fdReadSubFd(byte(sys.FdStdin))
|
||||
type ttyStat struct{}
|
||||
|
||||
// Stat implements the same method as documented on fsapi.File
|
||||
func (ttyStat) Stat() (sysapi.Stat_t, syscall.Errno) {
|
||||
func (ttyStat) Stat() (sysapi.Stat_t, experimentalsys.Errno) {
|
||||
return sysapi.Stat_t{
|
||||
Mode: fs.ModeDevice | fs.ModeCharDevice,
|
||||
Nlink: 1,
|
||||
@@ -555,7 +555,7 @@ type neverReadyTtyStdinFile struct {
|
||||
}
|
||||
|
||||
// PollRead implements the same method as documented on fsapi.File
|
||||
func (neverReadyTtyStdinFile) PollRead(timeout *time.Duration) (ready bool, errno syscall.Errno) {
|
||||
func (neverReadyTtyStdinFile) PollRead(timeout *time.Duration) (ready bool, errno experimentalsys.Errno) {
|
||||
time.Sleep(*timeout)
|
||||
return false, 0
|
||||
}
|
||||
@@ -567,6 +567,6 @@ type pollStdinFile struct {
|
||||
}
|
||||
|
||||
// PollRead implements the same method as documented on fsapi.File
|
||||
func (p *pollStdinFile) PollRead(*time.Duration) (ready bool, errno syscall.Errno) {
|
||||
func (p *pollStdinFile) PollRead(*time.Duration) (ready bool, errno experimentalsys.Errno) {
|
||||
return p.ready, 0
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ package wasi_snapshot_preview1
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
@@ -21,8 +21,8 @@ import (
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is ErrnoSuccess except the following error conditions:
|
||||
// - syscall.EFAULT: `buf` or `bufLen` point to an offset out of memory
|
||||
// - syscall.EIO: a file system error
|
||||
// - sys.EFAULT: `buf` or `bufLen` point to an offset out of memory
|
||||
// - sys.EIO: a file system error
|
||||
//
|
||||
// For example, if underlying random source was seeded like
|
||||
// `rand.NewSource(42)`, we expect api.Memory to contain:
|
||||
@@ -36,19 +36,19 @@ import (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-bufLen-size---errno
|
||||
var randomGet = newHostFunc(wasip1.RandomGetName, randomGetFn, []api.ValueType{i32, i32}, "buf", "buf_len")
|
||||
|
||||
func randomGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func randomGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||
randSource := sysCtx.RandSource()
|
||||
buf, bufLen := uint32(params[0]), uint32(params[1])
|
||||
|
||||
randomBytes, ok := mod.Memory().Read(buf, bufLen)
|
||||
if !ok { // out-of-range
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
|
||||
// We can ignore the returned n as it only != byteCount on error
|
||||
if _, err := io.ReadAtLeast(randSource, randomBytes, int(bufLen)); err != nil {
|
||||
return syscall.EIO
|
||||
return sys.EIO
|
||||
}
|
||||
|
||||
return 0
|
||||
|
||||
@@ -2,9 +2,9 @@ package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sched_yield---errno
|
||||
var schedYield = newHostFunc(wasip1.SchedYieldName, schedYieldFn, nil)
|
||||
|
||||
func schedYieldFn(_ context.Context, mod api.Module, _ []uint64) syscall.Errno {
|
||||
func schedYieldFn(_ context.Context, mod api.Module, _ []uint64) sys.Errno {
|
||||
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||
sysCtx.Osyield()
|
||||
return 0
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
socketapi "github.com/tetratelabs/wazero/internal/sock"
|
||||
"github.com/tetratelabs/wazero/internal/sysfs"
|
||||
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||
@@ -23,7 +24,7 @@ var sockAccept = newHostFunc(
|
||||
"fd", "flags", "result.fd",
|
||||
)
|
||||
|
||||
func sockAcceptFn(_ context.Context, mod api.Module, params []uint64) (errno syscall.Errno) {
|
||||
func sockAcceptFn(_ context.Context, mod api.Module, params []uint64) (errno sys.Errno) {
|
||||
mem := mod.Memory()
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
@@ -50,7 +51,7 @@ var sockRecv = newHostFunc(
|
||||
"fd", "ri_data", "ri_data_len", "ri_flags", "result.ro_datalen", "result.ro_flags",
|
||||
)
|
||||
|
||||
func sockRecvFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func sockRecvFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||
mem := mod.Memory()
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
@@ -63,13 +64,13 @@ func sockRecvFn(_ context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
|
||||
var conn socketapi.TCPConn
|
||||
if e, ok := fsc.LookupFile(fd); !ok {
|
||||
return syscall.EBADF // Not open
|
||||
return sys.EBADF // Not open
|
||||
} else if conn, ok = e.File.(socketapi.TCPConn); !ok {
|
||||
return syscall.EBADF // Not a conn
|
||||
return sys.EBADF // Not a conn
|
||||
}
|
||||
|
||||
if riFlags & ^(wasip1.RI_RECV_PEEK|wasip1.RI_RECV_WAITALL) != 0 {
|
||||
return syscall.ENOTSUP
|
||||
return sys.ENOTSUP
|
||||
}
|
||||
|
||||
if riFlags&wasip1.RI_RECV_PEEK != 0 {
|
||||
@@ -78,16 +79,16 @@ func sockRecvFn(_ context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
// This means that the first `uint32` is a `buf *uint8`.
|
||||
firstIovecBufAddr, ok := mem.ReadUint32Le(riData)
|
||||
if !ok {
|
||||
return syscall.EINVAL
|
||||
return sys.EINVAL
|
||||
}
|
||||
// Read bufLen
|
||||
firstIovecBufLen, ok := mem.ReadUint32Le(riData + 4)
|
||||
if !ok {
|
||||
return syscall.EINVAL
|
||||
return sys.EINVAL
|
||||
}
|
||||
firstIovecBuf, ok := mem.Read(firstIovecBufAddr, firstIovecBufLen)
|
||||
if !ok {
|
||||
return syscall.EINVAL
|
||||
return sys.EINVAL
|
||||
}
|
||||
n, err := conn.Recvfrom(firstIovecBuf, sysfs.MSG_PEEK)
|
||||
if err != 0 {
|
||||
@@ -122,7 +123,7 @@ var sockSend = newHostFunc(
|
||||
"fd", "si_data", "si_data_len", "si_flags", "result.so_datalen",
|
||||
)
|
||||
|
||||
func sockSendFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func sockSendFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||
mem := mod.Memory()
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
@@ -133,14 +134,14 @@ func sockSendFn(_ context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
resultSoDatalen := uint32(params[4])
|
||||
|
||||
if siFlags != 0 {
|
||||
return syscall.ENOTSUP
|
||||
return sys.ENOTSUP
|
||||
}
|
||||
|
||||
var conn socketapi.TCPConn
|
||||
if e, ok := fsc.LookupFile(fd); !ok {
|
||||
return syscall.EBADF // Not open
|
||||
return sys.EBADF // Not open
|
||||
} else if conn, ok = e.File.(socketapi.TCPConn); !ok {
|
||||
return syscall.EBADF // Not a conn
|
||||
return sys.EBADF // Not a conn
|
||||
}
|
||||
|
||||
bufSize, errno := writev(mem, siData, siDataCount, conn.Write)
|
||||
@@ -157,7 +158,7 @@ func sockSendFn(_ context.Context, mod api.Module, params []uint64) syscall.Errn
|
||||
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_shutdownfd-fd-how-sdflags---errno
|
||||
var sockShutdown = newHostFunc(wasip1.SockShutdownName, sockShutdownFn, []wasm.ValueType{i32, i32}, "fd", "how")
|
||||
|
||||
func sockShutdownFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func sockShutdownFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
fd := int32(params[0])
|
||||
@@ -165,9 +166,9 @@ func sockShutdownFn(_ context.Context, mod api.Module, params []uint64) syscall.
|
||||
|
||||
var conn socketapi.TCPConn
|
||||
if e, ok := fsc.LookupFile(fd); !ok {
|
||||
return syscall.EBADF // Not open
|
||||
return sys.EBADF // Not open
|
||||
} else if conn, ok = e.File.(socketapi.TCPConn); !ok {
|
||||
return syscall.EBADF // Not a conn
|
||||
return sys.EBADF // Not a conn
|
||||
}
|
||||
|
||||
sysHow := 0
|
||||
@@ -180,8 +181,9 @@ func sockShutdownFn(_ context.Context, mod api.Module, params []uint64) syscall.
|
||||
case wasip1.SD_WR:
|
||||
sysHow = syscall.SHUT_WR
|
||||
default:
|
||||
return syscall.EINVAL
|
||||
return sys.EINVAL
|
||||
}
|
||||
|
||||
// TODO: Map this instead of relying on syscall symbols.
|
||||
return conn.Shutdown(sysHow)
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/sock"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
@@ -25,7 +25,7 @@ type testSock struct {
|
||||
fsapi.UnimplementedFile
|
||||
}
|
||||
|
||||
func (t testSock) Accept() (sock.TCPConn, syscall.Errno) {
|
||||
func (t testSock) Accept() (sock.TCPConn, sys.Errno) {
|
||||
panic("no-op")
|
||||
}
|
||||
|
||||
@@ -33,10 +33,10 @@ type testConn struct {
|
||||
fsapi.UnimplementedFile
|
||||
}
|
||||
|
||||
func (t testConn) Recvfrom([]byte, int) (n int, errno syscall.Errno) {
|
||||
func (t testConn) Recvfrom([]byte, int) (n int, errno sys.Errno) {
|
||||
panic("no-op")
|
||||
}
|
||||
|
||||
func (t testConn) Shutdown(int) syscall.Errno {
|
||||
func (t testConn) Shutdown(int) sys.Errno {
|
||||
panic("no-op")
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ package wasi_snapshot_preview1
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
@@ -229,18 +229,18 @@ func exportFunctions(builder wazero.HostModuleBuilder) {
|
||||
// writeOffsetsAndNullTerminatedValues is used to write NUL-terminated values
|
||||
// for args or environ, given a pre-defined bytesLen (which includes NUL
|
||||
// terminators).
|
||||
func writeOffsetsAndNullTerminatedValues(mem api.Memory, values [][]byte, offsets, bytes, bytesLen uint32) syscall.Errno {
|
||||
func writeOffsetsAndNullTerminatedValues(mem api.Memory, values [][]byte, offsets, bytes, bytesLen uint32) sys.Errno {
|
||||
// The caller may not place bytes directly after offsets, so we have to
|
||||
// read them independently.
|
||||
valuesLen := len(values)
|
||||
offsetsLen := uint32(valuesLen * 4) // uint32Le
|
||||
offsetsBuf, ok := mem.Read(offsets, offsetsLen)
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
bytesBuf, ok := mem.Read(bytes, bytesLen)
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return sys.EFAULT
|
||||
}
|
||||
|
||||
// Loop through the values, first writing the location of its data to
|
||||
@@ -285,7 +285,7 @@ func newHostFunc(
|
||||
|
||||
// wasiFunc special cases that all WASI functions return a single Errno
|
||||
// result. The returned value will be written back to the stack at index zero.
|
||||
type wasiFunc func(ctx context.Context, mod api.Module, params []uint64) syscall.Errno
|
||||
type wasiFunc func(ctx context.Context, mod api.Module, params []uint64) sys.Errno
|
||||
|
||||
// Call implements the same method as documented on api.GoModuleFunction.
|
||||
func (f wasiFunc) Call(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
|
||||
@@ -131,7 +131,7 @@ func Benchmark_fdReaddir(b *testing.B) {
|
||||
benches := []struct {
|
||||
name string
|
||||
fs fs.FS
|
||||
// dirMount ensures direct use of syscall.FS
|
||||
// dirMount ensures direct use of fsapi.FS
|
||||
dirMount string
|
||||
// twoCalls tests performance of reading a directory in two calls.
|
||||
twoCalls bool
|
||||
@@ -243,7 +243,7 @@ func Benchmark_pathFilestat(b *testing.B) {
|
||||
benches := []struct {
|
||||
name string
|
||||
fs fs.FS
|
||||
// dirMount ensures direct use of syscall.FS
|
||||
// dirMount ensures direct use of fsapi.FS
|
||||
dirMount string
|
||||
path string
|
||||
fd int32
|
||||
|
||||
@@ -429,7 +429,7 @@ func testSock(t *testing.T, bin []byte) {
|
||||
|
||||
func Test_HTTP(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("syscall.Nonblocking() is not supported on wasip1+windows.")
|
||||
t.Skip("fsapi.Nonblocking() is not supported on wasip1+windows.")
|
||||
}
|
||||
toolchains := map[string][]byte{}
|
||||
if wasmGotip != nil {
|
||||
|
||||
+18
-18
@@ -3,9 +3,9 @@ package fsapi
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
@@ -59,8 +59,8 @@ func (DirFile) IsAppend() bool {
|
||||
}
|
||||
|
||||
// SetAppend implements File.SetAppend
|
||||
func (DirFile) SetAppend(bool) syscall.Errno {
|
||||
return syscall.EISDIR
|
||||
func (DirFile) SetAppend(bool) experimentalsys.Errno {
|
||||
return experimentalsys.EISDIR
|
||||
}
|
||||
|
||||
// IsNonblock implements File.IsNonblock
|
||||
@@ -69,41 +69,41 @@ func (DirFile) IsNonblock() bool {
|
||||
}
|
||||
|
||||
// SetNonblock implements File.SetNonblock
|
||||
func (DirFile) SetNonblock(bool) syscall.Errno {
|
||||
return syscall.EISDIR
|
||||
func (DirFile) SetNonblock(bool) experimentalsys.Errno {
|
||||
return experimentalsys.EISDIR
|
||||
}
|
||||
|
||||
// IsDir implements File.IsDir
|
||||
func (DirFile) IsDir() (bool, syscall.Errno) {
|
||||
func (DirFile) IsDir() (bool, experimentalsys.Errno) {
|
||||
return true, 0
|
||||
}
|
||||
|
||||
// Read implements File.Read
|
||||
func (DirFile) Read([]byte) (int, syscall.Errno) {
|
||||
return 0, syscall.EISDIR
|
||||
func (DirFile) Read([]byte) (int, experimentalsys.Errno) {
|
||||
return 0, experimentalsys.EISDIR
|
||||
}
|
||||
|
||||
// Pread implements File.Pread
|
||||
func (DirFile) Pread([]byte, int64) (int, syscall.Errno) {
|
||||
return 0, syscall.EISDIR
|
||||
func (DirFile) Pread([]byte, int64) (int, experimentalsys.Errno) {
|
||||
return 0, experimentalsys.EISDIR
|
||||
}
|
||||
|
||||
// PollRead implements File.PollRead
|
||||
func (DirFile) PollRead(*time.Duration) (ready bool, errno syscall.Errno) {
|
||||
return false, syscall.ENOSYS
|
||||
func (DirFile) PollRead(*time.Duration) (ready bool, errno experimentalsys.Errno) {
|
||||
return false, experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Write implements File.Write
|
||||
func (DirFile) Write([]byte) (int, syscall.Errno) {
|
||||
return 0, syscall.EISDIR
|
||||
func (DirFile) Write([]byte) (int, experimentalsys.Errno) {
|
||||
return 0, experimentalsys.EISDIR
|
||||
}
|
||||
|
||||
// Pwrite implements File.Pwrite
|
||||
func (DirFile) Pwrite([]byte, int64) (int, syscall.Errno) {
|
||||
return 0, syscall.EISDIR
|
||||
func (DirFile) Pwrite([]byte, int64) (int, experimentalsys.Errno) {
|
||||
return 0, experimentalsys.EISDIR
|
||||
}
|
||||
|
||||
// Truncate implements File.Truncate
|
||||
func (DirFile) Truncate(int64) syscall.Errno {
|
||||
return syscall.EISDIR
|
||||
func (DirFile) Truncate(int64) experimentalsys.Errno {
|
||||
return experimentalsys.EISDIR
|
||||
}
|
||||
|
||||
+77
-76
@@ -4,6 +4,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
@@ -11,14 +12,14 @@ import (
|
||||
// including WASI and runtime.GOOS=js.
|
||||
//
|
||||
// Implementations should embed UnimplementedFile for forward compatability. Any
|
||||
// unsupported method or parameter should return syscall.ENOSYS.
|
||||
// unsupported method or parameter should return ENOSYS.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// All methods that can return an error return a syscall.Errno, which is zero
|
||||
// All methods that can return an error return a Errno, which is zero
|
||||
// on success.
|
||||
//
|
||||
// Restricting to syscall.Errno matches current WebAssembly host functions,
|
||||
// Restricting to Errno matches current WebAssembly host functions,
|
||||
// which are constrained to well-known error codes. For example, `GOOS=js` maps
|
||||
// hard coded values and panics otherwise. More commonly, WASI maps syscall
|
||||
// errors to u32 numeric values.
|
||||
@@ -36,41 +37,41 @@ type File interface {
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// Possible errors are those from Stat, except syscall.ENOSYS should not
|
||||
// Possible errors are those from Stat, except ENOSYS should not
|
||||
// be returned. Zero should be returned if there is no implementation.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - Implementations should cache this result.
|
||||
// - This combined with Ino can implement os.SameFile.
|
||||
Dev() (uint64, syscall.Errno)
|
||||
Dev() (uint64, experimentalsys.Errno)
|
||||
|
||||
// Ino returns the serial number (Stat_t.Ino) of this file, zero if unknown
|
||||
// or an error retrieving it.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// Possible errors are those from Stat, except syscall.ENOSYS should not
|
||||
// Possible errors are those from Stat, except ENOSYS should not
|
||||
// be returned. Zero should be returned if there is no implementation.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - Implementations should cache this result.
|
||||
// - This combined with Dev can implement os.SameFile.
|
||||
Ino() (sys.Inode, syscall.Errno)
|
||||
Ino() (sys.Inode, experimentalsys.Errno)
|
||||
|
||||
// IsDir returns true if this file is a directory or an error there was an
|
||||
// error retrieving this information.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// Possible errors are those from Stat, except syscall.ENOSYS should not
|
||||
// Possible errors are those from Stat, except ENOSYS should not
|
||||
// be returned. false should be returned if there is no implementation.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - Implementations should cache this result.
|
||||
IsDir() (bool, syscall.Errno)
|
||||
IsDir() (bool, experimentalsys.Errno)
|
||||
|
||||
// IsNonblock returns true if the file was opened with O_NONBLOCK, or
|
||||
// SetNonblock was successfully enabled on this file.
|
||||
@@ -85,15 +86,15 @@ type File interface {
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the file or directory was closed.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EBADF: the file or directory was closed.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - This is like syscall.SetNonblock and `fcntl` with O_NONBLOCK in
|
||||
// POSIX. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html
|
||||
SetNonblock(enable bool) syscall.Errno
|
||||
SetNonblock(enable bool) experimentalsys.Errno
|
||||
|
||||
// IsAppend returns true if the file was opened with syscall.O_APPEND, or
|
||||
// SetAppend was successfully enabled on this file.
|
||||
@@ -108,24 +109,24 @@ type File interface {
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the file or directory was closed.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EBADF: the file or directory was closed.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - There is no `O_APPEND` for `fcntl` in POSIX, so implementations may
|
||||
// have to re-open the underlying file to apply this. See
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html
|
||||
SetAppend(enable bool) syscall.Errno
|
||||
SetAppend(enable bool) experimentalsys.Errno
|
||||
|
||||
// Stat is similar to syscall.Fstat.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the file or directory was closed.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EBADF: the file or directory was closed.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -134,17 +135,17 @@ type File interface {
|
||||
// - A fs.FileInfo backed implementation sets atim, mtim and ctim to the
|
||||
// same value.
|
||||
// - Windows allows you to stat a closed directory.
|
||||
Stat() (sys.Stat_t, syscall.Errno)
|
||||
Stat() (sys.Stat_t, experimentalsys.Errno)
|
||||
|
||||
// Read attempts to read all bytes in the file into `buf`, and returns the
|
||||
// count read even on error.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the file or directory was closed or not readable.
|
||||
// - syscall.EISDIR: the file was a directory.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EBADF: the file or directory was closed or not readable.
|
||||
// - EISDIR: the file was a directory.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -152,18 +153,18 @@ type File interface {
|
||||
// io.Reader. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html
|
||||
// - Unlike io.Reader, there is no io.EOF returned on end-of-file. To
|
||||
// read the file completely, the caller must repeat until `n` is zero.
|
||||
Read(buf []byte) (n int, errno syscall.Errno)
|
||||
Read(buf []byte) (n int, errno experimentalsys.Errno)
|
||||
|
||||
// Pread attempts to read all bytes in the file into `p`, starting at the
|
||||
// offset `off`, and returns the count read even on error.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the file or directory was closed or not readable.
|
||||
// - syscall.EINVAL: the offset was negative.
|
||||
// - syscall.EISDIR: the file was a directory.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EBADF: the file or directory was closed or not readable.
|
||||
// - EINVAL: the offset was negative.
|
||||
// - EISDIR: the file was a directory.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -171,7 +172,7 @@ type File interface {
|
||||
// of io.ReaderAt. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html
|
||||
// - Unlike io.ReaderAt, there is no io.EOF returned on end-of-file. To
|
||||
// read the file completely, the caller must repeat until `n` is zero.
|
||||
Pread(buf []byte, off int64) (n int, errno syscall.Errno)
|
||||
Pread(buf []byte, off int64) (n int, errno experimentalsys.Errno)
|
||||
|
||||
// Seek attempts to set the next offset for Read or Write and returns the
|
||||
// resulting absolute offset or an error.
|
||||
@@ -194,16 +195,16 @@ type File interface {
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the file or directory was closed or not readable.
|
||||
// - syscall.EINVAL: the offset was negative.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EBADF: the file or directory was closed or not readable.
|
||||
// - EINVAL: the offset was negative.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - This is like io.Seeker and `fseek` in POSIX, preferring semantics
|
||||
// of io.Seeker. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/fseek.html
|
||||
Seek(offset int64, whence int) (newOffset int64, errno syscall.Errno)
|
||||
Seek(offset int64, whence int) (newOffset int64, errno experimentalsys.Errno)
|
||||
|
||||
// PollRead returns if the file has data ready to be read or an error.
|
||||
//
|
||||
@@ -213,8 +214,8 @@ type File interface {
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -223,7 +224,7 @@ type File interface {
|
||||
// - No-op files, such as those which read from /dev/null, should return
|
||||
// immediately true to avoid hangs (because data will never become
|
||||
// available).
|
||||
PollRead(timeout *time.Duration) (ready bool, errno syscall.Errno)
|
||||
PollRead(timeout *time.Duration) (ready bool, errno experimentalsys.Errno)
|
||||
|
||||
// Readdir reads the contents of the directory associated with file and
|
||||
// returns a slice of up to n Dirent values in an arbitrary order. This is
|
||||
@@ -234,10 +235,10 @@ type File interface {
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the file was closed or not a directory.
|
||||
// - syscall.ENOENT: the directory could not be read (e.g. deleted).
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EBADF: the file was closed or not a directory.
|
||||
// - ENOENT: the directory could not be read (e.g. deleted).
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -247,88 +248,88 @@ type File interface {
|
||||
// read the directory completely, the caller must repeat until the
|
||||
// count read (`len(dirents)`) is less than `n`.
|
||||
// - See /RATIONALE.md for design notes.
|
||||
Readdir(n int) (dirents []Dirent, errno syscall.Errno)
|
||||
Readdir(n int) (dirents []Dirent, errno experimentalsys.Errno)
|
||||
|
||||
// Write attempts to write all bytes in `p` to the file, and returns the
|
||||
// count written even on error.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the file was closed, not writeable, or a directory.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EBADF: the file was closed, not writeable, or a directory.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - This is like io.Writer and `write` in POSIX, preferring semantics of
|
||||
// io.Writer. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html
|
||||
Write(buf []byte) (n int, errno syscall.Errno)
|
||||
Write(buf []byte) (n int, errno experimentalsys.Errno)
|
||||
|
||||
// Pwrite attempts to write all bytes in `p` to the file at the given
|
||||
// offset `off`, and returns the count written even on error.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the file or directory was closed or not writeable.
|
||||
// - syscall.EINVAL: the offset was negative.
|
||||
// - syscall.EISDIR: the file was a directory.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EBADF: the file or directory was closed or not writeable.
|
||||
// - EINVAL: the offset was negative.
|
||||
// - EISDIR: the file was a directory.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - This is like io.WriterAt and `pwrite` in POSIX, preferring semantics
|
||||
// of io.WriterAt. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html
|
||||
Pwrite(buf []byte, off int64) (n int, errno syscall.Errno)
|
||||
Pwrite(buf []byte, off int64) (n int, errno experimentalsys.Errno)
|
||||
|
||||
// Truncate truncates a file to a specified length.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the file or directory was closed.
|
||||
// - syscall.EINVAL: the `size` is negative.
|
||||
// - syscall.EISDIR: the file was a directory.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EBADF: the file or directory was closed.
|
||||
// - EINVAL: the `size` is negative.
|
||||
// - EISDIR: the file was a directory.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - This is like syscall.Ftruncate and `ftruncate` in POSIX. See
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
|
||||
// - Windows does not error when calling Truncate on a closed file.
|
||||
Truncate(size int64) syscall.Errno
|
||||
Truncate(size int64) experimentalsys.Errno
|
||||
|
||||
// Sync synchronizes changes to the file.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.EBADF: the file or directory was closed.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - EBADF: the file or directory was closed.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - This is like syscall.Fsync and `fsync` in POSIX. See
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html
|
||||
// - This returns with no error instead of syscall.ENOSYS when
|
||||
// - This returns with no error instead of ENOSYS when
|
||||
// unimplemented. This prevents fake filesystems from erring.
|
||||
// - Windows does not error when calling Sync on a closed file.
|
||||
Sync() syscall.Errno
|
||||
Sync() experimentalsys.Errno
|
||||
|
||||
// Datasync synchronizes the data of a file.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.EBADF: the file or directory was closed.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - EBADF: the file or directory was closed.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - This is like syscall.Fdatasync and `fdatasync` in POSIX. See
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html
|
||||
// - This returns with no error instead of syscall.ENOSYS when
|
||||
// - This returns with no error instead of ENOSYS when
|
||||
// unimplemented. This prevents fake filesystems from erring.
|
||||
// - As this is commonly missing, some implementations dispatch to Sync.
|
||||
Datasync() syscall.Errno
|
||||
Datasync() experimentalsys.Errno
|
||||
|
||||
// Utimens set file access and modification times of this file, at
|
||||
// nanosecond precision.
|
||||
@@ -342,25 +343,25 @@ type File interface {
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the file or directory was closed.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EBADF: the file or directory was closed.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - This is like syscall.UtimesNano and `futimens` in POSIX. See
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html
|
||||
// - Windows requires files to be open with syscall.O_RDWR, which means you
|
||||
// cannot use this to update timestamps on a directory (syscall.EPERM).
|
||||
Utimens(times *[2]syscall.Timespec) syscall.Errno
|
||||
// cannot use this to update timestamps on a directory (EPERM).
|
||||
Utimens(times *[2]syscall.Timespec) experimentalsys.Errno
|
||||
|
||||
// Close closes the underlying file.
|
||||
//
|
||||
// A zero syscall.Errno is returned if unimplemented or success.
|
||||
// A zero Errno is returned if unimplemented or success.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - This is like syscall.Close and `close` in POSIX. See
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
|
||||
Close() syscall.Errno
|
||||
Close() experimentalsys.Errno
|
||||
}
|
||||
|
||||
+81
-78
@@ -4,6 +4,7 @@ import (
|
||||
"io/fs"
|
||||
"syscall"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
@@ -11,14 +12,14 @@ import (
|
||||
// including WASI and runtime.GOOS=js.
|
||||
//
|
||||
// Implementations should embed UnimplementedFS for forward compatability. Any
|
||||
// unsupported method or parameter should return syscall.ENO
|
||||
// unsupported method or parameter should return ENO
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// All methods that can return an error return a syscall.Errno, which is zero
|
||||
// All methods that can return an error return a Errno, which is zero
|
||||
// on success.
|
||||
//
|
||||
// Restricting to syscall.Errno matches current WebAssembly host functions,
|
||||
// Restricting to Errno matches current WebAssembly host functions,
|
||||
// which are constrained to well-known error codes. For example, `GOOS=js` maps
|
||||
// hard coded values and panics otherwise. More commonly, WASI maps syscall
|
||||
// errors to u32 numeric values.
|
||||
@@ -32,12 +33,12 @@ type FS interface {
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EINVAL: `path` or `flag` is invalid.
|
||||
// - syscall.EISDIR: the path was a directory, but flag included
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EINVAL: `path` or `flag` is invalid.
|
||||
// - EISDIR: the path was a directory, but flag included
|
||||
// syscall.O_RDWR or syscall.O_WRONLY
|
||||
// - syscall.ENOENT: `path` doesn't exist and `flag` doesn't contain
|
||||
// - ENOENT: `path` doesn't exist and `flag` doesn't contain
|
||||
// os.O_CREATE.
|
||||
//
|
||||
// # Constraints on the returned file
|
||||
@@ -45,7 +46,7 @@ type FS interface {
|
||||
// Implementations that can read flags should enforce them regardless of
|
||||
// the type returned. For example, while os.File implements io.Writer,
|
||||
// attempts to write to a directory or a file opened with os.O_RDONLY fail
|
||||
// with a syscall.EBADF.
|
||||
// with a EBADF.
|
||||
//
|
||||
// Some implementations choose whether to enforce read-only opens, namely
|
||||
// fs.FS. While fs.FS is supported (Adapt), wazero cannot runtime enforce
|
||||
@@ -55,21 +56,22 @@ type FS interface {
|
||||
// # Notes
|
||||
//
|
||||
// - This is like os.OpenFile, except the path is relative to this file
|
||||
// system, and syscall.Errno is returned instead of os.PathError.
|
||||
// system, and Errno is returned instead of os.PathError.
|
||||
// - flag are the same as os.OpenFile, for example, os.O_CREATE.
|
||||
// - Implications of permissions when os.O_CREATE are described in Chmod
|
||||
// notes.
|
||||
// - This is like `open` in POSIX. See
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html
|
||||
OpenFile(path string, flag int, perm fs.FileMode) (File, syscall.Errno)
|
||||
OpenFile(path string, flag int, perm fs.FileMode) (File, experimentalsys.Errno)
|
||||
// TODO: make sure all flags are not in the syscall package
|
||||
|
||||
// Lstat gets file status without following symbolic links.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.ENOENT: `path` doesn't exist.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - ENOENT: `path` doesn't exist.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -81,15 +83,15 @@ type FS interface {
|
||||
// same value.
|
||||
// - When the path is a symbolic link, the stat returned is for the link,
|
||||
// not the file it refers to.
|
||||
Lstat(path string) (sys.Stat_t, syscall.Errno)
|
||||
Lstat(path string) (sys.Stat_t, experimentalsys.Errno)
|
||||
|
||||
// Stat gets file status.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.ENOENT: `path` doesn't exist.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - ENOENT: `path` doesn't exist.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -101,17 +103,17 @@ type FS interface {
|
||||
// same value.
|
||||
// - When the path is a symbolic link, the stat returned is for the file
|
||||
// it refers to.
|
||||
Stat(path string) (sys.Stat_t, syscall.Errno)
|
||||
Stat(path string) (sys.Stat_t, experimentalsys.Errno)
|
||||
|
||||
// Mkdir makes a directory.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EINVAL: `path` is invalid.
|
||||
// - syscall.EEXIST: `path` exists and is a directory.
|
||||
// - syscall.ENOTDIR: `path` exists and is a file.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EINVAL: `path` is invalid.
|
||||
// - EEXIST: `path` exists and is a directory.
|
||||
// - ENOTDIR: `path` exists and is a file.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -120,16 +122,16 @@ type FS interface {
|
||||
// - This is like `mkdir` in POSIX. See
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html
|
||||
// - Implications of permissions are described in Chmod notes.
|
||||
Mkdir(path string, perm fs.FileMode) syscall.Errno
|
||||
Mkdir(path string, perm fs.FileMode) experimentalsys.Errno
|
||||
|
||||
// Chmod changes the mode of the file.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EINVAL: `path` is invalid.
|
||||
// - syscall.ENOENT: `path` does not exist.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EINVAL: `path` is invalid.
|
||||
// - ENOENT: `path` does not exist.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -140,19 +142,19 @@ type FS interface {
|
||||
// - Windows ignores the execute bit, and any permissions come back as
|
||||
// group and world. For example, chmod of 0400 reads back as 0444, and
|
||||
// 0700 0666. Also, permissions on directories aren't supported at all.
|
||||
Chmod(path string, perm fs.FileMode) syscall.Errno
|
||||
Chmod(path string, perm fs.FileMode) experimentalsys.Errno
|
||||
|
||||
// Rename renames file or directory.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EINVAL: `from` or `to` is invalid.
|
||||
// - syscall.ENOENT: `from` or `to` don't exist.
|
||||
// - syscall.ENOTDIR: `from` is a directory and `to` exists as a file.
|
||||
// - syscall.EISDIR: `from` is a file and `to` exists as a directory.
|
||||
// - syscall.ENOTEMPTY: `both from` and `to` are existing directory, but
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EINVAL: `from` or `to` is invalid.
|
||||
// - ENOENT: `from` or `to` don't exist.
|
||||
// - ENOTDIR: `from` is a directory and `to` exists as a file.
|
||||
// - EISDIR: `from` is a file and `to` exists as a directory.
|
||||
// - ENOTEMPTY: `both from` and `to` are existing directory, but
|
||||
// `to` is not empty.
|
||||
//
|
||||
// # Notes
|
||||
@@ -162,18 +164,18 @@ type FS interface {
|
||||
// - This is like `rename` in POSIX. See
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html
|
||||
// - Windows doesn't let you overwrite an existing directory.
|
||||
Rename(from, to string) syscall.Errno
|
||||
Rename(from, to string) experimentalsys.Errno
|
||||
|
||||
// Rmdir removes a directory.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EINVAL: `path` is invalid.
|
||||
// - syscall.ENOENT: `path` doesn't exist.
|
||||
// - syscall.ENOTDIR: `path` exists, but isn't a directory.
|
||||
// - syscall.ENOTEMPTY: `path` exists, but isn't empty.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EINVAL: `path` is invalid.
|
||||
// - ENOENT: `path` doesn't exist.
|
||||
// - ENOTDIR: `path` exists, but isn't a directory.
|
||||
// - ENOTEMPTY: `path` exists, but isn't empty.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -181,18 +183,18 @@ type FS interface {
|
||||
// file system.
|
||||
// - This is like `rmdir` in POSIX. See
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html
|
||||
// - As of Go 1.19, Windows maps syscall.ENOTDIR to syscall.ENOENT.
|
||||
Rmdir(path string) syscall.Errno
|
||||
// - As of Go 1.19, Windows maps ENOTDIR to ENOENT.
|
||||
Rmdir(path string) experimentalsys.Errno
|
||||
|
||||
// Unlink removes a directory entry.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EINVAL: `path` is invalid.
|
||||
// - syscall.ENOENT: `path` doesn't exist.
|
||||
// - syscall.EISDIR: `path` exists, but is a directory.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EINVAL: `path` is invalid.
|
||||
// - ENOENT: `path` doesn't exist.
|
||||
// - EISDIR: `path` exists, but is a directory.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -203,18 +205,18 @@ type FS interface {
|
||||
// - On Windows, syscall.Unlink doesn't delete symlink to directory unlike other platforms. Implementations might
|
||||
// want to combine syscall.RemoveDirectory with syscall.Unlink in order to delete such links on Windows.
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya
|
||||
Unlink(path string) syscall.Errno
|
||||
Unlink(path string) experimentalsys.Errno
|
||||
|
||||
// Link creates a "hard" link from oldPath to newPath, in contrast to a
|
||||
// soft link (via Symlink).
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EPERM: `oldPath` is invalid.
|
||||
// - syscall.ENOENT: `oldPath` doesn't exist.
|
||||
// - syscall.EISDIR: `newPath` exists, but is a directory.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EPERM: `oldPath` is invalid.
|
||||
// - ENOENT: `oldPath` doesn't exist.
|
||||
// - EISDIR: `newPath` exists, but is a directory.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -222,17 +224,17 @@ type FS interface {
|
||||
// file system.
|
||||
// - This is like `link` in POSIX. See
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/link.html
|
||||
Link(oldPath, newPath string) syscall.Errno
|
||||
Link(oldPath, newPath string) experimentalsys.Errno
|
||||
|
||||
// Symlink creates a "soft" link from oldPath to newPath, in contrast to a
|
||||
// hard link (via Link).
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EPERM: `oldPath` or `newPath` is invalid.
|
||||
// - syscall.EEXIST: `newPath` exists.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EPERM: `oldPath` or `newPath` is invalid.
|
||||
// - EEXIST: `newPath` exists.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -246,17 +248,17 @@ type FS interface {
|
||||
// See https://github.com/bytecodealliance/cap-std/blob/v1.0.4/cap-std/src/fs/dir.rs#L404-L409
|
||||
// for how others implement this.
|
||||
// - Symlinks in Windows requires `SeCreateSymbolicLinkPrivilege`.
|
||||
// Otherwise, syscall.EPERM results.
|
||||
// Otherwise, EPERM results.
|
||||
// See https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
|
||||
Symlink(oldPath, linkName string) syscall.Errno
|
||||
Symlink(oldPath, linkName string) experimentalsys.Errno
|
||||
|
||||
// Readlink reads the contents of a symbolic link.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EINVAL: `path` is invalid.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EINVAL: `path` is invalid.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
@@ -267,7 +269,7 @@ type FS interface {
|
||||
// - On Windows, the path separator is different from other platforms,
|
||||
// but to provide consistent results to Wasm, this normalizes to a "/"
|
||||
// separator.
|
||||
Readlink(path string) (string, syscall.Errno)
|
||||
Readlink(path string) (string, experimentalsys.Errno)
|
||||
|
||||
// Utimens set file access and modification times on a path relative to
|
||||
// this file system, at nanosecond precision.
|
||||
@@ -275,25 +277,26 @@ type FS interface {
|
||||
// # Parameters
|
||||
//
|
||||
// The `times` parameter includes the access and modification timestamps to
|
||||
// assign. Special syscall.Timespec NSec values platform.UTIME_NOW and
|
||||
// platform.UTIME_OMIT may be specified instead of real timestamps. A nil
|
||||
// `times` parameter behaves the same as if both were set to
|
||||
// platform.UTIME_NOW.
|
||||
// assign. Special syscall.Timespec NSec values UTIME_NOW and UTIME_OMIT
|
||||
// may be specified instead of real timestamps. A nil `times` parameter
|
||||
// behaves the same as if both were set to UTIME_NOW.
|
||||
//
|
||||
// When the `symlinkFollow` parameter is true and the path is a symbolic link,
|
||||
// the target of expanding that link is updated.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EINVAL: `path` is invalid.
|
||||
// - syscall.EEXIST: `path` exists and is a directory.
|
||||
// - syscall.ENOTDIR: `path` exists and is a file.
|
||||
// A zero Errno is success. The below are expected otherwise:
|
||||
// - ENOSYS: the implementation does not support this function.
|
||||
// - EINVAL: `path` is invalid.
|
||||
// - EEXIST: `path` exists and is a directory.
|
||||
// - ENOTDIR: `path` exists and is a file.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - This is like syscall.UtimesNano and `utimensat` with `AT_FDCWD` in
|
||||
// POSIX. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html
|
||||
Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) syscall.Errno
|
||||
Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) experimentalsys.Errno
|
||||
// TODO: change impl to not use syscall package,
|
||||
// possibly by being just a pair of int64s..
|
||||
}
|
||||
|
||||
@@ -5,10 +5,11 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
// UnimplementedFS is an FS that returns syscall.ENOSYS for all functions,
|
||||
// UnimplementedFS is an FS that returns ENOSYS for all functions,
|
||||
// This should be embedded to have forward compatible implementations.
|
||||
type UnimplementedFS struct{}
|
||||
|
||||
@@ -19,92 +20,92 @@ func (UnimplementedFS) String() string {
|
||||
|
||||
// Open implements the same method as documented on fs.FS
|
||||
func (UnimplementedFS) Open(name string) (fs.File, error) {
|
||||
return nil, &fs.PathError{Op: "open", Path: name, Err: syscall.ENOSYS}
|
||||
return nil, &fs.PathError{Op: "open", Path: name, Err: experimentalsys.ENOSYS}
|
||||
}
|
||||
|
||||
// OpenFile implements FS.OpenFile
|
||||
func (UnimplementedFS) OpenFile(path string, flag int, perm fs.FileMode) (File, syscall.Errno) {
|
||||
return nil, syscall.ENOSYS
|
||||
func (UnimplementedFS) OpenFile(path string, flag int, perm fs.FileMode) (File, experimentalsys.Errno) {
|
||||
return nil, experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Lstat implements FS.Lstat
|
||||
func (UnimplementedFS) Lstat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
return sys.Stat_t{}, syscall.ENOSYS
|
||||
func (UnimplementedFS) Lstat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
return sys.Stat_t{}, experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Stat implements FS.Stat
|
||||
func (UnimplementedFS) Stat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
return sys.Stat_t{}, syscall.ENOSYS
|
||||
func (UnimplementedFS) Stat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
return sys.Stat_t{}, experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Readlink implements FS.Readlink
|
||||
func (UnimplementedFS) Readlink(path string) (string, syscall.Errno) {
|
||||
return "", syscall.ENOSYS
|
||||
func (UnimplementedFS) Readlink(path string) (string, experimentalsys.Errno) {
|
||||
return "", experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Mkdir implements FS.Mkdir
|
||||
func (UnimplementedFS) Mkdir(path string, perm fs.FileMode) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFS) Mkdir(path string, perm fs.FileMode) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Chmod implements FS.Chmod
|
||||
func (UnimplementedFS) Chmod(path string, perm fs.FileMode) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFS) Chmod(path string, perm fs.FileMode) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Rename implements FS.Rename
|
||||
func (UnimplementedFS) Rename(from, to string) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFS) Rename(from, to string) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Rmdir implements FS.Rmdir
|
||||
func (UnimplementedFS) Rmdir(path string) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFS) Rmdir(path string) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Link implements FS.Link
|
||||
func (UnimplementedFS) Link(_, _ string) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFS) Link(_, _ string) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Symlink implements FS.Symlink
|
||||
func (UnimplementedFS) Symlink(_, _ string) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFS) Symlink(_, _ string) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Unlink implements FS.Unlink
|
||||
func (UnimplementedFS) Unlink(path string) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFS) Unlink(path string) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Utimens implements FS.Utimens
|
||||
func (UnimplementedFS) Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFS) Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Truncate implements FS.Truncate
|
||||
func (UnimplementedFS) Truncate(string, int64) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFS) Truncate(string, int64) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// UnimplementedFile is a File that returns syscall.ENOSYS for all functions,
|
||||
// UnimplementedFile is a File that returns ENOSYS for all functions,
|
||||
// except where no-op are otherwise documented.
|
||||
//
|
||||
// This should be embedded to have forward compatible implementations.
|
||||
type UnimplementedFile struct{}
|
||||
|
||||
// Dev implements File.Dev
|
||||
func (UnimplementedFile) Dev() (uint64, syscall.Errno) {
|
||||
func (UnimplementedFile) Dev() (uint64, experimentalsys.Errno) {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// Ino implements File.Ino
|
||||
func (UnimplementedFile) Ino() (sys.Inode, syscall.Errno) {
|
||||
func (UnimplementedFile) Ino() (sys.Inode, experimentalsys.Errno) {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// IsDir implements File.IsDir
|
||||
func (UnimplementedFile) IsDir() (bool, syscall.Errno) {
|
||||
func (UnimplementedFile) IsDir() (bool, experimentalsys.Errno) {
|
||||
return false, 0
|
||||
}
|
||||
|
||||
@@ -114,8 +115,8 @@ func (UnimplementedFile) IsAppend() bool {
|
||||
}
|
||||
|
||||
// SetAppend implements File.SetAppend
|
||||
func (UnimplementedFile) SetAppend(bool) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFile) SetAppend(bool) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// IsNonblock implements File.IsNonblock
|
||||
@@ -124,69 +125,69 @@ func (UnimplementedFile) IsNonblock() bool {
|
||||
}
|
||||
|
||||
// SetNonblock implements File.SetNonblock
|
||||
func (UnimplementedFile) SetNonblock(bool) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFile) SetNonblock(bool) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Stat implements File.Stat
|
||||
func (UnimplementedFile) Stat() (sys.Stat_t, syscall.Errno) {
|
||||
return sys.Stat_t{}, syscall.ENOSYS
|
||||
func (UnimplementedFile) Stat() (sys.Stat_t, experimentalsys.Errno) {
|
||||
return sys.Stat_t{}, experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Read implements File.Read
|
||||
func (UnimplementedFile) Read([]byte) (int, syscall.Errno) {
|
||||
return 0, syscall.ENOSYS
|
||||
func (UnimplementedFile) Read([]byte) (int, experimentalsys.Errno) {
|
||||
return 0, experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Pread implements File.Pread
|
||||
func (UnimplementedFile) Pread([]byte, int64) (int, syscall.Errno) {
|
||||
return 0, syscall.ENOSYS
|
||||
func (UnimplementedFile) Pread([]byte, int64) (int, experimentalsys.Errno) {
|
||||
return 0, experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Seek implements File.Seek
|
||||
func (UnimplementedFile) Seek(int64, int) (int64, syscall.Errno) {
|
||||
return 0, syscall.ENOSYS
|
||||
func (UnimplementedFile) Seek(int64, int) (int64, experimentalsys.Errno) {
|
||||
return 0, experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Readdir implements File.Readdir
|
||||
func (UnimplementedFile) Readdir(int) (dirents []Dirent, errno syscall.Errno) {
|
||||
return nil, syscall.ENOSYS
|
||||
func (UnimplementedFile) Readdir(int) (dirents []Dirent, errno experimentalsys.Errno) {
|
||||
return nil, experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// PollRead implements File.PollRead
|
||||
func (UnimplementedFile) PollRead(*time.Duration) (ready bool, errno syscall.Errno) {
|
||||
return false, syscall.ENOSYS
|
||||
func (UnimplementedFile) PollRead(*time.Duration) (ready bool, errno experimentalsys.Errno) {
|
||||
return false, experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Write implements File.Write
|
||||
func (UnimplementedFile) Write([]byte) (int, syscall.Errno) {
|
||||
return 0, syscall.ENOSYS
|
||||
func (UnimplementedFile) Write([]byte) (int, experimentalsys.Errno) {
|
||||
return 0, experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Pwrite implements File.Pwrite
|
||||
func (UnimplementedFile) Pwrite([]byte, int64) (int, syscall.Errno) {
|
||||
return 0, syscall.ENOSYS
|
||||
func (UnimplementedFile) Pwrite([]byte, int64) (int, experimentalsys.Errno) {
|
||||
return 0, experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Truncate implements File.Truncate
|
||||
func (UnimplementedFile) Truncate(int64) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFile) Truncate(int64) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Sync implements File.Sync
|
||||
func (UnimplementedFile) Sync() syscall.Errno {
|
||||
return 0 // not syscall.ENOSYS
|
||||
func (UnimplementedFile) Sync() experimentalsys.Errno {
|
||||
return 0 // not ENOSYS
|
||||
}
|
||||
|
||||
// Datasync implements File.Datasync
|
||||
func (UnimplementedFile) Datasync() syscall.Errno {
|
||||
return 0 // not syscall.ENOSYS
|
||||
func (UnimplementedFile) Datasync() experimentalsys.Errno {
|
||||
return 0 // not ENOSYS
|
||||
}
|
||||
|
||||
// Utimens implements File.Utimens
|
||||
func (UnimplementedFile) Utimens(*[2]syscall.Timespec) syscall.Errno {
|
||||
return syscall.ENOSYS
|
||||
func (UnimplementedFile) Utimens(*[2]syscall.Timespec) experimentalsys.Errno {
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Close implements File.Close
|
||||
func (UnimplementedFile) Close() (errno syscall.Errno) { return }
|
||||
func (UnimplementedFile) Close() (errno experimentalsys.Errno) { return }
|
||||
|
||||
+31
-32
@@ -2,9 +2,8 @@ package gojs
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
// Errno is a (GOARCH=wasm) error, which must match a key in mapJSError.
|
||||
@@ -62,50 +61,50 @@ var (
|
||||
|
||||
// ToErrno maps I/O errors as the message must be the code, ex. "EINVAL", not
|
||||
// the message, e.g. "invalid argument".
|
||||
//
|
||||
// This should match wasi_snapshot_preview1.ToErrno for maintenance ease.
|
||||
func ToErrno(err error) *Errno {
|
||||
if err == nil || err == io.EOF {
|
||||
return nil // io.EOF has no value in GOOS=js, and isn't an error.
|
||||
}
|
||||
errno := platform.UnwrapOSError(err)
|
||||
|
||||
switch errno {
|
||||
case syscall.EACCES:
|
||||
return ErrnoAcces
|
||||
case syscall.EAGAIN:
|
||||
return ErrnoAgain
|
||||
case syscall.EBADF:
|
||||
return ErrnoBadf
|
||||
case syscall.EEXIST:
|
||||
return ErrnoExist
|
||||
case syscall.EFAULT:
|
||||
return ErrnoFault
|
||||
case syscall.EINTR:
|
||||
return ErrnoIntr
|
||||
case syscall.EINVAL:
|
||||
return ErrnoInval
|
||||
case syscall.EIO:
|
||||
errno, ok := err.(sys.Errno)
|
||||
if !ok {
|
||||
return ErrnoIo
|
||||
case syscall.EISDIR:
|
||||
}
|
||||
switch errno {
|
||||
case sys.EACCES:
|
||||
return ErrnoAcces
|
||||
case sys.EAGAIN:
|
||||
return ErrnoAgain
|
||||
case sys.EBADF:
|
||||
return ErrnoBadf
|
||||
case sys.EEXIST:
|
||||
return ErrnoExist
|
||||
case sys.EFAULT:
|
||||
return ErrnoFault
|
||||
case sys.EINTR:
|
||||
return ErrnoIntr
|
||||
case sys.EINVAL:
|
||||
return ErrnoInval
|
||||
case sys.EIO:
|
||||
return ErrnoIo
|
||||
case sys.EISDIR:
|
||||
return ErrnoIsdir
|
||||
case syscall.ELOOP:
|
||||
case sys.ELOOP:
|
||||
return ErrnoLoop
|
||||
case syscall.ENAMETOOLONG:
|
||||
case sys.ENAMETOOLONG:
|
||||
return ErrnoNametoolong
|
||||
case syscall.ENOENT:
|
||||
case sys.ENOENT:
|
||||
return ErrnoNoent
|
||||
case syscall.ENOSYS:
|
||||
case sys.ENOSYS:
|
||||
return ErrnoNosys
|
||||
case syscall.ENOTDIR:
|
||||
case sys.ENOTDIR:
|
||||
return ErrnoNotdir
|
||||
case syscall.ENOTEMPTY:
|
||||
case sys.ENOTEMPTY:
|
||||
return ErrnoNotempty
|
||||
case syscall.ENOTSUP:
|
||||
case sys.ENOTSUP:
|
||||
return ErrnoNotsup
|
||||
case syscall.EPERM:
|
||||
case sys.EPERM:
|
||||
return ErrnoPerm
|
||||
case syscall.EROFS:
|
||||
case sys.EROFS:
|
||||
return ErrnoRofs
|
||||
default:
|
||||
return ErrnoIo
|
||||
|
||||
+40
-39
@@ -2,8 +2,9 @@ package gojs
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func TestToErrno(t *testing.T) {
|
||||
@@ -20,98 +21,98 @@ func TestToErrno(t *testing.T) {
|
||||
input: io.EOF,
|
||||
},
|
||||
{
|
||||
name: "syscall.EACCES",
|
||||
input: syscall.EACCES,
|
||||
name: "sys.EACCES",
|
||||
input: sys.EACCES,
|
||||
expected: ErrnoAcces,
|
||||
},
|
||||
{
|
||||
name: "syscall.EAGAIN",
|
||||
input: syscall.EAGAIN,
|
||||
name: "sys.EAGAIN",
|
||||
input: sys.EAGAIN,
|
||||
expected: ErrnoAgain,
|
||||
},
|
||||
{
|
||||
name: "syscall.EBADF",
|
||||
input: syscall.EBADF,
|
||||
name: "sys.EBADF",
|
||||
input: sys.EBADF,
|
||||
expected: ErrnoBadf,
|
||||
},
|
||||
{
|
||||
name: "syscall.EEXIST",
|
||||
input: syscall.EEXIST,
|
||||
name: "sys.EEXIST",
|
||||
input: sys.EEXIST,
|
||||
expected: ErrnoExist,
|
||||
},
|
||||
{
|
||||
name: "syscall.EFAULT",
|
||||
input: syscall.EFAULT,
|
||||
name: "sys.EFAULT",
|
||||
input: sys.EFAULT,
|
||||
expected: ErrnoFault,
|
||||
},
|
||||
{
|
||||
name: "syscall.EINTR",
|
||||
input: syscall.EINTR,
|
||||
name: "sys.EINTR",
|
||||
input: sys.EINTR,
|
||||
expected: ErrnoIntr,
|
||||
},
|
||||
{
|
||||
name: "syscall.EINVAL",
|
||||
input: syscall.EINVAL,
|
||||
name: "sys.EINVAL",
|
||||
input: sys.EINVAL,
|
||||
expected: ErrnoInval,
|
||||
},
|
||||
{
|
||||
name: "syscall.EIO",
|
||||
input: syscall.EIO,
|
||||
name: "sys.EIO",
|
||||
input: sys.EIO,
|
||||
expected: ErrnoIo,
|
||||
},
|
||||
{
|
||||
name: "syscall.EISDIR",
|
||||
input: syscall.EISDIR,
|
||||
name: "sys.EISDIR",
|
||||
input: sys.EISDIR,
|
||||
expected: ErrnoIsdir,
|
||||
},
|
||||
{
|
||||
name: "syscall.ELOOP",
|
||||
input: syscall.ELOOP,
|
||||
name: "sys.ELOOP",
|
||||
input: sys.ELOOP,
|
||||
expected: ErrnoLoop,
|
||||
},
|
||||
{
|
||||
name: "syscall.ENAMETOOLONG",
|
||||
input: syscall.ENAMETOOLONG,
|
||||
name: "sys.ENAMETOOLONG",
|
||||
input: sys.ENAMETOOLONG,
|
||||
expected: ErrnoNametoolong,
|
||||
},
|
||||
{
|
||||
name: "syscall.ENOENT",
|
||||
input: syscall.ENOENT,
|
||||
name: "sys.ENOENT",
|
||||
input: sys.ENOENT,
|
||||
expected: ErrnoNoent,
|
||||
},
|
||||
{
|
||||
name: "syscall.ENOSYS",
|
||||
input: syscall.ENOSYS,
|
||||
name: "sys.ENOSYS",
|
||||
input: sys.ENOSYS,
|
||||
expected: ErrnoNosys,
|
||||
},
|
||||
{
|
||||
name: "syscall.ENOTDIR",
|
||||
input: syscall.ENOTDIR,
|
||||
name: "sys.ENOTDIR",
|
||||
input: sys.ENOTDIR,
|
||||
expected: ErrnoNotdir,
|
||||
},
|
||||
{
|
||||
name: "syscall.ENOTEMPTY",
|
||||
input: syscall.ENOTEMPTY,
|
||||
name: "sys.ENOTEMPTY",
|
||||
input: sys.ENOTEMPTY,
|
||||
expected: ErrnoNotempty,
|
||||
},
|
||||
{
|
||||
name: "syscall.ENOTSUP",
|
||||
input: syscall.ENOTSUP,
|
||||
name: "sys.ENOTSUP",
|
||||
input: sys.ENOTSUP,
|
||||
expected: ErrnoNotsup,
|
||||
},
|
||||
{
|
||||
name: "syscall.EPERM",
|
||||
input: syscall.EPERM,
|
||||
name: "sys.EPERM",
|
||||
input: sys.EPERM,
|
||||
expected: ErrnoPerm,
|
||||
},
|
||||
{
|
||||
name: "syscall.EROFS",
|
||||
input: syscall.EROFS,
|
||||
name: "sys.EROFS",
|
||||
input: sys.EROFS,
|
||||
expected: ErrnoRofs,
|
||||
},
|
||||
{
|
||||
name: "syscall.Errno unexpected == ErrnoIo",
|
||||
input: syscall.Errno(0xfe),
|
||||
name: "sys.Errno unexpected == ErrnoIo",
|
||||
input: sys.Errno(0xfe),
|
||||
expected: ErrnoIo,
|
||||
},
|
||||
}
|
||||
|
||||
+24
-23
@@ -7,6 +7,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/custom"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/goos"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/util"
|
||||
@@ -174,7 +175,7 @@ func (jsfsFstat) invoke(ctx context.Context, mod api.Module, args ...interface{}
|
||||
func syscallFstat(fsc *internalsys.FSContext, fd int32) (*jsSt, error) {
|
||||
f, ok := fsc.LookupFile(fd)
|
||||
if !ok {
|
||||
return nil, syscall.EBADF
|
||||
return nil, experimentalsys.EBADF
|
||||
}
|
||||
|
||||
if st, errno := f.File.Stat(); errno != 0 {
|
||||
@@ -239,11 +240,11 @@ func (jsfsRead) invoke(ctx context.Context, mod api.Module, args ...interface{})
|
||||
}
|
||||
|
||||
// syscallRead is like syscall.Read
|
||||
func syscallRead(mod api.Module, fd int32, offset interface{}, buf []byte) (n int, errno syscall.Errno) {
|
||||
func syscallRead(mod api.Module, fd int32, offset interface{}, buf []byte) (n int, errno experimentalsys.Errno) {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return 0, syscall.EBADF
|
||||
return 0, experimentalsys.EBADF
|
||||
} else if offset != nil {
|
||||
return f.File.Pread(buf, toInt64(offset))
|
||||
} else {
|
||||
@@ -282,17 +283,17 @@ func (jsfsWrite) invoke(ctx context.Context, mod api.Module, args ...interface{}
|
||||
}
|
||||
|
||||
// syscallWrite is like syscall.Write
|
||||
func syscallWrite(mod api.Module, fd int32, offset interface{}, buf []byte) (n int, errno syscall.Errno) {
|
||||
func syscallWrite(mod api.Module, fd int32, offset interface{}, buf []byte) (n int, errno experimentalsys.Errno) {
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
errno = syscall.EBADF
|
||||
errno = experimentalsys.EBADF
|
||||
} else if offset != nil {
|
||||
n, errno = f.File.Pwrite(buf, toInt64(offset))
|
||||
} else {
|
||||
n, errno = f.File.Write(buf)
|
||||
}
|
||||
if errno == syscall.ENOSYS {
|
||||
errno = syscall.EBADF // e.g. unimplemented for write
|
||||
if errno == experimentalsys.ENOSYS {
|
||||
errno = experimentalsys.EBADF // e.g. unimplemented for write
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -350,7 +351,7 @@ func (m *jsfsMkdir) invoke(ctx context.Context, mod api.Module, args ...interfac
|
||||
root := fsc.RootFS()
|
||||
|
||||
var fd int32
|
||||
var errno syscall.Errno
|
||||
var errno experimentalsys.Errno
|
||||
// We need at least read access to open the file descriptor
|
||||
if perm == 0 {
|
||||
perm = 0o0500
|
||||
@@ -467,11 +468,11 @@ func (jsfsFchmod) invoke(ctx context.Context, mod api.Module, args ...interface{
|
||||
|
||||
// Check to see if the file descriptor is available
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
var errno syscall.Errno
|
||||
var errno experimentalsys.Errno
|
||||
if _, ok := fsc.LookupFile(fd); !ok {
|
||||
errno = syscall.EBADF
|
||||
errno = experimentalsys.EBADF
|
||||
} else {
|
||||
errno = syscall.ENOSYS // We only support functions used in wasip1
|
||||
errno = experimentalsys.ENOSYS // We only support functions used in wasip1
|
||||
}
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
@@ -490,7 +491,7 @@ func (c *jsfsChown) invoke(ctx context.Context, mod api.Module, args ...interfac
|
||||
_ = args[2] // gid
|
||||
callback := args[3].(funcWrapper)
|
||||
|
||||
errno := syscall.ENOSYS // We only support functions used in wasip1
|
||||
errno := experimentalsys.ENOSYS // We only support functions used in wasip1
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
}
|
||||
@@ -508,11 +509,11 @@ func (jsfsFchown) invoke(ctx context.Context, mod api.Module, args ...interface{
|
||||
|
||||
// Check to see if the file descriptor is available
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
var errno syscall.Errno
|
||||
var errno experimentalsys.Errno
|
||||
if _, ok := fsc.LookupFile(fd); !ok {
|
||||
errno = syscall.EBADF
|
||||
errno = experimentalsys.EBADF
|
||||
} else {
|
||||
errno = syscall.ENOSYS // We only support functions used in wasip1
|
||||
errno = experimentalsys.ENOSYS // We only support functions used in wasip1
|
||||
}
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
@@ -531,7 +532,7 @@ func (l *jsfsLchown) invoke(ctx context.Context, mod api.Module, args ...interfa
|
||||
_ = args[2] // gid
|
||||
callback := args[3].(funcWrapper)
|
||||
|
||||
errno := syscall.ENOSYS // We only support functions used in wasip1
|
||||
errno := experimentalsys.ENOSYS // We only support functions used in wasip1
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
}
|
||||
@@ -548,7 +549,7 @@ func (t *jsfsTruncate) invoke(ctx context.Context, mod api.Module, args ...inter
|
||||
_ = args[1] // length
|
||||
callback := args[2].(funcWrapper)
|
||||
|
||||
errno := syscall.ENOSYS // We only support functions used in wasip1
|
||||
errno := experimentalsys.ENOSYS // We only support functions used in wasip1
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
}
|
||||
@@ -565,9 +566,9 @@ func (jsfsFtruncate) invoke(ctx context.Context, mod api.Module, args ...interfa
|
||||
|
||||
// Check to see if the file descriptor is available
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
var errno syscall.Errno
|
||||
var errno experimentalsys.Errno
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
errno = syscall.EBADF
|
||||
errno = experimentalsys.EBADF
|
||||
} else {
|
||||
errno = f.File.Truncate(length)
|
||||
}
|
||||
@@ -640,9 +641,9 @@ func (jsfsFsync) invoke(ctx context.Context, mod api.Module, args ...interface{}
|
||||
|
||||
// Check to see if the file descriptor is available
|
||||
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||
var errno syscall.Errno
|
||||
var errno experimentalsys.Errno
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
errno = syscall.EBADF
|
||||
errno = experimentalsys.EBADF
|
||||
} else {
|
||||
errno = f.File.Sync()
|
||||
}
|
||||
@@ -714,11 +715,11 @@ func (s *jsSt) call(_ context.Context, _ api.Module, _ goos.Ref, method string,
|
||||
panic(fmt.Sprintf("TODO: stat.%s", method))
|
||||
}
|
||||
|
||||
func jsfsInvoke(ctx context.Context, mod api.Module, callback funcWrapper, err syscall.Errno) (interface{}, error) {
|
||||
func jsfsInvoke(ctx context.Context, mod api.Module, callback funcWrapper, err experimentalsys.Errno) (interface{}, error) {
|
||||
return callback.invoke(ctx, mod, goos.RefJsfs, maybeError(err), err == 0) // note: error first
|
||||
}
|
||||
|
||||
func maybeError(errno syscall.Errno) error {
|
||||
func maybeError(errno experimentalsys.Errno) error {
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ package gojs
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/custom"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/goos"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/util"
|
||||
@@ -65,7 +65,7 @@ func (p *processChdir) invoke(_ context.Context, mod api.Module, args ...interfa
|
||||
if s, err := syscallStat(mod, newWd); err != nil {
|
||||
return nil, err
|
||||
} else if !s.isDir {
|
||||
return nil, syscall.ENOTDIR
|
||||
return nil, sys.ENOTDIR
|
||||
} else {
|
||||
p.proc.cwd = newWd
|
||||
return nil, nil
|
||||
|
||||
@@ -3,10 +3,10 @@ package gojs
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/custom"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/goarch"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
@@ -47,9 +47,9 @@ func wasmWrite(_ context.Context, mod api.Module, stack goarch.Stack) {
|
||||
switch errno {
|
||||
case 0:
|
||||
return // success
|
||||
case syscall.ENOSYS:
|
||||
case sys.ENOSYS:
|
||||
return // e.g. unimplemented for write
|
||||
case syscall.EBADF:
|
||||
case sys.EBADF:
|
||||
return // e.g. not opened for write
|
||||
default:
|
||||
panic(fmt.Errorf("error writing p: %w", errno))
|
||||
|
||||
+2
-2
@@ -3,10 +3,10 @@
|
||||
package writefs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
// statFields isn't used outside JS, it is only for compilation
|
||||
func statFields(string) (atimeNsec, mtimeNsec int64, dev, inode uint64) {
|
||||
panic(syscall.ENOSYS)
|
||||
panic(sys.ENOSYS)
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
//go:build !windows
|
||||
|
||||
package platform
|
||||
|
||||
import "syscall"
|
||||
|
||||
func adjustErrno(err syscall.Errno) syscall.Errno {
|
||||
return err
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package platform
|
||||
|
||||
import "syscall"
|
||||
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
|
||||
const (
|
||||
// ERROR_ACCESS_DENIED is a Windows error returned by syscall.Unlink
|
||||
// instead of syscall.EACCES
|
||||
ERROR_ACCESS_DENIED = syscall.Errno(5)
|
||||
|
||||
// ERROR_INVALID_HANDLE is a Windows error returned by syscall.Write
|
||||
// instead of syscall.EBADF
|
||||
ERROR_INVALID_HANDLE = syscall.Errno(6)
|
||||
|
||||
// ERROR_FILE_EXISTS is a Windows error returned by os.OpenFile
|
||||
// instead of syscall.EEXIST
|
||||
ERROR_FILE_EXISTS = syscall.Errno(0x50)
|
||||
|
||||
// ERROR_INVALID_NAME is a Windows error returned by open when a file
|
||||
// path has a trailing slash
|
||||
ERROR_INVALID_NAME = syscall.Errno(0x7B)
|
||||
|
||||
// ERROR_NEGATIVE_SEEK is a Windows error returned by os.Truncate
|
||||
// instead of syscall.EINVAL
|
||||
ERROR_NEGATIVE_SEEK = syscall.Errno(0x83)
|
||||
|
||||
// ERROR_DIR_NOT_EMPTY is a Windows error returned by syscall.Rmdir
|
||||
// instead of syscall.ENOTEMPTY
|
||||
ERROR_DIR_NOT_EMPTY = syscall.Errno(0x91)
|
||||
|
||||
// ERROR_ALREADY_EXISTS is a Windows error returned by os.Mkdir
|
||||
// instead of syscall.EEXIST
|
||||
ERROR_ALREADY_EXISTS = syscall.Errno(0xB7)
|
||||
|
||||
// ERROR_DIRECTORY is a Windows error returned by syscall.Rmdir
|
||||
// instead of syscall.ENOTDIR
|
||||
ERROR_DIRECTORY = syscall.Errno(0x10B)
|
||||
)
|
||||
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--1300-1699-
|
||||
const (
|
||||
// ERROR_PRIVILEGE_NOT_HELD is a Windows error returned by os.Symlink
|
||||
// instead of syscall.EPERM.
|
||||
//
|
||||
// Note: This can happen when trying to create symlinks w/o admin perms.
|
||||
ERROR_PRIVILEGE_NOT_HELD = syscall.Errno(0x522)
|
||||
)
|
||||
|
||||
func adjustErrno(err syscall.Errno) syscall.Errno {
|
||||
// Note: In windows, ERROR_PATH_NOT_FOUND(0x3) maps to syscall.ENOTDIR
|
||||
switch err {
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
return syscall.EEXIST
|
||||
case ERROR_DIRECTORY:
|
||||
return syscall.ENOTDIR
|
||||
case ERROR_DIR_NOT_EMPTY:
|
||||
return syscall.ENOTEMPTY
|
||||
case ERROR_FILE_EXISTS:
|
||||
return syscall.EEXIST
|
||||
case ERROR_INVALID_HANDLE:
|
||||
return syscall.EBADF
|
||||
case ERROR_ACCESS_DENIED:
|
||||
// POSIX read and write functions expect EBADF, not EACCES when not
|
||||
// open for reading or writing.
|
||||
return syscall.EBADF
|
||||
case ERROR_PRIVILEGE_NOT_HELD:
|
||||
return syscall.EPERM
|
||||
case ERROR_NEGATIVE_SEEK, ERROR_INVALID_NAME:
|
||||
return syscall.EINVAL
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -3,8 +3,8 @@ package sock
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
)
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
type TCPSock interface {
|
||||
fsapi.File
|
||||
|
||||
Accept() (TCPConn, syscall.Errno)
|
||||
Accept() (TCPConn, sys.Errno)
|
||||
}
|
||||
|
||||
// TCPConn is a pseudo-file representing a TCP connection.
|
||||
@@ -20,9 +20,11 @@ type TCPConn interface {
|
||||
fsapi.File
|
||||
|
||||
// Recvfrom only supports the flag sysfs.MSG_PEEK
|
||||
Recvfrom(p []byte, flags int) (n int, errno syscall.Errno)
|
||||
// TODO: document this like fsapi.File with known sys.Errno
|
||||
Recvfrom(p []byte, flags int) (n int, errno sys.Errno)
|
||||
|
||||
Shutdown(how int) syscall.Errno
|
||||
// TODO: document this like fsapi.File with known sys.Errno
|
||||
Shutdown(how int) sys.Errno
|
||||
}
|
||||
|
||||
// ConfigKey is a context.Context Value key. Its associated value should be a Config.
|
||||
|
||||
+26
-26
@@ -4,8 +4,8 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/descriptor"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
socketapi "github.com/tetratelabs/wazero/internal/sock"
|
||||
@@ -61,15 +61,15 @@ type FileEntry struct {
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EBADF: the dir was closed or not readable.
|
||||
// - syscall.ENOTDIR: the file was not a directory.
|
||||
// A zero sys.Errno is success. The below are expected otherwise:
|
||||
// - sys.ENOSYS: the implementation does not support this function.
|
||||
// - sys.EBADF: the dir was closed or not readable.
|
||||
// - sys.ENOTDIR: the file was not a directory.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - See /RATIONALE.md for design notes.
|
||||
func (f *FileEntry) DirentCache() (*DirentCache, syscall.Errno) {
|
||||
func (f *FileEntry) DirentCache() (*DirentCache, sys.Errno) {
|
||||
if dir := f.direntCache; dir != nil {
|
||||
return dir, 0
|
||||
}
|
||||
@@ -78,7 +78,7 @@ func (f *FileEntry) DirentCache() (*DirentCache, syscall.Errno) {
|
||||
if isDir, errno := f.File.IsDir(); errno != 0 {
|
||||
return nil, errno
|
||||
} else if !isDir {
|
||||
return nil, syscall.ENOTDIR
|
||||
return nil, sys.ENOTDIR
|
||||
}
|
||||
|
||||
// Generate the dotEntries only once.
|
||||
@@ -132,7 +132,7 @@ type DirentCache struct {
|
||||
}
|
||||
|
||||
// synthesizeDotEntries generates a slice of the two elements "." and "..".
|
||||
func synthesizeDotEntries(f *FileEntry) ([]fsapi.Dirent, syscall.Errno) {
|
||||
func synthesizeDotEntries(f *FileEntry) ([]fsapi.Dirent, sys.Errno) {
|
||||
dotIno, errno := f.File.Ino()
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
@@ -158,16 +158,16 @@ var exhaustedDirents = [0]fsapi.Dirent{}
|
||||
//
|
||||
// When non-zero, `pos` is the zero based index of all dirents returned since
|
||||
// last rewind. Only entries beginning at `pos` are cached for subsequent
|
||||
// calls. A non-zero `pos` before the cache returns syscall.ENOENT for reasons
|
||||
// calls. A non-zero `pos` before the cache returns sys.ENOENT for reasons
|
||||
// described on DirentCache documentation.
|
||||
//
|
||||
// Up to `n` entries are cached and returned. When `n` exceeds the cache, the
|
||||
// difference are read from the underlying fsapi.File via `Readdir`. EOF is
|
||||
// when `len(dirents)` returned are less than `n`.
|
||||
func (d *DirentCache) Read(pos uint64, n uint32) (dirents []fsapi.Dirent, errno syscall.Errno) {
|
||||
func (d *DirentCache) Read(pos uint64, n uint32) (dirents []fsapi.Dirent, errno sys.Errno) {
|
||||
switch {
|
||||
case pos > d.countRead: // farther than read or negative coerced to uint64.
|
||||
return nil, syscall.ENOENT
|
||||
return nil, sys.ENOENT
|
||||
case pos == 0 && d.dirents != nil:
|
||||
// Rewind if we have already read entries. This allows us to see new
|
||||
// entries added after the directory was opened.
|
||||
@@ -209,7 +209,7 @@ func (d *DirentCache) Read(pos uint64, n uint32) (dirents []fsapi.Dirent, errno
|
||||
// won't do unless wasi-testsuite starts requiring it. Implementing
|
||||
// this would allow re-reading a large directory, so care would be
|
||||
// needed to not buffer the entire directory in memory while skipping.
|
||||
errno = syscall.ENOENT
|
||||
errno = sys.ENOENT
|
||||
return
|
||||
} else if posInCache := pos - cacheStart; posInCache != 0 {
|
||||
if uint64(len(d.dirents)) == posInCache {
|
||||
@@ -284,7 +284,7 @@ func (c *FSContext) LookupFile(fd int32) (*FileEntry, bool) {
|
||||
|
||||
// OpenFile opens the file into the table and returns its file descriptor.
|
||||
// The result must be closed by CloseFile or Close.
|
||||
func (c *FSContext) OpenFile(fs fsapi.FS, path string, flag int, perm fs.FileMode) (int32, syscall.Errno) {
|
||||
func (c *FSContext) OpenFile(fs fsapi.FS, path string, flag int, perm fs.FileMode) (int32, sys.Errno) {
|
||||
if f, errno := fs.OpenFile(path, flag, perm); errno != 0 {
|
||||
return 0, errno
|
||||
} else {
|
||||
@@ -295,7 +295,7 @@ func (c *FSContext) OpenFile(fs fsapi.FS, path string, flag int, perm fs.FileMod
|
||||
fe.Name = path
|
||||
}
|
||||
if newFD, ok := c.openedFiles.Insert(fe); !ok {
|
||||
return 0, syscall.EBADF
|
||||
return 0, sys.EBADF
|
||||
} else {
|
||||
return newFD, 0
|
||||
}
|
||||
@@ -303,12 +303,12 @@ func (c *FSContext) OpenFile(fs fsapi.FS, path string, flag int, perm fs.FileMod
|
||||
}
|
||||
|
||||
// Renumber assigns the file pointed by the descriptor `from` to `to`.
|
||||
func (c *FSContext) Renumber(from, to int32) syscall.Errno {
|
||||
func (c *FSContext) Renumber(from, to int32) sys.Errno {
|
||||
fromFile, ok := c.openedFiles.Lookup(from)
|
||||
if !ok || to < 0 {
|
||||
return syscall.EBADF
|
||||
return sys.EBADF
|
||||
} else if fromFile.IsPreopen {
|
||||
return syscall.ENOTSUP
|
||||
return sys.ENOTSUP
|
||||
}
|
||||
|
||||
// If toFile is already open, we close it to prevent windows lock issues.
|
||||
@@ -318,30 +318,30 @@ func (c *FSContext) Renumber(from, to int32) syscall.Errno {
|
||||
// https://github.com/bytecodealliance/wasmtime/blob/main/crates/wasi-common/src/snapshots/preview_1.rs#L531-L546
|
||||
if toFile, ok := c.openedFiles.Lookup(to); ok {
|
||||
if toFile.IsPreopen {
|
||||
return syscall.ENOTSUP
|
||||
return sys.ENOTSUP
|
||||
}
|
||||
_ = toFile.File.Close()
|
||||
}
|
||||
|
||||
c.openedFiles.Delete(from)
|
||||
if !c.openedFiles.InsertAt(fromFile, to) {
|
||||
return syscall.EBADF
|
||||
return sys.EBADF
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// SockAccept accepts a socketapi.TCPConn into the file table and returns
|
||||
// its file descriptor.
|
||||
func (c *FSContext) SockAccept(sockFD int32, nonblock bool) (int32, syscall.Errno) {
|
||||
func (c *FSContext) SockAccept(sockFD int32, nonblock bool) (int32, sys.Errno) {
|
||||
var sock socketapi.TCPSock
|
||||
if e, ok := c.LookupFile(sockFD); !ok || !e.IsPreopen {
|
||||
return 0, syscall.EBADF // Not a preopen
|
||||
return 0, sys.EBADF // Not a preopen
|
||||
} else if sock, ok = e.File.(socketapi.TCPSock); !ok {
|
||||
return 0, syscall.EBADF // Not a sock
|
||||
return 0, sys.EBADF // Not a sock
|
||||
}
|
||||
|
||||
var conn socketapi.TCPConn
|
||||
var errno syscall.Errno
|
||||
var errno sys.Errno
|
||||
if conn, errno = sock.Accept(); errno != 0 {
|
||||
return 0, errno
|
||||
} else if nonblock {
|
||||
@@ -353,17 +353,17 @@ func (c *FSContext) SockAccept(sockFD int32, nonblock bool) (int32, syscall.Errn
|
||||
|
||||
fe := &FileEntry{File: conn}
|
||||
if newFD, ok := c.openedFiles.Insert(fe); !ok {
|
||||
return 0, syscall.EBADF
|
||||
return 0, sys.EBADF
|
||||
} else {
|
||||
return newFD, 0
|
||||
}
|
||||
}
|
||||
|
||||
// CloseFile returns any error closing the existing file.
|
||||
func (c *FSContext) CloseFile(fd int32) (errno syscall.Errno) {
|
||||
func (c *FSContext) CloseFile(fd int32) (errno sys.Errno) {
|
||||
f, ok := c.openedFiles.Lookup(fd)
|
||||
if !ok {
|
||||
return syscall.EBADF
|
||||
return sys.EBADF
|
||||
}
|
||||
if errno = f.File.Close(); errno != 0 {
|
||||
return errno
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"syscall"
|
||||
"testing"
|
||||
gofstest "testing/fstest"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/fstest"
|
||||
"github.com/tetratelabs/wazero/internal/sysfs"
|
||||
@@ -123,7 +123,7 @@ func TestFSContext_CloseFile(t *testing.T) {
|
||||
require.True(t, ok)
|
||||
|
||||
t.Run("EBADF for an invalid FD", func(t *testing.T) {
|
||||
require.EqualErrno(t, syscall.EBADF, fsc.CloseFile(42)) // 42 is an arbitrary invalid FD
|
||||
require.EqualErrno(t, sys.EBADF, fsc.CloseFile(42)) // 42 is an arbitrary invalid FD
|
||||
})
|
||||
t.Run("Can close a pre-open", func(t *testing.T) {
|
||||
require.EqualErrno(t, 0, fsc.CloseFile(FdPreopen))
|
||||
@@ -194,7 +194,7 @@ func TestContext_Close_Error(t *testing.T) {
|
||||
require.EqualErrno(t, 0, errno)
|
||||
|
||||
// arbitrary errors coerce to EIO
|
||||
require.EqualErrno(t, syscall.EIO, fsc.Close())
|
||||
require.EqualErrno(t, sys.EIO, fsc.Close())
|
||||
|
||||
// Paths should clear even under error
|
||||
require.Zero(t, fsc.openedFiles.Len(), "expected no opened files")
|
||||
@@ -241,13 +241,13 @@ func TestFSContext_Renumber(t *testing.T) {
|
||||
require.True(t, preopen.IsPreopen)
|
||||
|
||||
// From is preopen.
|
||||
require.Equal(t, syscall.ENOTSUP, fsc.Renumber(3, 100))
|
||||
require.Equal(t, sys.ENOTSUP, fsc.Renumber(3, 100))
|
||||
|
||||
// From does not exist.
|
||||
require.Equal(t, syscall.EBADF, fsc.Renumber(12345, 3))
|
||||
require.Equal(t, sys.EBADF, fsc.Renumber(12345, 3))
|
||||
|
||||
// Both are preopen.
|
||||
require.Equal(t, syscall.ENOTSUP, fsc.Renumber(3, 3))
|
||||
require.Equal(t, sys.ENOTSUP, fsc.Renumber(3, 3))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ func TestDirentCache_Read(t *testing.T) {
|
||||
pos uint64
|
||||
n uint32
|
||||
expectedDirents []fsapi.Dirent
|
||||
expectedErrno syscall.Errno
|
||||
expectedErrno sys.Errno
|
||||
}{
|
||||
{
|
||||
name: "empty dir has dot entries",
|
||||
@@ -391,14 +391,14 @@ func TestDirentCache_Read(t *testing.T) {
|
||||
initialDir: "dir/-",
|
||||
pos: 0,
|
||||
n: 1,
|
||||
expectedErrno: syscall.ENOTDIR,
|
||||
expectedErrno: sys.ENOTDIR,
|
||||
},
|
||||
{
|
||||
name: "pos invalid when no prior state",
|
||||
initialDir: "dir",
|
||||
pos: 1,
|
||||
n: 1,
|
||||
expectedErrno: syscall.ENOENT,
|
||||
expectedErrno: sys.ENOENT,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+24
-23
@@ -4,6 +4,7 @@ import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
@@ -19,29 +20,29 @@ type lazyDir struct {
|
||||
}
|
||||
|
||||
// Dev implements the same method as documented on fsapi.File
|
||||
func (r *lazyDir) Dev() (uint64, syscall.Errno) {
|
||||
func (r *lazyDir) Dev() (uint64, experimentalsys.Errno) {
|
||||
if f, ok := r.file(); !ok {
|
||||
return 0, syscall.EBADF
|
||||
return 0, experimentalsys.EBADF
|
||||
} else {
|
||||
return f.Dev()
|
||||
}
|
||||
}
|
||||
|
||||
// Ino implements the same method as documented on fsapi.File
|
||||
func (r *lazyDir) Ino() (sys.Inode, syscall.Errno) {
|
||||
func (r *lazyDir) Ino() (sys.Inode, experimentalsys.Errno) {
|
||||
if f, ok := r.file(); !ok {
|
||||
return 0, syscall.EBADF
|
||||
return 0, experimentalsys.EBADF
|
||||
} else {
|
||||
return f.Ino()
|
||||
}
|
||||
}
|
||||
|
||||
// IsDir implements the same method as documented on fsapi.File
|
||||
func (r *lazyDir) IsDir() (bool, syscall.Errno) {
|
||||
func (r *lazyDir) IsDir() (bool, experimentalsys.Errno) {
|
||||
// Note: we don't return a constant because we don't know if this is really
|
||||
// backed by a dir, until the first call.
|
||||
if f, ok := r.file(); !ok {
|
||||
return false, syscall.EBADF
|
||||
return false, experimentalsys.EBADF
|
||||
} else {
|
||||
return f.IsDir()
|
||||
}
|
||||
@@ -53,59 +54,59 @@ func (r *lazyDir) IsAppend() bool {
|
||||
}
|
||||
|
||||
// SetAppend implements the same method as documented on fsapi.File
|
||||
func (r *lazyDir) SetAppend(bool) syscall.Errno {
|
||||
return syscall.EISDIR
|
||||
func (r *lazyDir) SetAppend(bool) experimentalsys.Errno {
|
||||
return experimentalsys.EISDIR
|
||||
}
|
||||
|
||||
// Seek implements the same method as documented on fsapi.File
|
||||
func (r *lazyDir) Seek(offset int64, whence int) (newOffset int64, errno syscall.Errno) {
|
||||
func (r *lazyDir) Seek(offset int64, whence int) (newOffset int64, errno experimentalsys.Errno) {
|
||||
if f, ok := r.file(); !ok {
|
||||
return 0, syscall.EBADF
|
||||
return 0, experimentalsys.EBADF
|
||||
} else {
|
||||
return f.Seek(offset, whence)
|
||||
}
|
||||
}
|
||||
|
||||
// Stat implements the same method as documented on fsapi.File
|
||||
func (r *lazyDir) Stat() (sys.Stat_t, syscall.Errno) {
|
||||
func (r *lazyDir) Stat() (sys.Stat_t, experimentalsys.Errno) {
|
||||
if f, ok := r.file(); !ok {
|
||||
return sys.Stat_t{}, syscall.EBADF
|
||||
return sys.Stat_t{}, experimentalsys.EBADF
|
||||
} else {
|
||||
return f.Stat()
|
||||
}
|
||||
}
|
||||
|
||||
// Readdir implements the same method as documented on fsapi.File
|
||||
func (r *lazyDir) Readdir(n int) (dirents []fsapi.Dirent, errno syscall.Errno) {
|
||||
func (r *lazyDir) Readdir(n int) (dirents []fsapi.Dirent, errno experimentalsys.Errno) {
|
||||
if f, ok := r.file(); !ok {
|
||||
return nil, syscall.EBADF
|
||||
return nil, experimentalsys.EBADF
|
||||
} else {
|
||||
return f.Readdir(n)
|
||||
}
|
||||
}
|
||||
|
||||
// Sync implements the same method as documented on fsapi.File
|
||||
func (r *lazyDir) Sync() syscall.Errno {
|
||||
func (r *lazyDir) Sync() experimentalsys.Errno {
|
||||
if f, ok := r.file(); !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
} else {
|
||||
return f.Sync()
|
||||
}
|
||||
}
|
||||
|
||||
// Datasync implements the same method as documented on fsapi.File
|
||||
func (r *lazyDir) Datasync() syscall.Errno {
|
||||
func (r *lazyDir) Datasync() experimentalsys.Errno {
|
||||
if f, ok := r.file(); !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
} else {
|
||||
return f.Datasync()
|
||||
}
|
||||
}
|
||||
|
||||
// Utimens implements the same method as documented on fsapi.File
|
||||
func (r *lazyDir) Utimens(times *[2]syscall.Timespec) syscall.Errno {
|
||||
func (r *lazyDir) Utimens(times *[2]syscall.Timespec) experimentalsys.Errno {
|
||||
if f, ok := r.file(); !ok {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
} else {
|
||||
return f.Utimens(times)
|
||||
}
|
||||
@@ -116,12 +117,12 @@ func (r *lazyDir) file() (fsapi.File, bool) {
|
||||
if f := r.f; r.f != nil {
|
||||
return f, true
|
||||
}
|
||||
var errno syscall.Errno
|
||||
var errno experimentalsys.Errno
|
||||
r.f, errno = r.fs.OpenFile(".", os.O_RDONLY, 0)
|
||||
switch errno {
|
||||
case 0:
|
||||
return r.f, true
|
||||
case syscall.ENOENT:
|
||||
case experimentalsys.ENOENT:
|
||||
return nil, false
|
||||
default:
|
||||
panic(errno) // unexpected
|
||||
@@ -129,7 +130,7 @@ func (r *lazyDir) file() (fsapi.File, bool) {
|
||||
}
|
||||
|
||||
// Close implements fs.File
|
||||
func (r *lazyDir) Close() syscall.Errno {
|
||||
func (r *lazyDir) Close() experimentalsys.Errno {
|
||||
f := r.f
|
||||
if f == nil {
|
||||
return 0 // never opened
|
||||
|
||||
+11
-11
@@ -6,8 +6,8 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/internal/sysfs"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
@@ -21,9 +21,9 @@ type StdinFile struct {
|
||||
}
|
||||
|
||||
// Read implements the same method as documented on fsapi.File
|
||||
func (f *StdinFile) Read(buf []byte) (int, syscall.Errno) {
|
||||
func (f *StdinFile) Read(buf []byte) (int, experimentalsys.Errno) {
|
||||
n, err := f.Reader.Read(buf)
|
||||
return n, platform.UnwrapOSError(err)
|
||||
return n, experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
type writerFile struct {
|
||||
@@ -33,9 +33,9 @@ type writerFile struct {
|
||||
}
|
||||
|
||||
// Write implements the same method as documented on fsapi.File
|
||||
func (f *writerFile) Write(buf []byte) (int, syscall.Errno) {
|
||||
func (f *writerFile) Write(buf []byte) (int, experimentalsys.Errno) {
|
||||
n, err := f.w.Write(buf)
|
||||
return n, platform.UnwrapOSError(err)
|
||||
return n, experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// noopStdinFile is a fs.ModeDevice file for use implementing FdStdin. This is
|
||||
@@ -51,12 +51,12 @@ func (noopStdinFile) AccessMode() int {
|
||||
}
|
||||
|
||||
// Read implements the same method as documented on fsapi.File
|
||||
func (noopStdinFile) Read([]byte) (int, syscall.Errno) {
|
||||
func (noopStdinFile) Read([]byte) (int, experimentalsys.Errno) {
|
||||
return 0, 0 // Always EOF
|
||||
}
|
||||
|
||||
// PollRead implements the same method as documented on fsapi.File
|
||||
func (noopStdinFile) PollRead(*time.Duration) (ready bool, errno syscall.Errno) {
|
||||
func (noopStdinFile) PollRead(*time.Duration) (ready bool, errno experimentalsys.Errno) {
|
||||
return true, 0 // always ready to read nothing
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func (noopStdoutFile) AccessMode() int {
|
||||
}
|
||||
|
||||
// Write implements the same method as documented on fsapi.File
|
||||
func (noopStdoutFile) Write(buf []byte) (int, syscall.Errno) {
|
||||
func (noopStdoutFile) Write(buf []byte) (int, experimentalsys.Errno) {
|
||||
return len(buf), 0 // same as io.Discard
|
||||
}
|
||||
|
||||
@@ -81,17 +81,17 @@ type noopStdioFile struct {
|
||||
}
|
||||
|
||||
// Stat implements the same method as documented on fsapi.File
|
||||
func (noopStdioFile) Stat() (sys.Stat_t, syscall.Errno) {
|
||||
func (noopStdioFile) Stat() (sys.Stat_t, experimentalsys.Errno) {
|
||||
return sys.Stat_t{Mode: modeDevice, Nlink: 1}, 0
|
||||
}
|
||||
|
||||
// IsDir implements the same method as documented on fsapi.File
|
||||
func (noopStdioFile) IsDir() (bool, syscall.Errno) {
|
||||
func (noopStdioFile) IsDir() (bool, experimentalsys.Errno) {
|
||||
return false, 0
|
||||
}
|
||||
|
||||
// Close implements the same method as documented on fsapi.File
|
||||
func (noopStdioFile) Close() (errno syscall.Errno) { return }
|
||||
func (noopStdioFile) Close() (errno experimentalsys.Errno) { return }
|
||||
|
||||
func stdinFileEntry(r io.Reader) (*FileEntry, error) {
|
||||
if r == nil {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"path"
|
||||
"syscall"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
@@ -38,12 +39,12 @@ func (a *adapter) String() string {
|
||||
}
|
||||
|
||||
// OpenFile implements the same method as documented on fsapi.FS
|
||||
func (a *adapter) OpenFile(path string, flag int, perm fs.FileMode) (fsapi.File, syscall.Errno) {
|
||||
func (a *adapter) OpenFile(path string, flag int, perm fs.FileMode) (fsapi.File, experimentalsys.Errno) {
|
||||
return OpenFSFile(a.fs, cleanPath(path), flag, perm)
|
||||
}
|
||||
|
||||
// Stat implements the same method as documented on fsapi.FS
|
||||
func (a *adapter) Stat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func (a *adapter) Stat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
f, errno := a.OpenFile(path, syscall.O_RDONLY, 0)
|
||||
if errno != 0 {
|
||||
return sys.Stat_t{}, errno
|
||||
@@ -53,7 +54,7 @@ func (a *adapter) Stat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
}
|
||||
|
||||
// Lstat implements the same method as documented on fsapi.FS
|
||||
func (a *adapter) Lstat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func (a *adapter) Lstat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
// At this time, we make the assumption that fsapi.FS instances do not support
|
||||
// symbolic links, therefore Lstat is the same as Stat. This is obviously
|
||||
// not true but until fsapi.FS has a solid story for how to handle symlinks we
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/fstest"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
@@ -27,14 +28,14 @@ func TestAdapt_MkDir(t *testing.T) {
|
||||
testFS := Adapt(os.DirFS(t.TempDir()))
|
||||
|
||||
err := testFS.Mkdir("mkdir", fs.ModeDir)
|
||||
require.EqualErrno(t, syscall.ENOSYS, err)
|
||||
require.EqualErrno(t, experimentalsys.ENOSYS, err)
|
||||
}
|
||||
|
||||
func TestAdapt_Chmod(t *testing.T) {
|
||||
testFS := Adapt(os.DirFS(t.TempDir()))
|
||||
|
||||
err := testFS.Chmod("chmod", fs.ModeDir)
|
||||
require.EqualErrno(t, syscall.ENOSYS, err)
|
||||
require.EqualErrno(t, experimentalsys.ENOSYS, err)
|
||||
}
|
||||
|
||||
func TestAdapt_Rename(t *testing.T) {
|
||||
@@ -54,7 +55,7 @@ func TestAdapt_Rename(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testFS.Rename(file1, file2)
|
||||
require.EqualErrno(t, syscall.ENOSYS, err)
|
||||
require.EqualErrno(t, experimentalsys.ENOSYS, err)
|
||||
}
|
||||
|
||||
func TestAdapt_Rmdir(t *testing.T) {
|
||||
@@ -66,7 +67,7 @@ func TestAdapt_Rmdir(t *testing.T) {
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
|
||||
err := testFS.Rmdir(path)
|
||||
require.EqualErrno(t, syscall.ENOSYS, err)
|
||||
require.EqualErrno(t, experimentalsys.ENOSYS, err)
|
||||
}
|
||||
|
||||
func TestAdapt_Unlink(t *testing.T) {
|
||||
@@ -78,7 +79,7 @@ func TestAdapt_Unlink(t *testing.T) {
|
||||
require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600))
|
||||
|
||||
err := testFS.Unlink(path)
|
||||
require.EqualErrno(t, syscall.ENOSYS, err)
|
||||
require.EqualErrno(t, experimentalsys.ENOSYS, err)
|
||||
}
|
||||
|
||||
func TestAdapt_UtimesNano(t *testing.T) {
|
||||
@@ -90,7 +91,7 @@ func TestAdapt_UtimesNano(t *testing.T) {
|
||||
require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600))
|
||||
|
||||
err := testFS.Utimens(path, nil, true)
|
||||
require.EqualErrno(t, syscall.ENOSYS, err)
|
||||
require.EqualErrno(t, experimentalsys.ENOSYS, err)
|
||||
}
|
||||
|
||||
func TestAdapt_Open_Read(t *testing.T) {
|
||||
@@ -109,7 +110,7 @@ func TestAdapt_Open_Read(t *testing.T) {
|
||||
_, err := testFS.OpenFile("../foo", os.O_RDONLY, 0)
|
||||
|
||||
// fsapi.FS doesn't allow relative path lookups
|
||||
require.EqualErrno(t, syscall.EINVAL, err)
|
||||
require.EqualErrno(t, experimentalsys.EINVAL, err)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"path"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func BenchmarkFsFileUtimesNs(b *testing.B) {
|
||||
@@ -65,7 +67,7 @@ func BenchmarkFsFileRead(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
var n int
|
||||
var errno syscall.Errno
|
||||
var errno sys.Errno
|
||||
|
||||
// Reset the read position back to the beginning of the file.
|
||||
if _, errno = f.Seek(0, io.SeekStart); errno != 0 {
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func datasync(f *os.File) syscall.Errno {
|
||||
return platform.UnwrapOSError(syscall.Fdatasync(int(f.Fd())))
|
||||
func datasync(f *os.File) sys.Errno {
|
||||
return sys.UnwrapOSError(syscall.Fdatasync(int(f.Fd())))
|
||||
}
|
||||
|
||||
@@ -4,10 +4,11 @@ package sysfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func datasync(f *os.File) syscall.Errno {
|
||||
func datasync(f *os.File) sys.Errno {
|
||||
// Attempt to sync everything, even if we only need to sync the data.
|
||||
return fsync(f)
|
||||
}
|
||||
|
||||
@@ -2,23 +2,22 @@ package sysfs
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
)
|
||||
|
||||
func adjustReaddirErr(f fsapi.File, isClosed bool, err error) syscall.Errno {
|
||||
func adjustReaddirErr(f fsapi.File, isClosed bool, err error) sys.Errno {
|
||||
if err == io.EOF {
|
||||
return 0 // e.g. Readdir on darwin returns io.EOF, but linux doesn't.
|
||||
} else if errno := platform.UnwrapOSError(err); errno != 0 {
|
||||
} else if errno := sys.UnwrapOSError(err); errno != 0 {
|
||||
errno = dirError(f, isClosed, errno)
|
||||
// Comply with errors allowed on fsapi.File Readdir
|
||||
switch errno {
|
||||
case syscall.EINVAL: // os.File Readdir can return this
|
||||
return syscall.EBADF
|
||||
case syscall.ENOTDIR: // dirError can return this
|
||||
return syscall.EBADF
|
||||
case sys.EINVAL: // os.File Readdir can return this
|
||||
return sys.EBADF
|
||||
case sys.ENOTDIR: // dirError can return this
|
||||
return sys.EBADF
|
||||
}
|
||||
return errno
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/fstest"
|
||||
"github.com/tetratelabs/wazero/internal/sysfs"
|
||||
@@ -72,7 +73,7 @@ func TestFSFileReaddir(t *testing.T) {
|
||||
t.Run("closed dir", func(t *testing.T) {
|
||||
require.EqualErrno(t, 0, dotF.Close())
|
||||
_, errno := dotF.Readdir(-1)
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
require.EqualErrno(t, sys.EBADF, errno)
|
||||
})
|
||||
|
||||
fileF, errno := sysfs.OpenFSFile(tc.fs, "empty.txt", syscall.O_RDONLY, 0)
|
||||
@@ -81,7 +82,7 @@ func TestFSFileReaddir(t *testing.T) {
|
||||
|
||||
t.Run("file", func(t *testing.T) {
|
||||
_, errno := fileF.Readdir(-1)
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
require.EqualErrno(t, sys.EBADF, errno)
|
||||
})
|
||||
|
||||
dirF, errno := sysfs.OpenFSFile(tc.fs, "dir", syscall.O_RDONLY, 0)
|
||||
|
||||
+21
-20
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
@@ -38,84 +39,84 @@ func (d *dirFS) String() string {
|
||||
}
|
||||
|
||||
// OpenFile implements the same method as documented on fsapi.FS
|
||||
func (d *dirFS) OpenFile(path string, flag int, perm fs.FileMode) (fsapi.File, syscall.Errno) {
|
||||
func (d *dirFS) OpenFile(path string, flag int, perm fs.FileMode) (fsapi.File, experimentalsys.Errno) {
|
||||
return OpenOSFile(d.join(path), flag, perm)
|
||||
}
|
||||
|
||||
// Lstat implements the same method as documented on fsapi.FS
|
||||
func (d *dirFS) Lstat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func (d *dirFS) Lstat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
return lstat(d.join(path))
|
||||
}
|
||||
|
||||
// Stat implements the same method as documented on fsapi.FS
|
||||
func (d *dirFS) Stat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func (d *dirFS) Stat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
return stat(d.join(path))
|
||||
}
|
||||
|
||||
// Mkdir implements the same method as documented on fsapi.FS
|
||||
func (d *dirFS) Mkdir(path string, perm fs.FileMode) (errno syscall.Errno) {
|
||||
func (d *dirFS) Mkdir(path string, perm fs.FileMode) (errno experimentalsys.Errno) {
|
||||
err := os.Mkdir(d.join(path), perm)
|
||||
if errno = platform.UnwrapOSError(err); errno == syscall.ENOTDIR {
|
||||
errno = syscall.ENOENT
|
||||
if errno = experimentalsys.UnwrapOSError(err); errno == experimentalsys.ENOTDIR {
|
||||
errno = experimentalsys.ENOENT
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Chmod implements the same method as documented on fsapi.FS
|
||||
func (d *dirFS) Chmod(path string, perm fs.FileMode) syscall.Errno {
|
||||
func (d *dirFS) Chmod(path string, perm fs.FileMode) experimentalsys.Errno {
|
||||
err := os.Chmod(d.join(path), perm)
|
||||
return platform.UnwrapOSError(err)
|
||||
return experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Rename implements the same method as documented on fsapi.FS
|
||||
func (d *dirFS) Rename(from, to string) syscall.Errno {
|
||||
func (d *dirFS) Rename(from, to string) experimentalsys.Errno {
|
||||
from, to = d.join(from), d.join(to)
|
||||
return rename(from, to)
|
||||
}
|
||||
|
||||
// Readlink implements the same method as documented on fsapi.FS
|
||||
func (d *dirFS) Readlink(path string) (string, syscall.Errno) {
|
||||
func (d *dirFS) Readlink(path string) (string, experimentalsys.Errno) {
|
||||
// Note: do not use syscall.Readlink as that causes race on Windows.
|
||||
// In any case, syscall.Readlink does almost the same logic as os.Readlink.
|
||||
dst, err := os.Readlink(d.join(path))
|
||||
if err != nil {
|
||||
return "", platform.UnwrapOSError(err)
|
||||
return "", experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
return platform.ToPosixPath(dst), 0
|
||||
}
|
||||
|
||||
// Link implements the same method as documented on fsapi.FS
|
||||
func (d *dirFS) Link(oldName, newName string) syscall.Errno {
|
||||
func (d *dirFS) Link(oldName, newName string) experimentalsys.Errno {
|
||||
err := os.Link(d.join(oldName), d.join(newName))
|
||||
return platform.UnwrapOSError(err)
|
||||
return experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Rmdir implements the same method as documented on fsapi.FS
|
||||
func (d *dirFS) Rmdir(path string) syscall.Errno {
|
||||
func (d *dirFS) Rmdir(path string) experimentalsys.Errno {
|
||||
return rmdir(d.join(path))
|
||||
}
|
||||
|
||||
func rmdir(path string) syscall.Errno {
|
||||
func rmdir(path string) experimentalsys.Errno {
|
||||
err := syscall.Rmdir(path)
|
||||
return platform.UnwrapOSError(err)
|
||||
return experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Unlink implements the same method as documented on fsapi.FS
|
||||
func (d *dirFS) Unlink(path string) (err syscall.Errno) {
|
||||
func (d *dirFS) Unlink(path string) (err experimentalsys.Errno) {
|
||||
return unlink(d.join(path))
|
||||
}
|
||||
|
||||
// Symlink implements the same method as documented on fsapi.FS
|
||||
func (d *dirFS) Symlink(oldName, link string) syscall.Errno {
|
||||
func (d *dirFS) Symlink(oldName, link string) experimentalsys.Errno {
|
||||
// Note: do not resolve `oldName` relative to this dirFS. The link result is always resolved
|
||||
// when dereference the `link` on its usage (e.g. readlink, read, etc).
|
||||
// https://github.com/bytecodealliance/cap-std/blob/v1.0.4/cap-std/src/fs/dir.rs#L404-L409
|
||||
err := os.Symlink(oldName, d.join(link))
|
||||
return platform.UnwrapOSError(err)
|
||||
return experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Utimens implements the same method as documented on fsapi.FS
|
||||
func (d *dirFS) Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) syscall.Errno {
|
||||
func (d *dirFS) Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) experimentalsys.Errno {
|
||||
return Utimens(d.join(path), times, symlinkFollow)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/fstest"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
@@ -28,7 +29,7 @@ func TestNewDirFS(t *testing.T) {
|
||||
t.Run("host path not found", func(t *testing.T) {
|
||||
testFS := NewDirFS("a")
|
||||
_, errno = testFS.OpenFile(".", os.O_RDONLY, 0)
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
require.EqualErrno(t, sys.ENOENT, errno)
|
||||
})
|
||||
t.Run("host path not a directory", func(t *testing.T) {
|
||||
arg0 := os.Args[0] // should be safe in scratch tests which don't have the source mounted.
|
||||
@@ -37,7 +38,7 @@ func TestNewDirFS(t *testing.T) {
|
||||
d, errno := testFS.OpenFile(".", os.O_RDONLY, 0)
|
||||
require.EqualErrno(t, 0, errno)
|
||||
_, errno = d.Readdir(-1)
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
require.EqualErrno(t, sys.EBADF, errno)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -93,7 +94,7 @@ func TestDirFS_MkDir(t *testing.T) {
|
||||
|
||||
t.Run("dir exists", func(t *testing.T) {
|
||||
err := testFS.Mkdir(name, fs.ModeDir)
|
||||
require.EqualErrno(t, syscall.EEXIST, err)
|
||||
require.EqualErrno(t, sys.EEXIST, err)
|
||||
})
|
||||
|
||||
t.Run("file exists", func(t *testing.T) {
|
||||
@@ -101,12 +102,12 @@ func TestDirFS_MkDir(t *testing.T) {
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
|
||||
err := testFS.Mkdir(name, fs.ModeDir)
|
||||
require.EqualErrno(t, syscall.EEXIST, err)
|
||||
require.EqualErrno(t, sys.EEXIST, err)
|
||||
})
|
||||
t.Run("try creating on file", func(t *testing.T) {
|
||||
filePath := path.Join("non-existing-dir", "foo.txt")
|
||||
err := testFS.Mkdir(filePath, fs.ModeDir)
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
require.EqualErrno(t, sys.ENOENT, err)
|
||||
})
|
||||
|
||||
// Remove the path so that we can test creating it with perms.
|
||||
@@ -161,7 +162,7 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testFS.Rename("file2", file1)
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
require.EqualErrno(t, sys.ENOENT, err)
|
||||
})
|
||||
t.Run("file to non-exist", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
@@ -180,7 +181,7 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, errno = os.Stat(file1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, platform.UnwrapOSError(errno))
|
||||
require.EqualErrno(t, sys.ENOENT, sys.UnwrapOSError(errno))
|
||||
|
||||
s, err := os.Stat(file2Path)
|
||||
require.NoError(t, err)
|
||||
@@ -201,7 +202,7 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err := os.Stat(dir1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, platform.UnwrapOSError(err))
|
||||
require.EqualErrno(t, sys.ENOENT, sys.UnwrapOSError(err))
|
||||
|
||||
s, err := os.Stat(dir2Path)
|
||||
require.NoError(t, err)
|
||||
@@ -224,7 +225,7 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
require.NoError(t, f.Close())
|
||||
|
||||
errno := testFS.Rename(dir1, dir2)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, errno)
|
||||
require.EqualErrno(t, sys.ENOTDIR, errno)
|
||||
})
|
||||
t.Run("file to dir", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
@@ -241,7 +242,7 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
require.NoError(t, os.Mkdir(dir1Path, 0o700))
|
||||
|
||||
errno := testFS.Rename(file1, dir1)
|
||||
require.EqualErrno(t, syscall.EISDIR, errno)
|
||||
require.EqualErrno(t, sys.EISDIR, errno)
|
||||
})
|
||||
|
||||
// Similar to https://github.com/ziglang/zig/blob/0.10.1/lib/std/fs/test.zig#L567-L582
|
||||
@@ -269,7 +270,7 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err = os.Stat(dir1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, platform.UnwrapOSError(err))
|
||||
require.EqualErrno(t, sys.ENOENT, sys.UnwrapOSError(err))
|
||||
|
||||
// Show the file inside that directory moved
|
||||
s, err := os.Stat(path.Join(dir2Path, file1))
|
||||
@@ -302,7 +303,7 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
errno := testFS.Rename(dir1, dir2)
|
||||
require.EqualErrno(t, syscall.ENOTEMPTY, errno)
|
||||
require.EqualErrno(t, sys.ENOTEMPTY, errno)
|
||||
})
|
||||
|
||||
t.Run("file to file", func(t *testing.T) {
|
||||
@@ -326,7 +327,7 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err = os.Stat(file1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, platform.UnwrapOSError(err))
|
||||
require.EqualErrno(t, sys.ENOENT, sys.UnwrapOSError(err))
|
||||
|
||||
// Show the file1 overwrote file2
|
||||
b, err := os.ReadFile(file2Path)
|
||||
@@ -375,7 +376,7 @@ func TestDirFS_Rmdir(t *testing.T) {
|
||||
name := "rmdir"
|
||||
|
||||
err := testFS.Rmdir(name)
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
require.EqualErrno(t, sys.ENOENT, err)
|
||||
})
|
||||
|
||||
t.Run("dir not empty", func(t *testing.T) {
|
||||
@@ -390,7 +391,7 @@ func TestDirFS_Rmdir(t *testing.T) {
|
||||
require.NoError(t, os.WriteFile(fileInDir, []byte{}, 0o600))
|
||||
|
||||
err := testFS.Rmdir(name)
|
||||
require.EqualErrno(t, syscall.ENOTEMPTY, err)
|
||||
require.EqualErrno(t, sys.ENOTEMPTY, err)
|
||||
|
||||
require.NoError(t, os.Remove(fileInDir))
|
||||
})
|
||||
@@ -452,7 +453,7 @@ func TestDirFS_Rmdir(t *testing.T) {
|
||||
require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600))
|
||||
|
||||
err := testFS.Rmdir(name)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, err)
|
||||
require.EqualErrno(t, sys.ENOTDIR, err)
|
||||
|
||||
require.NoError(t, os.Remove(realPath))
|
||||
})
|
||||
@@ -465,7 +466,7 @@ func TestDirFS_Unlink(t *testing.T) {
|
||||
name := "unlink"
|
||||
|
||||
err := testFS.Unlink(name)
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
require.EqualErrno(t, sys.ENOENT, err)
|
||||
})
|
||||
|
||||
t.Run("target: dir", func(t *testing.T) {
|
||||
@@ -478,7 +479,7 @@ func TestDirFS_Unlink(t *testing.T) {
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
|
||||
err := testFS.Unlink(dir)
|
||||
require.EqualErrno(t, syscall.EISDIR, err)
|
||||
require.EqualErrno(t, sys.EISDIR, err)
|
||||
|
||||
require.NoError(t, os.Remove(realPath))
|
||||
})
|
||||
@@ -531,12 +532,12 @@ func TestDirFS_Utimesns(t *testing.T) {
|
||||
|
||||
t.Run("doesn't exist", func(t *testing.T) {
|
||||
err := testFS.Utimens("nope", nil, true)
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
require.EqualErrno(t, sys.ENOENT, err)
|
||||
err = testFS.Utimens("nope", nil, false)
|
||||
if SupportsSymlinkNoFollow {
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
require.EqualErrno(t, sys.ENOENT, err)
|
||||
} else {
|
||||
require.EqualErrno(t, syscall.ENOSYS, err)
|
||||
require.EqualErrno(t, sys.ENOSYS, err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -647,7 +648,7 @@ func TestDirFS_Utimesns(t *testing.T) {
|
||||
|
||||
errno = testFS.Utimens(path, tc.times, !symlinkNoFollow)
|
||||
if symlinkNoFollow && !SupportsSymlinkNoFollow {
|
||||
require.EqualErrno(t, syscall.ENOSYS, errno)
|
||||
require.EqualErrno(t, sys.ENOSYS, errno)
|
||||
return
|
||||
}
|
||||
require.EqualErrno(t, 0, errno)
|
||||
@@ -759,12 +760,12 @@ func TestDirFS_Readdir(t *testing.T) {
|
||||
// tests enforce this. This test is Windows sensitive as well.
|
||||
//
|
||||
// https://github.com/ziglang/zig/blob/e3736baddb8ecff90f0594be9f604c7484ce9aa2/lib/std/fs/test.zig#L311C1-L311C1
|
||||
t.Run("syscall.ENOENT or no error, deleted while reading", func(t *testing.T) {
|
||||
t.Run("sys.ENOENT or no error, deleted while reading", func(t *testing.T) {
|
||||
require.NoError(t, os.RemoveAll(path.Join(root, readDirTarget)))
|
||||
|
||||
dirents, errno := dirFile.Readdir(-1)
|
||||
if errno != 0 {
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
require.EqualErrno(t, sys.ENOENT, errno)
|
||||
}
|
||||
|
||||
require.Equal(t, 0, len(dirents))
|
||||
@@ -780,11 +781,11 @@ func TestDirFS_Link(t *testing.T) {
|
||||
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
require.EqualErrno(t, testFS.Link("cat", ""), syscall.ENOENT)
|
||||
require.EqualErrno(t, testFS.Link("sub/test.txt", "sub/test.txt"), syscall.EEXIST)
|
||||
require.EqualErrno(t, testFS.Link("sub/test.txt", "."), syscall.EEXIST)
|
||||
require.EqualErrno(t, testFS.Link("sub/test.txt", ""), syscall.EEXIST)
|
||||
require.EqualErrno(t, testFS.Link("sub/test.txt", "/"), syscall.EEXIST)
|
||||
require.EqualErrno(t, testFS.Link("cat", ""), sys.ENOENT)
|
||||
require.EqualErrno(t, testFS.Link("sub/test.txt", "sub/test.txt"), sys.EEXIST)
|
||||
require.EqualErrno(t, testFS.Link("sub/test.txt", "."), sys.EEXIST)
|
||||
require.EqualErrno(t, testFS.Link("sub/test.txt", ""), sys.EEXIST)
|
||||
require.EqualErrno(t, testFS.Link("sub/test.txt", "/"), sys.EEXIST)
|
||||
require.EqualErrno(t, 0, testFS.Link("sub/test.txt", "foo"))
|
||||
}
|
||||
|
||||
@@ -797,7 +798,7 @@ func TestDirFS_Symlink(t *testing.T) {
|
||||
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
require.EqualErrno(t, syscall.EEXIST, testFS.Symlink("sub/test.txt", "sub/test.txt"))
|
||||
require.EqualErrno(t, sys.EEXIST, testFS.Symlink("sub/test.txt", "sub/test.txt"))
|
||||
// Non-existing old name is allowed.
|
||||
require.EqualErrno(t, 0, testFS.Symlink("non-existing", "aa"))
|
||||
require.EqualErrno(t, 0, testFS.Symlink("sub/", "symlinked-subdir"))
|
||||
|
||||
+61
-61
@@ -6,8 +6,8 @@ import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
@@ -37,14 +37,14 @@ func NewStdioFile(stdin bool, f fs.File) (fsapi.File, error) {
|
||||
return &stdioFile{File: file, st: sys.Stat_t{Mode: mode, Nlink: 1}}, nil
|
||||
}
|
||||
|
||||
func OpenFile(path string, flag int, perm fs.FileMode) (*os.File, syscall.Errno) {
|
||||
func OpenFile(path string, flag int, perm fs.FileMode) (*os.File, experimentalsys.Errno) {
|
||||
if flag&fsapi.O_DIRECTORY != 0 && flag&(syscall.O_WRONLY|syscall.O_RDWR) != 0 {
|
||||
return nil, syscall.EISDIR // invalid to open a directory writeable
|
||||
return nil, experimentalsys.EISDIR // invalid to open a directory writeable
|
||||
}
|
||||
return openFile(path, flag, perm)
|
||||
}
|
||||
|
||||
func OpenOSFile(path string, flag int, perm fs.FileMode) (fsapi.File, syscall.Errno) {
|
||||
func OpenOSFile(path string, flag int, perm fs.FileMode) (fsapi.File, experimentalsys.Errno) {
|
||||
f, errno := OpenFile(path, flag, perm)
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
@@ -52,12 +52,12 @@ func OpenOSFile(path string, flag int, perm fs.FileMode) (fsapi.File, syscall.Er
|
||||
return newOsFile(path, flag, perm, f), 0
|
||||
}
|
||||
|
||||
func OpenFSFile(fs fs.FS, path string, flag int, perm fs.FileMode) (fsapi.File, syscall.Errno) {
|
||||
func OpenFSFile(fs fs.FS, path string, flag int, perm fs.FileMode) (fsapi.File, experimentalsys.Errno) {
|
||||
if flag&fsapi.O_DIRECTORY != 0 && flag&(syscall.O_WRONLY|syscall.O_RDWR) != 0 {
|
||||
return nil, syscall.EISDIR // invalid to open a directory writeable
|
||||
return nil, experimentalsys.EISDIR // invalid to open a directory writeable
|
||||
}
|
||||
f, err := fs.Open(path)
|
||||
if errno := platform.UnwrapOSError(err); errno != 0 {
|
||||
if errno := experimentalsys.UnwrapOSError(err); errno != 0 {
|
||||
return nil, errno
|
||||
}
|
||||
// Don't return an os.File because the path is not absolute. osFile needs
|
||||
@@ -71,7 +71,7 @@ type stdioFile struct {
|
||||
}
|
||||
|
||||
// SetAppend implements File.SetAppend
|
||||
func (f *stdioFile) SetAppend(bool) syscall.Errno {
|
||||
func (f *stdioFile) SetAppend(bool) experimentalsys.Errno {
|
||||
// Ignore for stdio.
|
||||
return 0
|
||||
}
|
||||
@@ -82,12 +82,12 @@ func (f *stdioFile) IsAppend() bool {
|
||||
}
|
||||
|
||||
// Stat implements File.Stat
|
||||
func (f *stdioFile) Stat() (sys.Stat_t, syscall.Errno) {
|
||||
func (f *stdioFile) Stat() (sys.Stat_t, experimentalsys.Errno) {
|
||||
return f.st, 0
|
||||
}
|
||||
|
||||
// Close implements File.Close
|
||||
func (f *stdioFile) Close() syscall.Errno {
|
||||
func (f *stdioFile) Close() experimentalsys.Errno {
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ type fsFile struct {
|
||||
// before Readdir.
|
||||
reopenDir bool
|
||||
|
||||
// closed is true when closed was called. This ensures proper syscall.EBADF
|
||||
// closed is true when closed was called. This ensures proper sys.EBADF
|
||||
closed bool
|
||||
|
||||
// cachedStat includes fields that won't change while a file is open.
|
||||
@@ -133,7 +133,7 @@ type cachedStat struct {
|
||||
|
||||
// cachedStat returns the cacheable parts of fsapi.Stat_t or an error if they
|
||||
// couldn't be retrieved.
|
||||
func (f *fsFile) cachedStat() (dev uint64, ino sys.Inode, isDir bool, errno syscall.Errno) {
|
||||
func (f *fsFile) cachedStat() (dev uint64, ino sys.Inode, isDir bool, errno experimentalsys.Errno) {
|
||||
if f.cachedSt == nil {
|
||||
if _, errno = f.Stat(); errno != 0 {
|
||||
return
|
||||
@@ -143,19 +143,19 @@ func (f *fsFile) cachedStat() (dev uint64, ino sys.Inode, isDir bool, errno sysc
|
||||
}
|
||||
|
||||
// Dev implements the same method as documented on fsapi.File
|
||||
func (f *fsFile) Dev() (uint64, syscall.Errno) {
|
||||
func (f *fsFile) Dev() (uint64, experimentalsys.Errno) {
|
||||
dev, _, _, errno := f.cachedStat()
|
||||
return dev, errno
|
||||
}
|
||||
|
||||
// Ino implements the same method as documented on fsapi.File
|
||||
func (f *fsFile) Ino() (sys.Inode, syscall.Errno) {
|
||||
func (f *fsFile) Ino() (sys.Inode, experimentalsys.Errno) {
|
||||
_, ino, _, errno := f.cachedStat()
|
||||
return ino, errno
|
||||
}
|
||||
|
||||
// IsDir implements the same method as documented on fsapi.File
|
||||
func (f *fsFile) IsDir() (bool, syscall.Errno) {
|
||||
func (f *fsFile) IsDir() (bool, experimentalsys.Errno) {
|
||||
_, _, isDir, errno := f.cachedStat()
|
||||
return isDir, errno
|
||||
}
|
||||
@@ -166,28 +166,28 @@ func (f *fsFile) IsAppend() bool {
|
||||
}
|
||||
|
||||
// SetAppend implements the same method as documented on fsapi.File
|
||||
func (f *fsFile) SetAppend(bool) (errno syscall.Errno) {
|
||||
return fileError(f, f.closed, syscall.ENOSYS)
|
||||
func (f *fsFile) SetAppend(bool) (errno experimentalsys.Errno) {
|
||||
return fileError(f, f.closed, experimentalsys.ENOSYS)
|
||||
}
|
||||
|
||||
// Stat implements the same method as documented on fsapi.File
|
||||
func (f *fsFile) Stat() (sys.Stat_t, syscall.Errno) {
|
||||
func (f *fsFile) Stat() (sys.Stat_t, experimentalsys.Errno) {
|
||||
if f.closed {
|
||||
return sys.Stat_t{}, syscall.EBADF
|
||||
return sys.Stat_t{}, experimentalsys.EBADF
|
||||
}
|
||||
|
||||
st, errno := statFile(f.file)
|
||||
switch errno {
|
||||
case 0:
|
||||
f.cachedSt = &cachedStat{dev: st.Dev, ino: st.Ino, isDir: st.Mode&fs.ModeDir == fs.ModeDir}
|
||||
case syscall.EIO:
|
||||
errno = syscall.EBADF
|
||||
case experimentalsys.EIO:
|
||||
errno = experimentalsys.EBADF
|
||||
}
|
||||
return st, errno
|
||||
}
|
||||
|
||||
// Read implements the same method as documented on fsapi.File
|
||||
func (f *fsFile) Read(buf []byte) (n int, errno syscall.Errno) {
|
||||
func (f *fsFile) Read(buf []byte) (n int, errno experimentalsys.Errno) {
|
||||
if n, errno = read(f.file, buf); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
@@ -196,7 +196,7 @@ func (f *fsFile) Read(buf []byte) (n int, errno syscall.Errno) {
|
||||
}
|
||||
|
||||
// Pread implements the same method as documented on fsapi.File
|
||||
func (f *fsFile) Pread(buf []byte, off int64) (n int, errno syscall.Errno) {
|
||||
func (f *fsFile) Pread(buf []byte, off int64) (n int, errno experimentalsys.Errno) {
|
||||
if ra, ok := f.file.(io.ReaderAt); ok {
|
||||
if n, errno = pread(ra, buf, off); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
@@ -210,7 +210,7 @@ func (f *fsFile) Pread(buf []byte, off int64) (n int, errno syscall.Errno) {
|
||||
// Determine the current position in the file, as we need to revert it.
|
||||
currentOffset, err := rs.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return 0, fileError(f, f.closed, platform.UnwrapOSError(err))
|
||||
return 0, fileError(f, f.closed, experimentalsys.UnwrapOSError(err))
|
||||
}
|
||||
|
||||
// Put the read position back when complete.
|
||||
@@ -219,23 +219,23 @@ func (f *fsFile) Pread(buf []byte, off int64) (n int, errno syscall.Errno) {
|
||||
// If the current offset isn't in sync with this reader, move it.
|
||||
if off != currentOffset {
|
||||
if _, err = rs.Seek(off, io.SeekStart); err != nil {
|
||||
return 0, fileError(f, f.closed, platform.UnwrapOSError(err))
|
||||
return 0, fileError(f, f.closed, experimentalsys.UnwrapOSError(err))
|
||||
}
|
||||
}
|
||||
|
||||
n, err = rs.Read(buf)
|
||||
if errno = platform.UnwrapOSError(err); errno != 0 {
|
||||
if errno = experimentalsys.UnwrapOSError(err); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
}
|
||||
} else {
|
||||
errno = syscall.ENOSYS // unsupported
|
||||
errno = experimentalsys.ENOSYS // unsupported
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Seek implements the same method as documented on fsapi.File
|
||||
func (f *fsFile) Seek(offset int64, whence int) (newOffset int64, errno syscall.Errno) {
|
||||
func (f *fsFile) Seek(offset int64, whence int) (newOffset int64, errno experimentalsys.Errno) {
|
||||
// If this is a directory, and we're attempting to seek to position zero,
|
||||
// we have to re-open the file to ensure the directory state is reset.
|
||||
var isDir bool
|
||||
@@ -252,7 +252,7 @@ func (f *fsFile) Seek(offset int64, whence int) (newOffset int64, errno syscall.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
}
|
||||
} else {
|
||||
errno = syscall.ENOSYS // unsupported
|
||||
errno = experimentalsys.ENOSYS // unsupported
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -261,12 +261,12 @@ func (f *fsFile) Seek(offset int64, whence int) (newOffset int64, errno syscall.
|
||||
//
|
||||
// Notably, this uses readdirFile or fs.ReadDirFile if available. This does not
|
||||
// return inodes on windows.
|
||||
func (f *fsFile) Readdir(n int) (dirents []fsapi.Dirent, errno syscall.Errno) {
|
||||
func (f *fsFile) Readdir(n int) (dirents []fsapi.Dirent, errno experimentalsys.Errno) {
|
||||
// Windows lets you Readdir after close, fs.File also may not implement
|
||||
// close in a meaningful way. read our closed field to return consistent
|
||||
// results.
|
||||
if f.closed {
|
||||
errno = syscall.EBADF
|
||||
errno = experimentalsys.EBADF
|
||||
return
|
||||
}
|
||||
|
||||
@@ -300,39 +300,39 @@ func (f *fsFile) Readdir(n int) (dirents []fsapi.Dirent, errno syscall.Errno) {
|
||||
dirents = append(dirents, fsapi.Dirent{Name: e.Name(), Type: e.Type()})
|
||||
}
|
||||
} else {
|
||||
errno = syscall.EBADF // not a directory
|
||||
errno = experimentalsys.EBADF // not a directory
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Write implements the same method as documented on fsapi.File.
|
||||
func (f *fsFile) Write(buf []byte) (n int, errno syscall.Errno) {
|
||||
func (f *fsFile) Write(buf []byte) (n int, errno experimentalsys.Errno) {
|
||||
if w, ok := f.file.(io.Writer); ok {
|
||||
if n, errno = write(w, buf); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
}
|
||||
} else {
|
||||
errno = syscall.ENOSYS // unsupported
|
||||
errno = experimentalsys.ENOSYS // unsupported
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pwrite implements the same method as documented on fsapi.File.
|
||||
func (f *fsFile) Pwrite(buf []byte, off int64) (n int, errno syscall.Errno) {
|
||||
func (f *fsFile) Pwrite(buf []byte, off int64) (n int, errno experimentalsys.Errno) {
|
||||
if wa, ok := f.file.(io.WriterAt); ok {
|
||||
if n, errno = pwrite(wa, buf, off); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
}
|
||||
} else {
|
||||
errno = syscall.ENOSYS // unsupported
|
||||
errno = experimentalsys.ENOSYS // unsupported
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Close implements the same method as documented on fsapi.File.
|
||||
func (f *fsFile) Close() syscall.Errno {
|
||||
func (f *fsFile) Close() experimentalsys.Errno {
|
||||
if f.closed {
|
||||
return 0
|
||||
}
|
||||
@@ -340,12 +340,12 @@ func (f *fsFile) Close() syscall.Errno {
|
||||
return f.close()
|
||||
}
|
||||
|
||||
func (f *fsFile) close() syscall.Errno {
|
||||
return platform.UnwrapOSError(f.file.Close())
|
||||
func (f *fsFile) close() experimentalsys.Errno {
|
||||
return experimentalsys.UnwrapOSError(f.file.Close())
|
||||
}
|
||||
|
||||
// dirError is used for commands that work against a directory, but not a file.
|
||||
func dirError(f fsapi.File, isClosed bool, errno syscall.Errno) syscall.Errno {
|
||||
func dirError(f fsapi.File, isClosed bool, errno experimentalsys.Errno) experimentalsys.Errno {
|
||||
if vErrno := validate(f, isClosed, false, true); vErrno != 0 {
|
||||
return vErrno
|
||||
}
|
||||
@@ -353,7 +353,7 @@ func dirError(f fsapi.File, isClosed bool, errno syscall.Errno) syscall.Errno {
|
||||
}
|
||||
|
||||
// fileError is used for commands that work against a file, but not a directory.
|
||||
func fileError(f fsapi.File, isClosed bool, errno syscall.Errno) syscall.Errno {
|
||||
func fileError(f fsapi.File, isClosed bool, errno experimentalsys.Errno) experimentalsys.Errno {
|
||||
if vErrno := validate(f, isClosed, true, false); vErrno != 0 {
|
||||
return vErrno
|
||||
}
|
||||
@@ -361,9 +361,9 @@ func fileError(f fsapi.File, isClosed bool, errno syscall.Errno) syscall.Errno {
|
||||
}
|
||||
|
||||
// validate is used to making syscalls which will fail.
|
||||
func validate(f fsapi.File, isClosed, wantFile, wantDir bool) syscall.Errno {
|
||||
func validate(f fsapi.File, isClosed, wantFile, wantDir bool) experimentalsys.Errno {
|
||||
if isClosed {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
}
|
||||
|
||||
isDir, errno := f.IsDir()
|
||||
@@ -372,53 +372,53 @@ func validate(f fsapi.File, isClosed, wantFile, wantDir bool) syscall.Errno {
|
||||
}
|
||||
|
||||
if wantFile && isDir {
|
||||
return syscall.EISDIR
|
||||
return experimentalsys.EISDIR
|
||||
} else if wantDir && !isDir {
|
||||
return syscall.ENOTDIR
|
||||
return experimentalsys.ENOTDIR
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func read(r io.Reader, buf []byte) (n int, errno syscall.Errno) {
|
||||
func read(r io.Reader, buf []byte) (n int, errno experimentalsys.Errno) {
|
||||
if len(buf) == 0 {
|
||||
return 0, 0 // less overhead on zero-length reads.
|
||||
}
|
||||
|
||||
n, err := r.Read(buf)
|
||||
return n, platform.UnwrapOSError(err)
|
||||
return n, experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
func pread(ra io.ReaderAt, buf []byte, off int64) (n int, errno syscall.Errno) {
|
||||
func pread(ra io.ReaderAt, buf []byte, off int64) (n int, errno experimentalsys.Errno) {
|
||||
if len(buf) == 0 {
|
||||
return 0, 0 // less overhead on zero-length reads.
|
||||
}
|
||||
|
||||
n, err := ra.ReadAt(buf, off)
|
||||
return n, platform.UnwrapOSError(err)
|
||||
return n, experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
func seek(s io.Seeker, offset int64, whence int) (int64, syscall.Errno) {
|
||||
func seek(s io.Seeker, offset int64, whence int) (int64, experimentalsys.Errno) {
|
||||
if uint(whence) > io.SeekEnd {
|
||||
return 0, syscall.EINVAL // negative or exceeds the largest valid whence
|
||||
return 0, experimentalsys.EINVAL // negative or exceeds the largest valid whence
|
||||
}
|
||||
|
||||
newOffset, err := s.Seek(offset, whence)
|
||||
return newOffset, platform.UnwrapOSError(err)
|
||||
return newOffset, experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// reopenFile allows re-opening a file for reasons such as applying flags or
|
||||
// directory iteration.
|
||||
type reopenFile func() syscall.Errno
|
||||
type reopenFile func() experimentalsys.Errno
|
||||
|
||||
// compile-time check to ensure fsFile.reopen implements reopenFile.
|
||||
var _ reopenFile = (*fsFile)(nil).reopen
|
||||
|
||||
// reopen implements the same method as documented on reopenFile.
|
||||
func (f *fsFile) reopen() syscall.Errno {
|
||||
func (f *fsFile) reopen() experimentalsys.Errno {
|
||||
_ = f.close()
|
||||
var err error
|
||||
f.file, err = f.fs.Open(f.name)
|
||||
return platform.UnwrapOSError(err)
|
||||
return experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// readdirFile allows masking the `Readdir` function on os.File.
|
||||
@@ -427,9 +427,9 @@ type readdirFile interface {
|
||||
}
|
||||
|
||||
// readdir uses readdirFile.Readdir, special casing windows when path !="".
|
||||
func readdir(f readdirFile, path string, n int) (dirents []fsapi.Dirent, errno syscall.Errno) {
|
||||
func readdir(f readdirFile, path string, n int) (dirents []fsapi.Dirent, errno experimentalsys.Errno) {
|
||||
fis, e := f.Readdir(n)
|
||||
if errno = platform.UnwrapOSError(e); errno != 0 {
|
||||
if errno = experimentalsys.UnwrapOSError(e); errno != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -449,20 +449,20 @@ func readdir(f readdirFile, path string, n int) (dirents []fsapi.Dirent, errno s
|
||||
return
|
||||
}
|
||||
|
||||
func write(w io.Writer, buf []byte) (n int, errno syscall.Errno) {
|
||||
func write(w io.Writer, buf []byte) (n int, errno experimentalsys.Errno) {
|
||||
if len(buf) == 0 {
|
||||
return 0, 0 // less overhead on zero-length writes.
|
||||
}
|
||||
|
||||
n, err := w.Write(buf)
|
||||
return n, platform.UnwrapOSError(err)
|
||||
return n, experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
func pwrite(w io.WriterAt, buf []byte, off int64) (n int, errno syscall.Errno) {
|
||||
func pwrite(w io.WriterAt, buf []byte, off int64) (n int, errno experimentalsys.Errno) {
|
||||
if len(buf) == 0 {
|
||||
return 0, 0 // less overhead on zero-length writes.
|
||||
}
|
||||
|
||||
n, err := w.WriteAt(buf, off)
|
||||
return n, platform.UnwrapOSError(err)
|
||||
return n, experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
+43
-42
@@ -12,6 +12,7 @@ import (
|
||||
gofstest "testing/fstest"
|
||||
"time"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
@@ -67,7 +68,7 @@ func TestRegularFileSetNonblock(t *testing.T) {
|
||||
// Read from the file without ever writing to it should not block.
|
||||
buf := make([]byte, 8)
|
||||
_, e := rF.Read(buf)
|
||||
require.EqualErrno(t, syscall.EAGAIN, e)
|
||||
require.EqualErrno(t, experimentalsys.EAGAIN, e)
|
||||
|
||||
errno = rF.SetNonblock(false)
|
||||
require.EqualErrno(t, 0, errno)
|
||||
@@ -88,7 +89,7 @@ func TestReadFdNonblock(t *testing.T) {
|
||||
// Read from the file without ever writing to it should not block.
|
||||
buf := make([]byte, 8)
|
||||
_, e := readFd(fd, buf)
|
||||
require.EqualErrno(t, syscall.EAGAIN, e)
|
||||
require.EqualErrno(t, experimentalsys.EAGAIN, e)
|
||||
}
|
||||
|
||||
func TestFileSetAppend(t *testing.T) {
|
||||
@@ -308,7 +309,7 @@ func TestFilePollRead(t *testing.T) {
|
||||
// When there's nothing in the pipe, it isn't ready.
|
||||
ready, errno := rF.PollRead(&timeout)
|
||||
if runtime.GOOS == "windows" {
|
||||
require.EqualErrno(t, syscall.ENOSYS, errno)
|
||||
require.EqualErrno(t, experimentalsys.ENOSYS, errno)
|
||||
t.Skip("TODO: windows File.PollRead")
|
||||
}
|
||||
require.EqualErrno(t, 0, errno)
|
||||
@@ -400,7 +401,7 @@ func TestFilePread_Unsupported(t *testing.T) {
|
||||
|
||||
buf := make([]byte, 3)
|
||||
_, errno = f.Pread(buf, 0)
|
||||
require.EqualErrno(t, syscall.ENOSYS, errno)
|
||||
require.EqualErrno(t, experimentalsys.ENOSYS, errno)
|
||||
}
|
||||
|
||||
func TestFileRead_Errors(t *testing.T) {
|
||||
@@ -415,13 +416,13 @@ func TestFileRead_Errors(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fn func(fsapi.File) syscall.Errno
|
||||
fn func(fsapi.File) experimentalsys.Errno
|
||||
}{
|
||||
{name: "Read", fn: func(f fsapi.File) syscall.Errno {
|
||||
{name: "Read", fn: func(f fsapi.File) experimentalsys.Errno {
|
||||
_, errno := f.Read(buf)
|
||||
return errno
|
||||
}},
|
||||
{name: "Pread", fn: func(f fsapi.File) syscall.Errno {
|
||||
{name: "Pread", fn: func(f fsapi.File) experimentalsys.Errno {
|
||||
_, errno := f.Pread(buf, 0)
|
||||
return errno
|
||||
}},
|
||||
@@ -434,7 +435,7 @@ func TestFileRead_Errors(t *testing.T) {
|
||||
t.Run("EBADF when not open for reading", func(t *testing.T) {
|
||||
// The descriptor exists, but not open for reading
|
||||
errno := tc.fn(f)
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
require.EqualErrno(t, experimentalsys.EBADF, errno)
|
||||
})
|
||||
testEISDIR(t, tc.fn)
|
||||
})
|
||||
@@ -447,18 +448,18 @@ func TestFileSeek(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
openFile func(string) (fsapi.File, syscall.Errno)
|
||||
openFile func(string) (fsapi.File, experimentalsys.Errno)
|
||||
}{
|
||||
{name: "fsFile os.DirFS", openFile: func(name string) (fsapi.File, syscall.Errno) {
|
||||
{name: "fsFile os.DirFS", openFile: func(name string) (fsapi.File, experimentalsys.Errno) {
|
||||
return OpenFSFile(dirFS, name, syscall.O_RDONLY, 0)
|
||||
}},
|
||||
{name: "fsFile embed.api.FS", openFile: func(name string) (fsapi.File, syscall.Errno) {
|
||||
{name: "fsFile embed.api.FS", openFile: func(name string) (fsapi.File, experimentalsys.Errno) {
|
||||
return OpenFSFile(embedFS, name, syscall.O_RDONLY, 0)
|
||||
}},
|
||||
{name: "fsFile fstest.MapFS", openFile: func(name string) (fsapi.File, syscall.Errno) {
|
||||
{name: "fsFile fstest.MapFS", openFile: func(name string) (fsapi.File, experimentalsys.Errno) {
|
||||
return OpenFSFile(mapFS, name, syscall.O_RDONLY, 0)
|
||||
}},
|
||||
{name: "osFile", openFile: func(name string) (fsapi.File, syscall.Errno) {
|
||||
{name: "osFile", openFile: func(name string) (fsapi.File, experimentalsys.Errno) {
|
||||
return OpenOSFile(path.Join(tmpDir, name), syscall.O_RDONLY, 0o666)
|
||||
}},
|
||||
}
|
||||
@@ -475,13 +476,13 @@ func TestFileSeek(t *testing.T) {
|
||||
|
||||
// Shouldn't be able to use an invalid whence
|
||||
_, errno = f.Seek(0, io.SeekEnd+1)
|
||||
require.EqualErrno(t, syscall.EINVAL, errno)
|
||||
require.EqualErrno(t, experimentalsys.EINVAL, errno)
|
||||
_, errno = f.Seek(0, -1)
|
||||
require.EqualErrno(t, syscall.EINVAL, errno)
|
||||
require.EqualErrno(t, experimentalsys.EINVAL, errno)
|
||||
|
||||
// Shouldn't be able to seek before the file starts.
|
||||
_, errno = f.Seek(-1, io.SeekStart)
|
||||
require.EqualErrno(t, syscall.EINVAL, errno)
|
||||
require.EqualErrno(t, experimentalsys.EINVAL, errno)
|
||||
|
||||
requireRead(t, f, buf) // read 3 bytes
|
||||
|
||||
@@ -537,7 +538,7 @@ func TestFileSeek(t *testing.T) {
|
||||
require.Equal(t, direntCount, len(dirents))
|
||||
})
|
||||
|
||||
seekToZero := func(f fsapi.File) syscall.Errno {
|
||||
seekToZero := func(f fsapi.File) experimentalsys.Errno {
|
||||
_, errno := f.Seek(0, io.SeekStart)
|
||||
return errno
|
||||
}
|
||||
@@ -596,7 +597,7 @@ func TestFileSeek_Unsupported(t *testing.T) {
|
||||
defer f.Close()
|
||||
|
||||
_, errno = f.Seek(0, io.SeekCurrent)
|
||||
require.EqualErrno(t, syscall.ENOSYS, errno)
|
||||
require.EqualErrno(t, experimentalsys.ENOSYS, errno)
|
||||
}
|
||||
|
||||
func TestFileWriteAndPwrite(t *testing.T) {
|
||||
@@ -661,15 +662,15 @@ func TestFileWrite_empty(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fn func(fsapi.File, []byte) (int, syscall.Errno)
|
||||
fn func(fsapi.File, []byte) (int, experimentalsys.Errno)
|
||||
}{
|
||||
{name: "Write", fn: func(f fsapi.File, buf []byte) (int, syscall.Errno) {
|
||||
{name: "Write", fn: func(f fsapi.File, buf []byte) (int, experimentalsys.Errno) {
|
||||
return f.Write(buf)
|
||||
}},
|
||||
{name: "Pwrite from zero", fn: func(f fsapi.File, buf []byte) (int, syscall.Errno) {
|
||||
{name: "Pwrite from zero", fn: func(f fsapi.File, buf []byte) (int, experimentalsys.Errno) {
|
||||
return f.Pwrite(buf, 0)
|
||||
}},
|
||||
{name: "Pwrite from 3", fn: func(f fsapi.File, buf []byte) (int, syscall.Errno) {
|
||||
{name: "Pwrite from 3", fn: func(f fsapi.File, buf []byte) (int, experimentalsys.Errno) {
|
||||
return f.Pwrite(buf, 3)
|
||||
}},
|
||||
}
|
||||
@@ -703,12 +704,12 @@ func TestFileWrite_Unsupported(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fn func(fsapi.File, []byte) (int, syscall.Errno)
|
||||
fn func(fsapi.File, []byte) (int, experimentalsys.Errno)
|
||||
}{
|
||||
{name: "Write", fn: func(f fsapi.File, buf []byte) (int, syscall.Errno) {
|
||||
{name: "Write", fn: func(f fsapi.File, buf []byte) (int, experimentalsys.Errno) {
|
||||
return f.Write(buf)
|
||||
}},
|
||||
{name: "Pwrite", fn: func(f fsapi.File, buf []byte) (int, syscall.Errno) {
|
||||
{name: "Pwrite", fn: func(f fsapi.File, buf []byte) (int, experimentalsys.Errno) {
|
||||
return f.Pwrite(buf, 0)
|
||||
}},
|
||||
}
|
||||
@@ -720,7 +721,7 @@ func TestFileWrite_Unsupported(t *testing.T) {
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
_, errno := tc.fn(f, buf)
|
||||
require.EqualErrno(t, syscall.ENOSYS, errno)
|
||||
require.EqualErrno(t, experimentalsys.ENOSYS, errno)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -740,13 +741,13 @@ func TestFileWrite_Errors(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fn func(fsapi.File) syscall.Errno
|
||||
fn func(fsapi.File) experimentalsys.Errno
|
||||
}{
|
||||
{name: "Write", fn: func(f fsapi.File) syscall.Errno {
|
||||
{name: "Write", fn: func(f fsapi.File) experimentalsys.Errno {
|
||||
_, errno := f.Write(buf)
|
||||
return errno
|
||||
}},
|
||||
{name: "Pwrite", fn: func(f fsapi.File) syscall.Errno {
|
||||
{name: "Pwrite", fn: func(f fsapi.File) experimentalsys.Errno {
|
||||
_, errno := f.Pwrite(buf, 0)
|
||||
return errno
|
||||
}},
|
||||
@@ -759,7 +760,7 @@ func TestFileWrite_Errors(t *testing.T) {
|
||||
t.Run("EBADF when not open for writing", func(t *testing.T) {
|
||||
// The descriptor exists, but not open for writing
|
||||
errno := tc.fn(f)
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
require.EqualErrno(t, experimentalsys.EBADF, errno)
|
||||
})
|
||||
testEISDIR(t, tc.fn)
|
||||
})
|
||||
@@ -774,7 +775,7 @@ func TestFileDatasync_NoError(t *testing.T) {
|
||||
testSync_NoError(t, fsapi.File.Datasync)
|
||||
}
|
||||
|
||||
func testSync_NoError(t *testing.T, sync func(fsapi.File) syscall.Errno) {
|
||||
func testSync_NoError(t *testing.T, sync func(fsapi.File) experimentalsys.Errno) {
|
||||
roPath := "file_test.go"
|
||||
ro, errno := OpenFSFile(embedFS, roPath, syscall.O_RDONLY, 0)
|
||||
require.EqualErrno(t, 0, errno)
|
||||
@@ -814,7 +815,7 @@ func TestFileDatasync(t *testing.T) {
|
||||
// testSync doesn't guarantee sync works because the operating system may
|
||||
// sync anyway. There is no test in Go for syscall.Fdatasync, but closest is
|
||||
// similar to below. Effectively, this only tests that things don't error.
|
||||
func testSync(t *testing.T, sync func(fsapi.File) syscall.Errno) {
|
||||
func testSync(t *testing.T, sync func(fsapi.File) experimentalsys.Errno) {
|
||||
// Even though it is invalid, try to sync a directory
|
||||
dPath := t.TempDir()
|
||||
d := requireOpenFile(t, dPath, syscall.O_RDONLY, 0)
|
||||
@@ -906,7 +907,7 @@ func TestFileTruncate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
truncateToZero := func(f fsapi.File) syscall.Errno {
|
||||
truncateToZero := func(f fsapi.File) experimentalsys.Errno {
|
||||
return f.Truncate(0)
|
||||
}
|
||||
|
||||
@@ -924,7 +925,7 @@ func TestFileTruncate(t *testing.T) {
|
||||
defer f.Close()
|
||||
|
||||
errno := f.Truncate(-1)
|
||||
require.EqualErrno(t, syscall.EINVAL, errno)
|
||||
require.EqualErrno(t, experimentalsys.EINVAL, errno)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -942,10 +943,10 @@ func TestFileUtimens(t *testing.T) {
|
||||
|
||||
testUtimens(t, true)
|
||||
|
||||
testEBADFIfFileClosed(t, func(f fsapi.File) syscall.Errno {
|
||||
testEBADFIfFileClosed(t, func(f fsapi.File) experimentalsys.Errno {
|
||||
return f.Utimens(nil)
|
||||
})
|
||||
testEBADFIfDirClosed(t, func(d fsapi.File) syscall.Errno {
|
||||
testEBADFIfDirClosed(t, func(d fsapi.File) experimentalsys.Errno {
|
||||
return d.Utimens(nil)
|
||||
})
|
||||
}
|
||||
@@ -1019,18 +1020,18 @@ func TestNewStdioFile(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testEBADFIfDirClosed(t *testing.T, fn func(fsapi.File) syscall.Errno) bool {
|
||||
func testEBADFIfDirClosed(t *testing.T, fn func(fsapi.File) experimentalsys.Errno) bool {
|
||||
return t.Run("EBADF if dir closed", func(t *testing.T) {
|
||||
d := requireOpenFile(t, t.TempDir(), syscall.O_RDONLY, 0o755)
|
||||
|
||||
// close the directory underneath
|
||||
require.EqualErrno(t, 0, d.Close())
|
||||
|
||||
require.EqualErrno(t, syscall.EBADF, fn(d))
|
||||
require.EqualErrno(t, experimentalsys.EBADF, fn(d))
|
||||
})
|
||||
}
|
||||
|
||||
func testEBADFIfFileClosed(t *testing.T, fn func(fsapi.File) syscall.Errno) bool {
|
||||
func testEBADFIfFileClosed(t *testing.T, fn func(fsapi.File) experimentalsys.Errno) bool {
|
||||
return t.Run("EBADF if file closed", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
@@ -1039,16 +1040,16 @@ func testEBADFIfFileClosed(t *testing.T, fn func(fsapi.File) syscall.Errno) bool
|
||||
// close the file underneath
|
||||
require.EqualErrno(t, 0, f.Close())
|
||||
|
||||
require.EqualErrno(t, syscall.EBADF, fn(f))
|
||||
require.EqualErrno(t, experimentalsys.EBADF, fn(f))
|
||||
})
|
||||
}
|
||||
|
||||
func testEISDIR(t *testing.T, fn func(fsapi.File) syscall.Errno) bool {
|
||||
func testEISDIR(t *testing.T, fn func(fsapi.File) experimentalsys.Errno) bool {
|
||||
return t.Run("EISDIR if directory", func(t *testing.T) {
|
||||
f := requireOpenFile(t, os.TempDir(), syscall.O_RDONLY|fsapi.O_DIRECTORY, 0o666)
|
||||
defer f.Close()
|
||||
|
||||
require.EqualErrno(t, syscall.EISDIR, fn(f))
|
||||
require.EqualErrno(t, experimentalsys.EISDIR, fn(f))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -5,17 +5,17 @@ package sysfs
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
const nonBlockingFileIoSupported = true
|
||||
|
||||
// readFd exposes syscall.Read.
|
||||
func readFd(fd uintptr, buf []byte) (int, syscall.Errno) {
|
||||
func readFd(fd uintptr, buf []byte) (int, sys.Errno) {
|
||||
if len(buf) == 0 {
|
||||
return 0, 0 // Short-circuit 0-len reads.
|
||||
}
|
||||
n, err := syscall.Read(int(fd), buf)
|
||||
errno := platform.UnwrapOSError(err)
|
||||
errno := sys.UnwrapOSError(err)
|
||||
return n, errno
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
const nonBlockingFileIoSupported = true
|
||||
@@ -19,27 +19,24 @@ var procPeekNamedPipe = kernel32.NewProc("PeekNamedPipe")
|
||||
// PeekNamedPipe: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe
|
||||
// "GetFileType can assist in determining what device type the handle refers to. A console handle presents as FILE_TYPE_CHAR."
|
||||
// https://learn.microsoft.com/en-us/windows/console/console-handles
|
||||
func readFd(fd uintptr, buf []byte) (int, syscall.Errno) {
|
||||
func readFd(fd uintptr, buf []byte) (int, sys.Errno) {
|
||||
handle := syscall.Handle(fd)
|
||||
fileType, err := syscall.GetFileType(syscall.Stdin)
|
||||
if err != nil {
|
||||
return 0, platform.UnwrapOSError(err)
|
||||
return 0, sys.UnwrapOSError(err)
|
||||
}
|
||||
if fileType&syscall.FILE_TYPE_CHAR == 0 {
|
||||
return -1, syscall.ENOSYS
|
||||
return -1, sys.ENOSYS
|
||||
}
|
||||
n, err := peekNamedPipe(handle)
|
||||
if err != nil {
|
||||
errno := platform.UnwrapOSError(err)
|
||||
if errno == syscall.ERROR_BROKEN_PIPE {
|
||||
return 0, 0
|
||||
}
|
||||
if err == syscall.ERROR_BROKEN_PIPE {
|
||||
return 0, 0
|
||||
}
|
||||
if n == 0 {
|
||||
return -1, syscall.EAGAIN
|
||||
return -1, sys.EAGAIN
|
||||
}
|
||||
un, err := syscall.Read(handle, buf[0:n])
|
||||
return un, platform.UnwrapOSError(err)
|
||||
return un, sys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// peekNamedPipe partially exposes PeekNamedPipe from the Win32 API
|
||||
|
||||
+10
-10
@@ -5,7 +5,7 @@ import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
@@ -35,19 +35,19 @@ const (
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success. The below are expected otherwise:
|
||||
// - syscall.ENOSYS: the implementation does not support this function.
|
||||
// - syscall.EINVAL: `path` is invalid.
|
||||
// - syscall.EEXIST: `path` exists and is a directory.
|
||||
// - syscall.ENOTDIR: `path` exists and is a file.
|
||||
// A zero sys.Errno is success. The below are expected otherwise:
|
||||
// - sys.ENOSYS: the implementation does not support this function.
|
||||
// - sys.EINVAL: `path` is invalid.
|
||||
// - sys.EEXIST: `path` exists and is a directory.
|
||||
// - sys.ENOTDIR: `path` exists and is a file.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - This is like syscall.UtimesNano and `utimensat` with `AT_FDCWD` in
|
||||
// POSIX. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html
|
||||
func Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) syscall.Errno {
|
||||
func Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) experimentalsys.Errno {
|
||||
err := utimens(path, times, symlinkFollow)
|
||||
return platform.UnwrapOSError(err)
|
||||
return experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
func timesToPtr(times *[2]syscall.Timespec) unsafe.Pointer { //nolint:unused
|
||||
@@ -59,7 +59,7 @@ func timesToPtr(times *[2]syscall.Timespec) unsafe.Pointer { //nolint:unused
|
||||
|
||||
func utimensPortable(path string, times *[2]syscall.Timespec, symlinkFollow bool) error { //nolint:unused
|
||||
if !symlinkFollow {
|
||||
return syscall.ENOSYS
|
||||
return experimentalsys.ENOSYS
|
||||
}
|
||||
|
||||
// Handle when both inputs are current system time.
|
||||
@@ -92,7 +92,7 @@ func utimensPortable(path string, times *[2]syscall.Timespec, symlinkFollow bool
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeTimespec(path string, times *[2]syscall.Timespec, i int) (ts syscall.Timespec, err syscall.Errno) { //nolint:unused
|
||||
func normalizeTimespec(path string, times *[2]syscall.Timespec, i int) (ts syscall.Timespec, err experimentalsys.Errno) { //nolint:unused
|
||||
switch times[i].Nsec {
|
||||
case UTIME_NOW: // declined in Go per golang/go#31880.
|
||||
ts = nowTimespec()
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
@@ -15,13 +16,13 @@ import (
|
||||
func TestUtimens(t *testing.T) {
|
||||
t.Run("doesn't exist", func(t *testing.T) {
|
||||
err := Utimens("nope", nil, true)
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
require.EqualErrno(t, sys.ENOENT, err)
|
||||
|
||||
err = Utimens("nope", nil, false)
|
||||
if SupportsSymlinkNoFollow {
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
require.EqualErrno(t, sys.ENOENT, err)
|
||||
} else {
|
||||
require.EqualErrno(t, syscall.ENOSYS, err)
|
||||
require.EqualErrno(t, sys.ENOSYS, err)
|
||||
}
|
||||
})
|
||||
testUtimens(t, false)
|
||||
@@ -154,7 +155,7 @@ func testUtimens(t *testing.T, futimes bool) {
|
||||
if !futimes {
|
||||
err = Utimens(path, tc.times, !symlinkNoFollow)
|
||||
if symlinkNoFollow && !SupportsSymlinkNoFollow {
|
||||
require.EqualErrno(t, syscall.ENOSYS, err)
|
||||
require.EqualErrno(t, sys.ENOSYS, err)
|
||||
return
|
||||
}
|
||||
require.EqualErrno(t, 0, errno)
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
package sysfs
|
||||
|
||||
import "syscall"
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
// Define values even if not used except as sentinels.
|
||||
const (
|
||||
@@ -19,5 +23,5 @@ func futimens(fd uintptr, times *[2]syscall.Timespec) error {
|
||||
// Go exports syscall.Futimes, which is microsecond granularity, and
|
||||
// WASI tests expect nanosecond. We don't yet have a way to invoke the
|
||||
// futimens syscall portably.
|
||||
return syscall.ENOSYS
|
||||
return sys.ENOSYS
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
)
|
||||
|
||||
@@ -22,7 +23,7 @@ func futimens(fd uintptr, times *[2]syscall.Timespec) error {
|
||||
// Before Go 1.20, ERROR_INVALID_HANDLE was returned for too many reasons.
|
||||
// Kick out so that callers can use path-based operations instead.
|
||||
if !platform.IsAtLeastGo120 {
|
||||
return syscall.ENOSYS
|
||||
return sys.ENOSYS
|
||||
}
|
||||
|
||||
// Per docs, zero isn't a valid timestamp as it cannot be differentiated
|
||||
|
||||
@@ -5,17 +5,16 @@ package sysfs
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
// OpenFile is like os.OpenFile except it returns syscall.Errno. A zero
|
||||
// syscall.Errno is success.
|
||||
func openFile(path string, flag int, perm fs.FileMode) (*os.File, syscall.Errno) {
|
||||
// OpenFile is like os.OpenFile except it returns sys.Errno. A zero
|
||||
// sys.Errno is success.
|
||||
func openFile(path string, flag int, perm fs.FileMode) (*os.File, sys.Errno) {
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
// Note: This does not return a fsapi.File because fsapi.FS that returns
|
||||
// one may want to hide the real OS path. For example, this is needed for
|
||||
// pre-opens.
|
||||
return f, platform.UnwrapOSError(err)
|
||||
return f, sys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
@@ -3,13 +3,12 @@ package sysfs
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func openFile(path string, flag int, perm fs.FileMode) (*os.File, syscall.Errno) {
|
||||
func openFile(path string, flag int, perm fs.FileMode) (*os.File, sys.Errno) {
|
||||
flag &= ^(O_DIRECTORY | O_NOFOLLOW) // erase placeholders
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
return f, platform.UnwrapOSError(err)
|
||||
return f, sys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
@@ -5,12 +5,11 @@ package sysfs
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func openFile(path string, flag int, perm fs.FileMode) (*os.File, syscall.Errno) {
|
||||
func openFile(path string, flag int, perm fs.FileMode) (*os.File, sys.Errno) {
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
return f, platform.UnwrapOSError(err)
|
||||
return f, sys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
@@ -47,12 +48,12 @@ func TestOpenFile_Errors(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
_, errno := OpenFile(nestedFile+"/", os.O_RDONLY, 0)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, errno)
|
||||
require.EqualErrno(t, sys.ENOTDIR, errno)
|
||||
})
|
||||
|
||||
t.Run("not found must be ENOENT", func(t *testing.T) {
|
||||
_, errno := OpenFile(path.Join(tmpDir, "not-really-exist.txt"), os.O_RDONLY, 0o600)
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
require.EqualErrno(t, sys.ENOENT, errno)
|
||||
})
|
||||
|
||||
// This is the same as https://github.com/ziglang/zig/blob/d24ebf1d12cf66665b52136a2807f97ff021d78d/lib/std/os/test.zig#L105-L112
|
||||
@@ -63,7 +64,7 @@ func TestOpenFile_Errors(t *testing.T) {
|
||||
defer f.Close()
|
||||
|
||||
_, err := OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o666)
|
||||
require.EqualErrno(t, syscall.EEXIST, err)
|
||||
require.EqualErrno(t, sys.EEXIST, err)
|
||||
})
|
||||
|
||||
t.Run("writing to a read-only file is EBADF", func(t *testing.T) {
|
||||
@@ -74,7 +75,7 @@ func TestOpenFile_Errors(t *testing.T) {
|
||||
defer f.Close()
|
||||
|
||||
_, errno := f.Write([]byte{1, 2, 3, 4})
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
require.EqualErrno(t, sys.EBADF, errno)
|
||||
})
|
||||
|
||||
t.Run("writing to a directory is EISDIR", func(t *testing.T) {
|
||||
@@ -85,7 +86,7 @@ func TestOpenFile_Errors(t *testing.T) {
|
||||
defer f.Close()
|
||||
|
||||
_, errno := f.Write([]byte{1, 2, 3, 4})
|
||||
require.EqualErrno(t, syscall.EISDIR, errno)
|
||||
require.EqualErrno(t, sys.EISDIR, errno)
|
||||
})
|
||||
|
||||
// This is similar to https://github.com/WebAssembly/wasi-testsuite/blob/dc7f8d27be1030cd4788ebdf07d9b57e5d23441e/tests/rust/src/bin/dangling_symlink.rs
|
||||
@@ -97,17 +98,17 @@ func TestOpenFile_Errors(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
_, errno := OpenFile(symlink, fsapi.O_DIRECTORY|fsapi.O_NOFOLLOW, 0o0666)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, errno)
|
||||
require.EqualErrno(t, sys.ENOTDIR, errno)
|
||||
|
||||
_, errno = OpenFile(symlink, fsapi.O_NOFOLLOW, 0o0666)
|
||||
require.EqualErrno(t, syscall.ELOOP, errno)
|
||||
require.EqualErrno(t, sys.ELOOP, errno)
|
||||
})
|
||||
|
||||
t.Run("opening a directory writeable is EISDIR", func(t *testing.T) {
|
||||
_, errno := OpenFile(tmpDir, fsapi.O_DIRECTORY|syscall.O_WRONLY, 0o0666)
|
||||
require.EqualErrno(t, syscall.EISDIR, errno)
|
||||
require.EqualErrno(t, sys.EISDIR, errno)
|
||||
|
||||
_, errno = OpenFile(tmpDir, fsapi.O_DIRECTORY|syscall.O_WRONLY, 0o0666)
|
||||
require.EqualErrno(t, syscall.EISDIR, errno)
|
||||
require.EqualErrno(t, sys.EISDIR, errno)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
)
|
||||
|
||||
func openFile(path string, flag int, perm fs.FileMode) (*os.File, syscall.Errno) {
|
||||
func openFile(path string, flag int, perm fs.FileMode) (*os.File, sys.Errno) {
|
||||
isDir := flag&fsapi.O_DIRECTORY > 0
|
||||
flag &= ^(fsapi.O_DIRECTORY | fsapi.O_NOFOLLOW) // erase placeholders
|
||||
|
||||
@@ -23,31 +24,31 @@ func openFile(path string, flag int, perm fs.FileMode) (*os.File, syscall.Errno)
|
||||
|
||||
// TODO: Set FILE_SHARE_DELETE for directory as well.
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
errno := platform.UnwrapOSError(err)
|
||||
errno := sys.UnwrapOSError(err)
|
||||
if errno == 0 {
|
||||
return f, 0
|
||||
}
|
||||
|
||||
switch errno {
|
||||
case syscall.EINVAL:
|
||||
case sys.EINVAL:
|
||||
// WASI expects ENOTDIR for a file path with a trailing slash.
|
||||
if strings.HasSuffix(path, "/") {
|
||||
errno = syscall.ENOTDIR
|
||||
errno = sys.ENOTDIR
|
||||
}
|
||||
// To match expectations of WASI, e.g. TinyGo TestStatBadDir, return
|
||||
// ENOENT, not ENOTDIR.
|
||||
case syscall.ENOTDIR:
|
||||
errno = syscall.ENOENT
|
||||
case syscall.ENOENT:
|
||||
case sys.ENOTDIR:
|
||||
errno = sys.ENOENT
|
||||
case sys.ENOENT:
|
||||
if isSymlink(path) {
|
||||
// Either symlink or hard link not found. We change the returned
|
||||
// errno depending on if it is symlink or not to have consistent
|
||||
// behavior across OSes.
|
||||
if isDir {
|
||||
// Dangling symlink dir must raise ENOTDIR.
|
||||
errno = syscall.ENOTDIR
|
||||
errno = sys.ENOTDIR
|
||||
} else {
|
||||
errno = syscall.ELOOP
|
||||
errno = sys.ELOOP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+33
-32
@@ -8,6 +8,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
@@ -36,7 +37,7 @@ type osFile struct {
|
||||
// before Readdir.
|
||||
reopenDir bool
|
||||
|
||||
// closed is true when closed was called. This ensures proper syscall.EBADF
|
||||
// closed is true when closed was called. This ensures proper sys.EBADF
|
||||
closed bool
|
||||
|
||||
// cachedStat includes fields that won't change while a file is open.
|
||||
@@ -45,7 +46,7 @@ type osFile struct {
|
||||
|
||||
// cachedStat returns the cacheable parts of fsapi.Stat_t or an error if they
|
||||
// couldn't be retrieved.
|
||||
func (f *osFile) cachedStat() (dev uint64, ino sys.Inode, isDir bool, errno syscall.Errno) {
|
||||
func (f *osFile) cachedStat() (dev uint64, ino sys.Inode, isDir bool, errno experimentalsys.Errno) {
|
||||
if f.cachedSt == nil {
|
||||
if _, errno = f.Stat(); errno != 0 {
|
||||
return
|
||||
@@ -55,19 +56,19 @@ func (f *osFile) cachedStat() (dev uint64, ino sys.Inode, isDir bool, errno sysc
|
||||
}
|
||||
|
||||
// Dev implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Dev() (uint64, syscall.Errno) {
|
||||
func (f *osFile) Dev() (uint64, experimentalsys.Errno) {
|
||||
dev, _, _, errno := f.cachedStat()
|
||||
return dev, errno
|
||||
}
|
||||
|
||||
// Ino implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Ino() (sys.Inode, syscall.Errno) {
|
||||
func (f *osFile) Ino() (sys.Inode, experimentalsys.Errno) {
|
||||
_, ino, _, errno := f.cachedStat()
|
||||
return ino, errno
|
||||
}
|
||||
|
||||
// IsDir implements the same method as documented on fsapi.File
|
||||
func (f *osFile) IsDir() (bool, syscall.Errno) {
|
||||
func (f *osFile) IsDir() (bool, experimentalsys.Errno) {
|
||||
_, _, isDir, errno := f.cachedStat()
|
||||
return isDir, errno
|
||||
}
|
||||
@@ -78,7 +79,7 @@ func (f *osFile) IsAppend() bool {
|
||||
}
|
||||
|
||||
// SetAppend implements the same method as documented on fsapi.File
|
||||
func (f *osFile) SetAppend(enable bool) (errno syscall.Errno) {
|
||||
func (f *osFile) SetAppend(enable bool) (errno experimentalsys.Errno) {
|
||||
if enable {
|
||||
f.flag |= syscall.O_APPEND
|
||||
} else {
|
||||
@@ -96,7 +97,7 @@ func (f *osFile) SetAppend(enable bool) (errno syscall.Errno) {
|
||||
// compile-time check to ensure osFile.reopen implements reopenFile.
|
||||
var _ reopenFile = (*fsFile)(nil).reopen
|
||||
|
||||
func (f *osFile) reopen() (errno syscall.Errno) {
|
||||
func (f *osFile) reopen() (errno experimentalsys.Errno) {
|
||||
// Clear any create flag, as we are re-opening, not re-creating.
|
||||
f.flag &= ^syscall.O_CREAT
|
||||
|
||||
@@ -111,36 +112,36 @@ func (f *osFile) IsNonblock() bool {
|
||||
}
|
||||
|
||||
// SetNonblock implements the same method as documented on fsapi.File
|
||||
func (f *osFile) SetNonblock(enable bool) (errno syscall.Errno) {
|
||||
func (f *osFile) SetNonblock(enable bool) (errno experimentalsys.Errno) {
|
||||
if enable {
|
||||
f.flag |= fsapi.O_NONBLOCK
|
||||
} else {
|
||||
f.flag &= ^fsapi.O_NONBLOCK
|
||||
}
|
||||
if err := setNonblock(f.fd, enable); err != nil {
|
||||
return fileError(f, f.closed, platform.UnwrapOSError(err))
|
||||
return fileError(f, f.closed, experimentalsys.UnwrapOSError(err))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Stat implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Stat() (sys.Stat_t, syscall.Errno) {
|
||||
func (f *osFile) Stat() (sys.Stat_t, experimentalsys.Errno) {
|
||||
if f.closed {
|
||||
return sys.Stat_t{}, syscall.EBADF
|
||||
return sys.Stat_t{}, experimentalsys.EBADF
|
||||
}
|
||||
|
||||
st, errno := statFile(f.file)
|
||||
switch errno {
|
||||
case 0:
|
||||
f.cachedSt = &cachedStat{dev: st.Dev, ino: st.Ino, isDir: st.Mode&fs.ModeDir == fs.ModeDir}
|
||||
case syscall.EIO:
|
||||
errno = syscall.EBADF
|
||||
case experimentalsys.EIO:
|
||||
errno = experimentalsys.EBADF
|
||||
}
|
||||
return st, errno
|
||||
}
|
||||
|
||||
// Read implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Read(buf []byte) (n int, errno syscall.Errno) {
|
||||
func (f *osFile) Read(buf []byte) (n int, errno experimentalsys.Errno) {
|
||||
if len(buf) == 0 {
|
||||
return 0, 0 // Short-circuit 0-len reads.
|
||||
}
|
||||
@@ -157,7 +158,7 @@ func (f *osFile) Read(buf []byte) (n int, errno syscall.Errno) {
|
||||
}
|
||||
|
||||
// Pread implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Pread(buf []byte, off int64) (n int, errno syscall.Errno) {
|
||||
func (f *osFile) Pread(buf []byte, off int64) (n int, errno experimentalsys.Errno) {
|
||||
if n, errno = pread(f.file, buf, off); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
@@ -166,14 +167,14 @@ func (f *osFile) Pread(buf []byte, off int64) (n int, errno syscall.Errno) {
|
||||
}
|
||||
|
||||
// Seek implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Seek(offset int64, whence int) (newOffset int64, errno syscall.Errno) {
|
||||
func (f *osFile) Seek(offset int64, whence int) (newOffset int64, errno experimentalsys.Errno) {
|
||||
if newOffset, errno = seek(f.file, offset, whence); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
|
||||
// If the error was trying to rewind a directory, re-open it. Notably,
|
||||
// seeking to zero on a directory doesn't work on Windows with Go 1.18.
|
||||
if errno == syscall.EISDIR && offset == 0 && whence == io.SeekStart {
|
||||
if errno == experimentalsys.EISDIR && offset == 0 && whence == io.SeekStart {
|
||||
errno = 0
|
||||
f.reopenDir = true
|
||||
}
|
||||
@@ -182,13 +183,13 @@ func (f *osFile) Seek(offset int64, whence int) (newOffset int64, errno syscall.
|
||||
}
|
||||
|
||||
// PollRead implements the same method as documented on fsapi.File
|
||||
func (f *osFile) PollRead(timeout *time.Duration) (ready bool, errno syscall.Errno) {
|
||||
func (f *osFile) PollRead(timeout *time.Duration) (ready bool, errno experimentalsys.Errno) {
|
||||
fdSet := platform.FdSet{}
|
||||
fd := int(f.fd)
|
||||
fdSet.Set(fd)
|
||||
nfds := fd + 1 // See https://man7.org/linux/man-pages/man2/select.2.html#:~:text=condition%20has%20occurred.-,nfds,-This%20argument%20should
|
||||
count, err := _select(nfds, &fdSet, nil, nil, timeout)
|
||||
if errno = platform.UnwrapOSError(err); errno != 0 {
|
||||
if errno = experimentalsys.UnwrapOSError(err); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
}
|
||||
@@ -197,7 +198,7 @@ func (f *osFile) PollRead(timeout *time.Duration) (ready bool, errno syscall.Err
|
||||
|
||||
// Readdir implements File.Readdir. Notably, this uses "Readdir", not
|
||||
// "ReadDir", from os.File.
|
||||
func (f *osFile) Readdir(n int) (dirents []fsapi.Dirent, errno syscall.Errno) {
|
||||
func (f *osFile) Readdir(n int) (dirents []fsapi.Dirent, errno experimentalsys.Errno) {
|
||||
if f.reopenDir { // re-open the directory if needed.
|
||||
f.reopenDir = false
|
||||
if errno = adjustReaddirErr(f, f.closed, f.reopen()); errno != 0 {
|
||||
@@ -212,7 +213,7 @@ func (f *osFile) Readdir(n int) (dirents []fsapi.Dirent, errno syscall.Errno) {
|
||||
}
|
||||
|
||||
// Write implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Write(buf []byte) (n int, errno syscall.Errno) {
|
||||
func (f *osFile) Write(buf []byte) (n int, errno experimentalsys.Errno) {
|
||||
if n, errno = write(f.file, buf); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
@@ -221,7 +222,7 @@ func (f *osFile) Write(buf []byte) (n int, errno syscall.Errno) {
|
||||
}
|
||||
|
||||
// Pwrite implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Pwrite(buf []byte, off int64) (n int, errno syscall.Errno) {
|
||||
func (f *osFile) Pwrite(buf []byte, off int64) (n int, errno experimentalsys.Errno) {
|
||||
if n, errno = pwrite(f.file, buf, off); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
@@ -230,8 +231,8 @@ func (f *osFile) Pwrite(buf []byte, off int64) (n int, errno syscall.Errno) {
|
||||
}
|
||||
|
||||
// Truncate implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Truncate(size int64) (errno syscall.Errno) {
|
||||
if errno = platform.UnwrapOSError(f.file.Truncate(size)); errno != 0 {
|
||||
func (f *osFile) Truncate(size int64) (errno experimentalsys.Errno) {
|
||||
if errno = experimentalsys.UnwrapOSError(f.file.Truncate(size)); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
}
|
||||
@@ -239,27 +240,27 @@ func (f *osFile) Truncate(size int64) (errno syscall.Errno) {
|
||||
}
|
||||
|
||||
// Sync implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Sync() syscall.Errno {
|
||||
func (f *osFile) Sync() experimentalsys.Errno {
|
||||
return fsync(f.file)
|
||||
}
|
||||
|
||||
// Datasync implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Datasync() syscall.Errno {
|
||||
func (f *osFile) Datasync() experimentalsys.Errno {
|
||||
return datasync(f.file)
|
||||
}
|
||||
|
||||
// Utimens implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Utimens(times *[2]syscall.Timespec) syscall.Errno {
|
||||
func (f *osFile) Utimens(times *[2]syscall.Timespec) experimentalsys.Errno {
|
||||
if f.closed {
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
}
|
||||
|
||||
err := futimens(f.fd, times)
|
||||
return platform.UnwrapOSError(err)
|
||||
return experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Close implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Close() syscall.Errno {
|
||||
func (f *osFile) Close() experimentalsys.Errno {
|
||||
if f.closed {
|
||||
return 0
|
||||
}
|
||||
@@ -267,6 +268,6 @@ func (f *osFile) Close() syscall.Errno {
|
||||
return f.close()
|
||||
}
|
||||
|
||||
func (f *osFile) close() syscall.Errno {
|
||||
return platform.UnwrapOSError(f.file.Close())
|
||||
func (f *osFile) close() experimentalsys.Errno {
|
||||
return experimentalsys.UnwrapOSError(f.file.Close())
|
||||
}
|
||||
|
||||
+47
-46
@@ -6,6 +6,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
@@ -28,7 +29,7 @@ type readFS struct {
|
||||
}
|
||||
|
||||
// OpenFile implements the same method as documented on fsapi.FS
|
||||
func (r *readFS) OpenFile(path string, flag int, perm fs.FileMode) (fsapi.File, syscall.Errno) {
|
||||
func (r *readFS) OpenFile(path string, flag int, perm fs.FileMode) (fsapi.File, experimentalsys.Errno) {
|
||||
// TODO: Once the real implementation is complete, move the below to
|
||||
// /RATIONALE.md. Doing this while the type is unstable creates
|
||||
// documentation drift as we expect a lot of reshaping meanwhile.
|
||||
@@ -51,9 +52,9 @@ func (r *readFS) OpenFile(path string, flag int, perm fs.FileMode) (fsapi.File,
|
||||
switch flag & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR) {
|
||||
case os.O_WRONLY, os.O_RDWR:
|
||||
if flag&fsapi.O_DIRECTORY != 0 {
|
||||
return nil, syscall.EISDIR
|
||||
return nil, experimentalsys.EISDIR
|
||||
}
|
||||
return nil, syscall.ENOSYS
|
||||
return nil, experimentalsys.ENOSYS
|
||||
default: // os.O_RDONLY (or no flag) so we are ok!
|
||||
}
|
||||
|
||||
@@ -72,17 +73,17 @@ type readFile struct {
|
||||
}
|
||||
|
||||
// Dev implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Dev() (uint64, syscall.Errno) {
|
||||
func (r *readFile) Dev() (uint64, experimentalsys.Errno) {
|
||||
return r.f.Dev()
|
||||
}
|
||||
|
||||
// Ino implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Ino() (sys.Inode, syscall.Errno) {
|
||||
func (r *readFile) Ino() (sys.Inode, experimentalsys.Errno) {
|
||||
return r.f.Ino()
|
||||
}
|
||||
|
||||
// IsDir implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) IsDir() (bool, syscall.Errno) {
|
||||
func (r *readFile) IsDir() (bool, experimentalsys.Errno) {
|
||||
return r.f.IsDir()
|
||||
}
|
||||
|
||||
@@ -92,7 +93,7 @@ func (r *readFile) IsNonblock() bool {
|
||||
}
|
||||
|
||||
// SetNonblock implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) SetNonblock(enabled bool) syscall.Errno {
|
||||
func (r *readFile) SetNonblock(enabled bool) experimentalsys.Errno {
|
||||
return r.f.SetNonblock(enabled)
|
||||
}
|
||||
|
||||
@@ -102,135 +103,135 @@ func (r *readFile) IsAppend() bool {
|
||||
}
|
||||
|
||||
// SetAppend implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) SetAppend(enabled bool) syscall.Errno {
|
||||
func (r *readFile) SetAppend(enabled bool) experimentalsys.Errno {
|
||||
return r.f.SetAppend(enabled)
|
||||
}
|
||||
|
||||
// Stat implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Stat() (sys.Stat_t, syscall.Errno) {
|
||||
func (r *readFile) Stat() (sys.Stat_t, experimentalsys.Errno) {
|
||||
return r.f.Stat()
|
||||
}
|
||||
|
||||
// Read implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Read(buf []byte) (int, syscall.Errno) {
|
||||
func (r *readFile) Read(buf []byte) (int, experimentalsys.Errno) {
|
||||
return r.f.Read(buf)
|
||||
}
|
||||
|
||||
// Pread implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Pread(buf []byte, offset int64) (int, syscall.Errno) {
|
||||
func (r *readFile) Pread(buf []byte, offset int64) (int, experimentalsys.Errno) {
|
||||
return r.f.Pread(buf, offset)
|
||||
}
|
||||
|
||||
// Seek implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Seek(offset int64, whence int) (int64, syscall.Errno) {
|
||||
func (r *readFile) Seek(offset int64, whence int) (int64, experimentalsys.Errno) {
|
||||
return r.f.Seek(offset, whence)
|
||||
}
|
||||
|
||||
// Readdir implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Readdir(n int) (dirents []fsapi.Dirent, errno syscall.Errno) {
|
||||
func (r *readFile) Readdir(n int) (dirents []fsapi.Dirent, errno experimentalsys.Errno) {
|
||||
return r.f.Readdir(n)
|
||||
}
|
||||
|
||||
// Write implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Write([]byte) (int, syscall.Errno) {
|
||||
func (r *readFile) Write([]byte) (int, experimentalsys.Errno) {
|
||||
return 0, r.writeErr()
|
||||
}
|
||||
|
||||
// Pwrite implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Pwrite([]byte, int64) (n int, errno syscall.Errno) {
|
||||
func (r *readFile) Pwrite([]byte, int64) (n int, errno experimentalsys.Errno) {
|
||||
return 0, r.writeErr()
|
||||
}
|
||||
|
||||
// Truncate implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Truncate(int64) syscall.Errno {
|
||||
func (r *readFile) Truncate(int64) experimentalsys.Errno {
|
||||
return r.writeErr()
|
||||
}
|
||||
|
||||
// Sync implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Sync() syscall.Errno {
|
||||
return syscall.EBADF
|
||||
func (r *readFile) Sync() experimentalsys.Errno {
|
||||
return experimentalsys.EBADF
|
||||
}
|
||||
|
||||
// Datasync implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Datasync() syscall.Errno {
|
||||
return syscall.EBADF
|
||||
func (r *readFile) Datasync() experimentalsys.Errno {
|
||||
return experimentalsys.EBADF
|
||||
}
|
||||
|
||||
// Utimens implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Utimens(*[2]syscall.Timespec) syscall.Errno {
|
||||
return syscall.EBADF
|
||||
func (r *readFile) Utimens(*[2]syscall.Timespec) experimentalsys.Errno {
|
||||
return experimentalsys.EBADF
|
||||
}
|
||||
|
||||
func (r *readFile) writeErr() syscall.Errno {
|
||||
func (r *readFile) writeErr() experimentalsys.Errno {
|
||||
if isDir, errno := r.IsDir(); errno != 0 {
|
||||
return errno
|
||||
} else if isDir {
|
||||
return syscall.EISDIR
|
||||
return experimentalsys.EISDIR
|
||||
}
|
||||
return syscall.EBADF
|
||||
return experimentalsys.EBADF
|
||||
}
|
||||
|
||||
// Close implements the same method as documented on fsapi.File.
|
||||
func (r *readFile) Close() syscall.Errno {
|
||||
func (r *readFile) Close() experimentalsys.Errno {
|
||||
return r.f.Close()
|
||||
}
|
||||
|
||||
// PollRead implements File.PollRead
|
||||
func (r *readFile) PollRead(timeout *time.Duration) (ready bool, errno syscall.Errno) {
|
||||
func (r *readFile) PollRead(timeout *time.Duration) (ready bool, errno experimentalsys.Errno) {
|
||||
return r.f.PollRead(timeout)
|
||||
}
|
||||
|
||||
// Lstat implements the same method as documented on fsapi.FS
|
||||
func (r *readFS) Lstat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func (r *readFS) Lstat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
return r.fs.Lstat(path)
|
||||
}
|
||||
|
||||
// Stat implements the same method as documented on fsapi.FS
|
||||
func (r *readFS) Stat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func (r *readFS) Stat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
return r.fs.Stat(path)
|
||||
}
|
||||
|
||||
// Readlink implements the same method as documented on fsapi.FS
|
||||
func (r *readFS) Readlink(path string) (dst string, err syscall.Errno) {
|
||||
func (r *readFS) Readlink(path string) (dst string, err experimentalsys.Errno) {
|
||||
return r.fs.Readlink(path)
|
||||
}
|
||||
|
||||
// Mkdir implements the same method as documented on fsapi.FS
|
||||
func (r *readFS) Mkdir(path string, perm fs.FileMode) syscall.Errno {
|
||||
return syscall.EROFS
|
||||
func (r *readFS) Mkdir(path string, perm fs.FileMode) experimentalsys.Errno {
|
||||
return experimentalsys.EROFS
|
||||
}
|
||||
|
||||
// Chmod implements the same method as documented on fsapi.FS
|
||||
func (r *readFS) Chmod(path string, perm fs.FileMode) syscall.Errno {
|
||||
return syscall.EROFS
|
||||
func (r *readFS) Chmod(path string, perm fs.FileMode) experimentalsys.Errno {
|
||||
return experimentalsys.EROFS
|
||||
}
|
||||
|
||||
// Rename implements the same method as documented on fsapi.FS
|
||||
func (r *readFS) Rename(from, to string) syscall.Errno {
|
||||
return syscall.EROFS
|
||||
func (r *readFS) Rename(from, to string) experimentalsys.Errno {
|
||||
return experimentalsys.EROFS
|
||||
}
|
||||
|
||||
// Rmdir implements the same method as documented on fsapi.FS
|
||||
func (r *readFS) Rmdir(path string) syscall.Errno {
|
||||
return syscall.EROFS
|
||||
func (r *readFS) Rmdir(path string) experimentalsys.Errno {
|
||||
return experimentalsys.EROFS
|
||||
}
|
||||
|
||||
// Link implements the same method as documented on fsapi.FS
|
||||
func (r *readFS) Link(_, _ string) syscall.Errno {
|
||||
return syscall.EROFS
|
||||
func (r *readFS) Link(_, _ string) experimentalsys.Errno {
|
||||
return experimentalsys.EROFS
|
||||
}
|
||||
|
||||
// Symlink implements the same method as documented on fsapi.FS
|
||||
func (r *readFS) Symlink(_, _ string) syscall.Errno {
|
||||
return syscall.EROFS
|
||||
func (r *readFS) Symlink(_, _ string) experimentalsys.Errno {
|
||||
return experimentalsys.EROFS
|
||||
}
|
||||
|
||||
// Unlink implements the same method as documented on fsapi.FS
|
||||
func (r *readFS) Unlink(path string) syscall.Errno {
|
||||
return syscall.EROFS
|
||||
func (r *readFS) Unlink(path string) experimentalsys.Errno {
|
||||
return experimentalsys.EROFS
|
||||
}
|
||||
|
||||
// Utimens implements the same method as documented on fsapi.FS
|
||||
func (r *readFS) Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) syscall.Errno {
|
||||
return syscall.EROFS
|
||||
func (r *readFS) Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) experimentalsys.Errno {
|
||||
return experimentalsys.EROFS
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/fstest"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
@@ -47,7 +47,7 @@ func TestReadFS_MkDir(t *testing.T) {
|
||||
testFS := NewReadFS(writeable)
|
||||
|
||||
err := testFS.Mkdir("mkdir", fs.ModeDir)
|
||||
require.EqualErrno(t, syscall.EROFS, err)
|
||||
require.EqualErrno(t, sys.EROFS, err)
|
||||
}
|
||||
|
||||
func TestReadFS_Chmod(t *testing.T) {
|
||||
@@ -55,7 +55,7 @@ func TestReadFS_Chmod(t *testing.T) {
|
||||
testFS := NewReadFS(writeable)
|
||||
|
||||
err := testFS.Chmod("chmod", fs.ModeDir)
|
||||
require.EqualErrno(t, syscall.EROFS, err)
|
||||
require.EqualErrno(t, sys.EROFS, err)
|
||||
}
|
||||
|
||||
func TestReadFS_Rename(t *testing.T) {
|
||||
@@ -76,7 +76,7 @@ func TestReadFS_Rename(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testFS.Rename(file1, file2)
|
||||
require.EqualErrno(t, syscall.EROFS, err)
|
||||
require.EqualErrno(t, sys.EROFS, err)
|
||||
}
|
||||
|
||||
func TestReadFS_Rmdir(t *testing.T) {
|
||||
@@ -89,7 +89,7 @@ func TestReadFS_Rmdir(t *testing.T) {
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
|
||||
err := testFS.Rmdir(path)
|
||||
require.EqualErrno(t, syscall.EROFS, err)
|
||||
require.EqualErrno(t, sys.EROFS, err)
|
||||
}
|
||||
|
||||
func TestReadFS_Unlink(t *testing.T) {
|
||||
@@ -102,7 +102,7 @@ func TestReadFS_Unlink(t *testing.T) {
|
||||
require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600))
|
||||
|
||||
err := testFS.Unlink(path)
|
||||
require.EqualErrno(t, syscall.EROFS, err)
|
||||
require.EqualErrno(t, sys.EROFS, err)
|
||||
}
|
||||
|
||||
func TestReadFS_UtimesNano(t *testing.T) {
|
||||
@@ -115,7 +115,7 @@ func TestReadFS_UtimesNano(t *testing.T) {
|
||||
require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600))
|
||||
|
||||
err := testFS.Utimens(path, nil, true)
|
||||
require.EqualErrno(t, syscall.EROFS, err)
|
||||
require.EqualErrno(t, sys.EROFS, err)
|
||||
}
|
||||
|
||||
func TestReadFS_Open_Read(t *testing.T) {
|
||||
|
||||
@@ -5,12 +5,12 @@ package sysfs
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func rename(from, to string) syscall.Errno {
|
||||
func rename(from, to string) sys.Errno {
|
||||
if from == to {
|
||||
return 0
|
||||
}
|
||||
return platform.UnwrapOSError(syscall.Rename(from, to))
|
||||
return sys.UnwrapOSError(syscall.Rename(from, to))
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package sysfs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
|
||||
@@ -20,7 +18,7 @@ func TestRename(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
err = rename(path.Join(tmpDir, "non-exist"), file1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
require.EqualErrno(t, sys.ENOENT, err)
|
||||
})
|
||||
t.Run("file to non-exist", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
@@ -36,7 +34,7 @@ func TestRename(t *testing.T) {
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err = os.Stat(file1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, errors.Unwrap(err))
|
||||
require.EqualErrno(t, sys.ENOENT, sys.UnwrapOSError(err))
|
||||
|
||||
s, err := os.Stat(file2Path)
|
||||
require.NoError(t, err)
|
||||
@@ -54,7 +52,7 @@ func TestRename(t *testing.T) {
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err := os.Stat(dir1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, platform.UnwrapOSError(err))
|
||||
require.EqualErrno(t, sys.ENOENT, sys.UnwrapOSError(err))
|
||||
|
||||
s, err := os.Stat(dir2Path)
|
||||
require.NoError(t, err)
|
||||
@@ -73,7 +71,7 @@ func TestRename(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
err = rename(dir1Path, dir2Path)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, err)
|
||||
require.EqualErrno(t, sys.ENOTDIR, err)
|
||||
})
|
||||
t.Run("file to dir", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
@@ -87,7 +85,7 @@ func TestRename(t *testing.T) {
|
||||
require.NoError(t, os.Mkdir(dir1Path, 0o700))
|
||||
|
||||
err = rename(file1Path, dir1Path)
|
||||
require.EqualErrno(t, syscall.EISDIR, err)
|
||||
require.EqualErrno(t, sys.EISDIR, err)
|
||||
})
|
||||
|
||||
// Similar to https://github.com/ziglang/zig/blob/0.10.1/lib/std/fs/test.zig#L567-L582
|
||||
@@ -113,7 +111,7 @@ func TestRename(t *testing.T) {
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err = os.Stat(dir1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, errors.Unwrap(err))
|
||||
require.EqualErrno(t, sys.ENOENT, sys.UnwrapOSError(err))
|
||||
|
||||
// Show the file inside that directory moved
|
||||
s, err := os.Stat(path.Join(dir2Path, file1))
|
||||
@@ -143,7 +141,7 @@ func TestRename(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
err = rename(dir1Path, dir2Path)
|
||||
require.EqualErrno(t, syscall.ENOTEMPTY, err)
|
||||
require.EqualErrno(t, sys.ENOTEMPTY, err)
|
||||
})
|
||||
|
||||
t.Run("file to file", func(t *testing.T) {
|
||||
@@ -164,7 +162,7 @@ func TestRename(t *testing.T) {
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err = os.Stat(file1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, errors.Unwrap(err))
|
||||
require.EqualErrno(t, sys.ENOENT, sys.UnwrapOSError(err))
|
||||
|
||||
// Show the file1 overwrote file2
|
||||
b, err := os.ReadFile(file2Path)
|
||||
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func rename(from, to string) syscall.Errno {
|
||||
func rename(from, to string) sys.Errno {
|
||||
if from == to {
|
||||
return 0
|
||||
}
|
||||
@@ -18,7 +18,7 @@ func rename(from, to string) syscall.Errno {
|
||||
} else {
|
||||
fromIsDir = fromStat.Mode.IsDir()
|
||||
}
|
||||
if toStat, errno := stat(to); errno == syscall.ENOENT {
|
||||
if toStat, errno := stat(to); errno == sys.ENOENT {
|
||||
return syscallRename(from, to) // file or dir to not-exist is ok
|
||||
} else if errno != 0 {
|
||||
return errno // failed to stat to
|
||||
@@ -29,20 +29,20 @@ func rename(from, to string) syscall.Errno {
|
||||
// Now, handle known cases
|
||||
switch {
|
||||
case !fromIsDir && toIsDir: // file to dir
|
||||
return syscall.EISDIR
|
||||
return sys.EISDIR
|
||||
case !fromIsDir && !toIsDir: // file to file
|
||||
// Use os.Rename instead of syscall.Rename to overwrite a file.
|
||||
// This uses MoveFileEx instead of MoveFile (used by syscall.Rename).
|
||||
return platform.UnwrapOSError(os.Rename(from, to))
|
||||
return sys.UnwrapOSError(os.Rename(from, to))
|
||||
case fromIsDir && !toIsDir: // dir to file
|
||||
return syscall.ENOTDIR
|
||||
return sys.ENOTDIR
|
||||
default: // dir to dir
|
||||
|
||||
// We can't tell if a directory is empty or not, via stat information.
|
||||
// Reading the directory is expensive, as it can buffer large amounts
|
||||
// of data on fail. Instead, speculatively try to remove the directory.
|
||||
// This is only one syscall and won't buffer anything.
|
||||
if errno := rmdir(to); errno == 0 || errno == syscall.ENOENT {
|
||||
if errno := rmdir(to); errno == 0 || errno == sys.ENOENT {
|
||||
return syscallRename(from, to)
|
||||
} else {
|
||||
return errno
|
||||
@@ -50,6 +50,6 @@ func rename(from, to string) syscall.Errno {
|
||||
}
|
||||
}
|
||||
|
||||
func syscallRename(from string, to string) syscall.Errno {
|
||||
return platform.UnwrapOSError(syscall.Rename(from, to))
|
||||
func syscallRename(from string, to string) sys.Errno {
|
||||
return sys.UnwrapOSError(syscall.Rename(from, to))
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ package sysfs
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
@@ -16,7 +16,7 @@ func TestSelect(t *testing.T) {
|
||||
for {
|
||||
dur := time.Duration(0)
|
||||
n, err := _select(0, nil, nil, nil, &dur)
|
||||
if err == syscall.EINTR {
|
||||
if err == sys.EINTR {
|
||||
t.Logf("Select interrupted")
|
||||
continue
|
||||
}
|
||||
@@ -36,7 +36,7 @@ func TestSelect(t *testing.T) {
|
||||
start := time.Now()
|
||||
n, err := _select(0, nil, nil, nil, &dur)
|
||||
took = time.Since(start)
|
||||
if err == syscall.EINTR {
|
||||
if err == sys.EINTR {
|
||||
t.Logf("Select interrupted after %v", took)
|
||||
continue
|
||||
}
|
||||
@@ -77,11 +77,11 @@ func TestSelect(t *testing.T) {
|
||||
n, err := _select(fd+1, rFdSet, nil, nil, nil)
|
||||
if runtime.GOOS == "windows" {
|
||||
// Not implemented for fds != wasiFdStdin
|
||||
require.ErrorIs(t, err, syscall.ENOSYS)
|
||||
require.ErrorIs(t, err, sys.ENOSYS)
|
||||
require.Equal(t, -1, n)
|
||||
break
|
||||
}
|
||||
if err == syscall.EINTR {
|
||||
if err == sys.EINTR {
|
||||
t.Log("Select interrupted")
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
package sysfs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
)
|
||||
|
||||
func syscall_select(n int, r, w, e *platform.FdSet, timeout *time.Duration) (int, error) {
|
||||
return -1, syscall.ENOSYS
|
||||
return -1, sys.ENOSYS
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
)
|
||||
|
||||
@@ -15,12 +16,12 @@ const wasiFdStdin = 0
|
||||
// pollInterval is the interval between each calls to peekNamedPipe in pollNamedPipe
|
||||
const pollInterval = 100 * time.Millisecond
|
||||
|
||||
// syscall_select emulates the select syscall on Windows for two, well-known cases, returns syscall.ENOSYS for all others.
|
||||
// syscall_select emulates the select syscall on Windows for two, well-known cases, returns sys.ENOSYS for all others.
|
||||
// If r contains fd 0, and it is a regular file, then it immediately returns 1 (data ready on stdin)
|
||||
// and r will have the fd 0 bit set.
|
||||
// If r contains fd 0, and it is a FILE_TYPE_CHAR, then it invokes PeekNamedPipe to check the buffer for input;
|
||||
// if there is data ready, then it returns 1 and r will have fd 0 bit set.
|
||||
// If n==0 it will wait for the given timeout duration, but it will return syscall.ENOSYS if timeout is nil,
|
||||
// If n==0 it will wait for the given timeout duration, but it will return sys.ENOSYS if timeout is nil,
|
||||
// i.e. it won't block indefinitely.
|
||||
//
|
||||
// Note: idea taken from https://stackoverflow.com/questions/6839508/test-if-stdin-has-input-for-c-windows-and-or-linux
|
||||
@@ -31,7 +32,7 @@ func syscall_select(n int, r, w, e *platform.FdSet, timeout *time.Duration) (int
|
||||
if n == 0 {
|
||||
// Don't block indefinitely.
|
||||
if timeout == nil {
|
||||
return -1, syscall.ENOSYS
|
||||
return -1, sys.ENOSYS
|
||||
}
|
||||
time.Sleep(*timeout)
|
||||
return 0, nil
|
||||
@@ -55,7 +56,7 @@ func syscall_select(n int, r, w, e *platform.FdSet, timeout *time.Duration) (int
|
||||
r.Set(wasiFdStdin)
|
||||
return 1, nil
|
||||
}
|
||||
return -1, syscall.ENOSYS
|
||||
return -1, sys.ENOSYS
|
||||
}
|
||||
|
||||
// pollNamedPipe polls the given named pipe handle for the given duration.
|
||||
|
||||
@@ -3,8 +3,8 @@ package sysfs
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
socketapi "github.com/tetratelabs/wazero/internal/sock"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
@@ -24,14 +24,14 @@ type baseSockFile struct {
|
||||
var _ fsapi.File = (*baseSockFile)(nil)
|
||||
|
||||
// IsDir implements the same method as documented on File.IsDir
|
||||
func (*baseSockFile) IsDir() (bool, syscall.Errno) {
|
||||
func (*baseSockFile) IsDir() (bool, experimentalsys.Errno) {
|
||||
// We need to override this method because WASI-libc prestats the FD
|
||||
// and the default impl returns ENOSYS otherwise.
|
||||
return false, 0
|
||||
}
|
||||
|
||||
// Stat implements the same method as documented on File.Stat
|
||||
func (f *baseSockFile) Stat() (fs sys.Stat_t, errno syscall.Errno) {
|
||||
func (f *baseSockFile) Stat() (fs sys.Stat_t, errno experimentalsys.Errno) {
|
||||
// The mode is not really important, but it should be neither a regular file nor a directory.
|
||||
fs.Mode = os.ModeIrregular
|
||||
return
|
||||
|
||||
@@ -2,10 +2,10 @@ package sysfs
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
|
||||
@@ -21,12 +21,12 @@ func TestTcpConnFile_Write(t *testing.T) {
|
||||
defer tcp.Close() //nolint
|
||||
|
||||
file := newTcpConn(tcp)
|
||||
errno := syscall.Errno(0)
|
||||
errno := sys.Errno(0)
|
||||
// Ensure we don't interrupt until we get a non-zero errno,
|
||||
// and we retry on EAGAIN (i.e. when nonblocking is true).
|
||||
for {
|
||||
_, errno = file.Write([]byte("wazero"))
|
||||
if errno != syscall.EAGAIN {
|
||||
if errno != sys.EAGAIN {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
@@ -68,13 +68,13 @@ func TestTcpConnFile_Read(t *testing.T) {
|
||||
bytes := make([]byte, 4)
|
||||
|
||||
require.NoError(t, err)
|
||||
errno := syscall.Errno(0)
|
||||
errno := sys.Errno(0)
|
||||
file := newTcpConn(conn.(*net.TCPConn))
|
||||
// Ensure we don't interrupt until we get a non-zero errno,
|
||||
// and we retry on EAGAIN (i.e. when nonblocking is true).
|
||||
for {
|
||||
_, errno = file.Read(bytes)
|
||||
if errno != syscall.EAGAIN {
|
||||
if errno != sys.EAGAIN {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
+23
-23
@@ -6,7 +6,7 @@ import (
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
socketapi "github.com/tetratelabs/wazero/internal/sock"
|
||||
)
|
||||
|
||||
@@ -46,9 +46,9 @@ type tcpListenerFile struct {
|
||||
}
|
||||
|
||||
// Accept implements the same method as documented on socketapi.TCPSock
|
||||
func (f *tcpListenerFile) Accept() (socketapi.TCPConn, syscall.Errno) {
|
||||
func (f *tcpListenerFile) Accept() (socketapi.TCPConn, sys.Errno) {
|
||||
nfd, _, err := syscall.Accept(int(f.fd))
|
||||
errno := platform.UnwrapOSError(err)
|
||||
errno := sys.UnwrapOSError(err)
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
}
|
||||
@@ -56,13 +56,13 @@ func (f *tcpListenerFile) Accept() (socketapi.TCPConn, syscall.Errno) {
|
||||
}
|
||||
|
||||
// SetNonblock implements the same method as documented on fsapi.File
|
||||
func (f *tcpListenerFile) SetNonblock(enabled bool) syscall.Errno {
|
||||
return platform.UnwrapOSError(setNonblock(f.fd, enabled))
|
||||
func (f *tcpListenerFile) SetNonblock(enabled bool) sys.Errno {
|
||||
return sys.UnwrapOSError(setNonblock(f.fd, enabled))
|
||||
}
|
||||
|
||||
// Close implements the same method as documented on fsapi.File
|
||||
func (f *tcpListenerFile) Close() syscall.Errno {
|
||||
return platform.UnwrapOSError(syscall.Close(int(f.fd)))
|
||||
func (f *tcpListenerFile) Close() sys.Errno {
|
||||
return sys.UnwrapOSError(syscall.Close(int(f.fd)))
|
||||
}
|
||||
|
||||
// Addr is exposed for testing.
|
||||
@@ -77,7 +77,7 @@ type tcpConnFile struct {
|
||||
|
||||
fd uintptr
|
||||
|
||||
// closed is true when closed was called. This ensures proper syscall.EBADF
|
||||
// closed is true when closed was called. This ensures proper sys.EBADF
|
||||
closed bool
|
||||
}
|
||||
|
||||
@@ -90,45 +90,45 @@ func newTcpConn(tc *net.TCPConn) socketapi.TCPConn {
|
||||
}
|
||||
|
||||
// SetNonblock implements the same method as documented on fsapi.File
|
||||
func (f *tcpConnFile) SetNonblock(enabled bool) (errno syscall.Errno) {
|
||||
return platform.UnwrapOSError(setNonblock(f.fd, enabled))
|
||||
func (f *tcpConnFile) SetNonblock(enabled bool) (errno sys.Errno) {
|
||||
return sys.UnwrapOSError(setNonblock(f.fd, enabled))
|
||||
}
|
||||
|
||||
// Read implements the same method as documented on fsapi.File
|
||||
func (f *tcpConnFile) Read(buf []byte) (n int, errno syscall.Errno) {
|
||||
func (f *tcpConnFile) Read(buf []byte) (n int, errno sys.Errno) {
|
||||
n, err := syscall.Read(int(f.fd), buf)
|
||||
if err != nil {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = platform.UnwrapOSError(err)
|
||||
errno = sys.UnwrapOSError(err)
|
||||
errno = fileError(f, f.closed, errno)
|
||||
}
|
||||
return n, errno
|
||||
}
|
||||
|
||||
// Write implements the same method as documented on fsapi.File
|
||||
func (f *tcpConnFile) Write(buf []byte) (n int, errno syscall.Errno) {
|
||||
func (f *tcpConnFile) Write(buf []byte) (n int, errno sys.Errno) {
|
||||
n, err := syscall.Write(int(f.fd), buf)
|
||||
if err != nil {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = platform.UnwrapOSError(err)
|
||||
errno = sys.UnwrapOSError(err)
|
||||
errno = fileError(f, f.closed, errno)
|
||||
}
|
||||
return n, errno
|
||||
}
|
||||
|
||||
// Recvfrom implements the same method as documented on socketapi.TCPConn
|
||||
func (f *tcpConnFile) Recvfrom(p []byte, flags int) (n int, errno syscall.Errno) {
|
||||
func (f *tcpConnFile) Recvfrom(p []byte, flags int) (n int, errno sys.Errno) {
|
||||
if flags != MSG_PEEK {
|
||||
errno = syscall.EINVAL
|
||||
errno = sys.EINVAL
|
||||
return
|
||||
}
|
||||
n, _, recvfromErr := syscall.Recvfrom(int(f.fd), p, MSG_PEEK)
|
||||
errno = platform.UnwrapOSError(recvfromErr)
|
||||
errno = sys.UnwrapOSError(recvfromErr)
|
||||
return n, errno
|
||||
}
|
||||
|
||||
// Shutdown implements the same method as documented on fsapi.Conn
|
||||
func (f *tcpConnFile) Shutdown(how int) syscall.Errno {
|
||||
func (f *tcpConnFile) Shutdown(how int) sys.Errno {
|
||||
var err error
|
||||
switch how {
|
||||
case syscall.SHUT_RD, syscall.SHUT_WR:
|
||||
@@ -136,20 +136,20 @@ func (f *tcpConnFile) Shutdown(how int) syscall.Errno {
|
||||
case syscall.SHUT_RDWR:
|
||||
return f.close()
|
||||
default:
|
||||
return syscall.EINVAL
|
||||
return sys.EINVAL
|
||||
}
|
||||
return platform.UnwrapOSError(err)
|
||||
return sys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Close implements the same method as documented on fsapi.File
|
||||
func (f *tcpConnFile) Close() syscall.Errno {
|
||||
func (f *tcpConnFile) Close() sys.Errno {
|
||||
return f.close()
|
||||
}
|
||||
|
||||
func (f *tcpConnFile) close() syscall.Errno {
|
||||
func (f *tcpConnFile) close() sys.Errno {
|
||||
if f.closed {
|
||||
return 0
|
||||
}
|
||||
f.closed = true
|
||||
return platform.UnwrapOSError(syscall.Shutdown(int(f.fd), syscall.SHUT_RDWR))
|
||||
return sys.UnwrapOSError(syscall.Shutdown(int(f.fd), syscall.SHUT_RDWR))
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ package sysfs
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
socketapi "github.com/tetratelabs/wazero/internal/sock"
|
||||
)
|
||||
|
||||
@@ -21,6 +21,6 @@ type unsupportedSockFile struct {
|
||||
}
|
||||
|
||||
// Accept implements the same method as documented on socketapi.TCPSock
|
||||
func (f *unsupportedSockFile) Accept() (socketapi.TCPConn, syscall.Errno) {
|
||||
return nil, syscall.ENOSYS
|
||||
func (f *unsupportedSockFile) Accept() (socketapi.TCPConn, sys.Errno) {
|
||||
return nil, sys.ENOSYS
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
socketapi "github.com/tetratelabs/wazero/internal/sock"
|
||||
)
|
||||
|
||||
@@ -65,22 +65,22 @@ type winTcpListenerFile struct {
|
||||
}
|
||||
|
||||
// Accept implements the same method as documented on socketapi.TCPSock
|
||||
func (f *winTcpListenerFile) Accept() (socketapi.TCPConn, syscall.Errno) {
|
||||
func (f *winTcpListenerFile) Accept() (socketapi.TCPConn, sys.Errno) {
|
||||
conn, err := f.tl.Accept()
|
||||
if err != nil {
|
||||
return nil, platform.UnwrapOSError(err)
|
||||
return nil, sys.UnwrapOSError(err)
|
||||
}
|
||||
return &winTcpConnFile{tc: conn.(*net.TCPConn)}, 0
|
||||
}
|
||||
|
||||
// SetNonblock implements the same method as documented on fsapi.File
|
||||
func (f *winTcpListenerFile) SetNonblock(enabled bool) syscall.Errno {
|
||||
func (f *winTcpListenerFile) SetNonblock(enabled bool) sys.Errno {
|
||||
return 0 // setNonblock() is a no-op on Windows
|
||||
}
|
||||
|
||||
// Close implements the same method as documented on fsapi.File
|
||||
func (f *winTcpListenerFile) Close() syscall.Errno {
|
||||
return platform.UnwrapOSError(f.tl.Close())
|
||||
func (f *winTcpListenerFile) Close() sys.Errno {
|
||||
return sys.UnwrapOSError(f.tl.Close())
|
||||
}
|
||||
|
||||
// Addr is exposed for testing.
|
||||
@@ -95,7 +95,7 @@ type winTcpConnFile struct {
|
||||
|
||||
tc *net.TCPConn
|
||||
|
||||
// closed is true when closed was called. This ensures proper syscall.EBADF
|
||||
// closed is true when closed was called. This ensures proper sys.EBADF
|
||||
closed bool
|
||||
}
|
||||
|
||||
@@ -104,23 +104,23 @@ func newTcpConn(tc *net.TCPConn) socketapi.TCPConn {
|
||||
}
|
||||
|
||||
// SetNonblock implements the same method as documented on fsapi.File
|
||||
func (f *winTcpConnFile) SetNonblock(enabled bool) (errno syscall.Errno) {
|
||||
func (f *winTcpConnFile) SetNonblock(enabled bool) (errno sys.Errno) {
|
||||
syscallConn, err := f.tc.SyscallConn()
|
||||
if err != nil {
|
||||
return platform.UnwrapOSError(err)
|
||||
return sys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Prioritize the error from setNonblock over Control
|
||||
if controlErr := syscallConn.Control(func(fd uintptr) {
|
||||
errno = platform.UnwrapOSError(setNonblock(fd, enabled))
|
||||
errno = sys.UnwrapOSError(setNonblock(fd, enabled))
|
||||
}); errno == 0 {
|
||||
errno = platform.UnwrapOSError(controlErr)
|
||||
errno = sys.UnwrapOSError(controlErr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Read implements the same method as documented on fsapi.File
|
||||
func (f *winTcpConnFile) Read(buf []byte) (n int, errno syscall.Errno) {
|
||||
func (f *winTcpConnFile) Read(buf []byte) (n int, errno sys.Errno) {
|
||||
if n, errno = read(f.tc, buf); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
@@ -129,7 +129,7 @@ func (f *winTcpConnFile) Read(buf []byte) (n int, errno syscall.Errno) {
|
||||
}
|
||||
|
||||
// Write implements the same method as documented on fsapi.File
|
||||
func (f *winTcpConnFile) Write(buf []byte) (n int, errno syscall.Errno) {
|
||||
func (f *winTcpConnFile) Write(buf []byte) (n int, errno sys.Errno) {
|
||||
if n, errno = write(f.tc, buf); errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
@@ -138,15 +138,15 @@ func (f *winTcpConnFile) Write(buf []byte) (n int, errno syscall.Errno) {
|
||||
}
|
||||
|
||||
// Recvfrom implements the same method as documented on socketapi.TCPConn
|
||||
func (f *winTcpConnFile) Recvfrom(p []byte, flags int) (n int, errno syscall.Errno) {
|
||||
func (f *winTcpConnFile) Recvfrom(p []byte, flags int) (n int, errno sys.Errno) {
|
||||
if flags != MSG_PEEK {
|
||||
errno = syscall.EINVAL
|
||||
errno = sys.EINVAL
|
||||
return
|
||||
}
|
||||
conn := f.tc
|
||||
syscallConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
errno = platform.UnwrapOSError(err)
|
||||
errno = sys.UnwrapOSError(err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -154,15 +154,15 @@ func (f *winTcpConnFile) Recvfrom(p []byte, flags int) (n int, errno syscall.Err
|
||||
if controlErr := syscallConn.Control(func(fd uintptr) {
|
||||
var recvfromErr error
|
||||
n, recvfromErr = recvfrom(syscall.Handle(fd), p, MSG_PEEK)
|
||||
errno = platform.UnwrapOSError(recvfromErr)
|
||||
errno = sys.UnwrapOSError(recvfromErr)
|
||||
}); errno == 0 {
|
||||
errno = platform.UnwrapOSError(controlErr)
|
||||
errno = sys.UnwrapOSError(controlErr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Shutdown implements the same method as documented on fsapi.Conn
|
||||
func (f *winTcpConnFile) Shutdown(how int) syscall.Errno {
|
||||
func (f *winTcpConnFile) Shutdown(how int) sys.Errno {
|
||||
// FIXME: can userland shutdown listeners?
|
||||
var err error
|
||||
switch how {
|
||||
@@ -173,17 +173,17 @@ func (f *winTcpConnFile) Shutdown(how int) syscall.Errno {
|
||||
case syscall.SHUT_RDWR:
|
||||
return f.close()
|
||||
default:
|
||||
return syscall.EINVAL
|
||||
return sys.EINVAL
|
||||
}
|
||||
return platform.UnwrapOSError(err)
|
||||
return sys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Close implements the same method as documented on fsapi.File
|
||||
func (f *winTcpConnFile) Close() syscall.Errno {
|
||||
func (f *winTcpConnFile) Close() sys.Errno {
|
||||
return f.close()
|
||||
}
|
||||
|
||||
func (f *winTcpConnFile) close() syscall.Errno {
|
||||
func (f *winTcpConnFile) close() sys.Errno {
|
||||
if f.closed {
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -2,15 +2,14 @@ package sysfs
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
func defaultStatFile(f fs.File) (sys.Stat_t, syscall.Errno) {
|
||||
func defaultStatFile(f fs.File) (sys.Stat_t, experimentalsys.Errno) {
|
||||
if info, err := f.Stat(); err != nil {
|
||||
return sys.Stat_t{}, platform.UnwrapOSError(err)
|
||||
return sys.Stat_t{}, experimentalsys.UnwrapOSError(err)
|
||||
} else {
|
||||
return sys.NewStat_t(info), 0
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
@@ -17,27 +17,27 @@ import (
|
||||
// Note: this is only used in tests
|
||||
const dirNlinkIncludesDot = true
|
||||
|
||||
func lstat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func lstat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
if info, err := os.Lstat(path); err != nil {
|
||||
return sys.Stat_t{}, platform.UnwrapOSError(err)
|
||||
return sys.Stat_t{}, experimentalsys.UnwrapOSError(err)
|
||||
} else {
|
||||
return sys.NewStat_t(info), 0
|
||||
}
|
||||
}
|
||||
|
||||
func stat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func stat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
if info, err := os.Stat(path); err != nil {
|
||||
return sys.Stat_t{}, platform.UnwrapOSError(err)
|
||||
return sys.Stat_t{}, experimentalsys.UnwrapOSError(err)
|
||||
} else {
|
||||
return sys.NewStat_t(info), 0
|
||||
}
|
||||
}
|
||||
|
||||
func statFile(f fs.File) (sys.Stat_t, syscall.Errno) {
|
||||
func statFile(f fs.File) (sys.Stat_t, experimentalsys.Errno) {
|
||||
return defaultStatFile(f)
|
||||
}
|
||||
|
||||
func inoFromFileInfo(_ string, info fs.FileInfo) (sys.Inode, syscall.Errno) {
|
||||
func inoFromFileInfo(_ string, info fs.FileInfo) (sys.Inode, experimentalsys.Errno) {
|
||||
switch v := info.Sys().(type) {
|
||||
case *sys.Stat_t:
|
||||
return v.Ino, 0
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
@@ -20,27 +20,27 @@ import (
|
||||
// Note: this is only used in tests
|
||||
const dirNlinkIncludesDot = true
|
||||
|
||||
func lstat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func lstat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
if info, err := os.Lstat(path); err != nil {
|
||||
return sys.Stat_t{}, platform.UnwrapOSError(err)
|
||||
return sys.Stat_t{}, experimentalsys.UnwrapOSError(err)
|
||||
} else {
|
||||
return sys.NewStat_t(info), 0
|
||||
}
|
||||
}
|
||||
|
||||
func stat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func stat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
if info, err := os.Stat(path); err != nil {
|
||||
return sys.Stat_t{}, platform.UnwrapOSError(err)
|
||||
return sys.Stat_t{}, experimentalsys.UnwrapOSError(err)
|
||||
} else {
|
||||
return sys.NewStat_t(info), 0
|
||||
}
|
||||
}
|
||||
|
||||
func statFile(f fs.File) (sys.Stat_t, syscall.Errno) {
|
||||
func statFile(f fs.File) (sys.Stat_t, experimentalsys.Errno) {
|
||||
return defaultStatFile(f)
|
||||
}
|
||||
|
||||
func inoFromFileInfo(_ string, info fs.FileInfo) (sys.Inode, syscall.Errno) {
|
||||
func inoFromFileInfo(_ string, info fs.FileInfo) (sys.Inode, experimentalsys.Errno) {
|
||||
switch v := info.Sys().(type) {
|
||||
case *sys.Stat_t:
|
||||
return v.Ino, 0
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
@@ -17,9 +18,9 @@ func TestStat(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
_, errno := stat(path.Join(tmpDir, "cat"))
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
require.EqualErrno(t, experimentalsys.ENOENT, errno)
|
||||
_, errno = stat(path.Join(tmpDir, "sub/cat"))
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
require.EqualErrno(t, experimentalsys.ENOENT, errno)
|
||||
|
||||
var st sys.Stat_t
|
||||
|
||||
@@ -120,7 +121,7 @@ func TestStatFile(t *testing.T) {
|
||||
t.Run("closed dir", func(t *testing.T) {
|
||||
require.EqualErrno(t, 0, tmpDirF.Close())
|
||||
_, errno := tmpDirF.Stat()
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
require.EqualErrno(t, experimentalsys.EBADF, errno)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -140,7 +141,7 @@ func TestStatFile(t *testing.T) {
|
||||
t.Run("closed fsFile", func(t *testing.T) {
|
||||
require.EqualErrno(t, 0, fileF.Close())
|
||||
_, errno := fileF.Stat()
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
require.EqualErrno(t, experimentalsys.EBADF, errno)
|
||||
})
|
||||
|
||||
subdir := path.Join(tmpDir, "sub")
|
||||
@@ -159,7 +160,7 @@ func TestStatFile(t *testing.T) {
|
||||
t.Run("closed subdir", func(t *testing.T) {
|
||||
require.EqualErrno(t, 0, subdirF.Close())
|
||||
_, errno := subdirF.Stat()
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
require.EqualErrno(t, experimentalsys.EBADF, errno)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
@@ -20,27 +20,27 @@ import (
|
||||
// Note: this is only used in tests
|
||||
const dirNlinkIncludesDot = false
|
||||
|
||||
func lstat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func lstat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
if info, err := os.Lstat(path); err != nil {
|
||||
return sys.Stat_t{}, platform.UnwrapOSError(err)
|
||||
return sys.Stat_t{}, experimentalsys.UnwrapOSError(err)
|
||||
} else {
|
||||
return sys.NewStat_t(info), 0
|
||||
}
|
||||
}
|
||||
|
||||
func stat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func stat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
if info, err := os.Stat(path); err != nil {
|
||||
return sys.Stat_t{}, platform.UnwrapOSError(err)
|
||||
return sys.Stat_t{}, experimentalsys.UnwrapOSError(err)
|
||||
} else {
|
||||
return sys.NewStat_t(info), 0
|
||||
}
|
||||
}
|
||||
|
||||
func statFile(f fs.File) (sys.Stat_t, syscall.Errno) {
|
||||
func statFile(f fs.File) (sys.Stat_t, experimentalsys.Errno) {
|
||||
return defaultStatFile(f)
|
||||
}
|
||||
|
||||
func inoFromFileInfo(_ string, info fs.FileInfo) (sys.Inode, syscall.Errno) {
|
||||
func inoFromFileInfo(_ string, info fs.FileInfo) (sys.Inode, experimentalsys.Errno) {
|
||||
if st, ok := info.Sys().(*syscall.Stat_t); ok {
|
||||
return st.Ino, 0
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"path"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
// Note: this is only used in tests
|
||||
const dirNlinkIncludesDot = false
|
||||
|
||||
func lstat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func lstat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
|
||||
// Use FILE_FLAG_OPEN_REPARSE_POINT, otherwise CreateFile will follow symlink.
|
||||
// See https://docs.microsoft.com/en-us/windows/desktop/FileIO/symbolic-link-effects-on-file-systems-functions#createfile-and-createfiletransacted
|
||||
@@ -24,30 +24,31 @@ func lstat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
return statPath(attrs, path)
|
||||
}
|
||||
|
||||
func stat(path string) (sys.Stat_t, syscall.Errno) {
|
||||
func stat(path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
|
||||
return statPath(attrs, path)
|
||||
}
|
||||
|
||||
func statPath(createFileAttrs uint32, path string) (sys.Stat_t, syscall.Errno) {
|
||||
func statPath(createFileAttrs uint32, path string) (sys.Stat_t, experimentalsys.Errno) {
|
||||
if len(path) == 0 {
|
||||
return sys.Stat_t{}, syscall.ENOENT
|
||||
return sys.Stat_t{}, experimentalsys.ENOENT
|
||||
}
|
||||
pathp, err := syscall.UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return sys.Stat_t{}, syscall.EINVAL
|
||||
return sys.Stat_t{}, experimentalsys.EINVAL
|
||||
}
|
||||
|
||||
// open the file handle
|
||||
h, err := syscall.CreateFile(pathp, 0, 0, nil,
|
||||
syscall.OPEN_EXISTING, createFileAttrs, 0)
|
||||
if err != nil {
|
||||
errno := experimentalsys.UnwrapOSError(err)
|
||||
// To match expectations of WASI, e.g. TinyGo TestStatBadDir, return
|
||||
// ENOENT, not ENOTDIR.
|
||||
if err == syscall.ENOTDIR {
|
||||
err = syscall.ENOENT
|
||||
if errno == experimentalsys.ENOTDIR {
|
||||
errno = experimentalsys.ENOENT
|
||||
}
|
||||
return sys.Stat_t{}, platform.UnwrapOSError(err)
|
||||
return sys.Stat_t{}, errno
|
||||
}
|
||||
defer syscall.CloseHandle(h)
|
||||
|
||||
@@ -59,7 +60,7 @@ type fdFile interface {
|
||||
Fd() uintptr
|
||||
}
|
||||
|
||||
func statFile(f fs.File) (sys.Stat_t, syscall.Errno) {
|
||||
func statFile(f fs.File) (sys.Stat_t, experimentalsys.Errno) {
|
||||
if osF, ok := f.(fdFile); ok {
|
||||
// Attempt to get the stat by handle, which works for normal files
|
||||
st, err := statHandle(syscall.Handle(osF.Fd()))
|
||||
@@ -69,7 +70,7 @@ func statFile(f fs.File) (sys.Stat_t, syscall.Errno) {
|
||||
//
|
||||
// Note: statHandle uses UnwrapOSError which coerces
|
||||
// ERROR_INVALID_HANDLE to EBADF.
|
||||
if err != syscall.EBADF {
|
||||
if err != experimentalsys.EBADF {
|
||||
return st, err
|
||||
}
|
||||
}
|
||||
@@ -77,7 +78,7 @@ func statFile(f fs.File) (sys.Stat_t, syscall.Errno) {
|
||||
}
|
||||
|
||||
// inoFromFileInfo uses stat to get the inode information of the file.
|
||||
func inoFromFileInfo(dirPath string, info fs.FileInfo) (ino sys.Inode, errno syscall.Errno) {
|
||||
func inoFromFileInfo(dirPath string, info fs.FileInfo) (ino sys.Inode, errno experimentalsys.Errno) {
|
||||
if dirPath == "" {
|
||||
// This is a fs.File backed implementation which doesn't have access to
|
||||
// the original file path.
|
||||
@@ -92,15 +93,15 @@ func inoFromFileInfo(dirPath string, info fs.FileInfo) (ino sys.Inode, errno sys
|
||||
return
|
||||
}
|
||||
|
||||
func statHandle(h syscall.Handle) (sys.Stat_t, syscall.Errno) {
|
||||
func statHandle(h syscall.Handle) (sys.Stat_t, experimentalsys.Errno) {
|
||||
winFt, err := syscall.GetFileType(h)
|
||||
if err != nil {
|
||||
return sys.Stat_t{}, platform.UnwrapOSError(err)
|
||||
return sys.Stat_t{}, experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
var fi syscall.ByHandleFileInformation
|
||||
if err = syscall.GetFileInformationByHandle(h, &fi); err != nil {
|
||||
return sys.Stat_t{}, platform.UnwrapOSError(err)
|
||||
return sys.Stat_t{}, experimentalsys.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
var m fs.FileMode
|
||||
|
||||
@@ -4,11 +4,10 @@ package sysfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func fsync(f *os.File) syscall.Errno {
|
||||
return platform.UnwrapOSError(f.Sync())
|
||||
func fsync(f *os.File) sys.Errno {
|
||||
return sys.UnwrapOSError(f.Sync())
|
||||
}
|
||||
|
||||
@@ -2,17 +2,16 @@ package sysfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func fsync(f *os.File) syscall.Errno {
|
||||
errno := platform.UnwrapOSError(f.Sync())
|
||||
func fsync(f *os.File) sys.Errno {
|
||||
errno := sys.UnwrapOSError(f.Sync())
|
||||
// Coerce error performing stat on a directory to 0, as it won't work
|
||||
// on Windows.
|
||||
switch errno {
|
||||
case syscall.EACCES /* Go 1.20 */, syscall.EBADF /* Go 1.18 */ :
|
||||
case sys.EACCES /* Go 1.20 */, sys.EBADF /* Go 1.18 */ :
|
||||
if st, err := f.Stat(); err == nil && st.IsDir() {
|
||||
errno = 0
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"path"
|
||||
"runtime"
|
||||
"sort"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
@@ -49,7 +49,7 @@ func testOpen_O_RDWR(t *testing.T, tmpDir string, testFS fsapi.FS) {
|
||||
if runtime.GOOS != "windows" {
|
||||
// If the read-only flag was honored, we should not be able to write!
|
||||
_, err = f.Write(fileContents)
|
||||
require.EqualErrno(t, syscall.EBADF, platform.UnwrapOSError(err))
|
||||
require.EqualErrno(t, experimentalsys.EBADF, experimentalsys.UnwrapOSError(err))
|
||||
}
|
||||
|
||||
// Verify stat on the file
|
||||
@@ -94,7 +94,7 @@ func testOpen_Read(t *testing.T, testFS fsapi.FS, requireFileIno, expectDirIno b
|
||||
_, errno := testFS.OpenFile("nope", os.O_RDONLY, 0)
|
||||
|
||||
// We currently follow os.Open not syscall.Open, so the error is wrapped.
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
require.EqualErrno(t, experimentalsys.ENOENT, errno)
|
||||
})
|
||||
|
||||
t.Run("readdir . opens root", func(t *testing.T) {
|
||||
@@ -228,20 +228,20 @@ human
|
||||
defer f.Close()
|
||||
|
||||
_, errno = f.Write([]byte{1, 2, 3, 4})
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
require.EqualErrno(t, experimentalsys.EBADF, errno)
|
||||
})
|
||||
|
||||
t.Run("opening a directory with O_RDWR is EISDIR", func(t *testing.T) {
|
||||
_, errno := testFS.OpenFile("sub", fsapi.O_DIRECTORY|os.O_RDWR, 0)
|
||||
require.EqualErrno(t, syscall.EISDIR, errno)
|
||||
require.EqualErrno(t, experimentalsys.EISDIR, errno)
|
||||
})
|
||||
}
|
||||
|
||||
func testLstat(t *testing.T, testFS fsapi.FS) {
|
||||
_, errno := testFS.Lstat("cat")
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
require.EqualErrno(t, experimentalsys.ENOENT, errno)
|
||||
_, errno = testFS.Lstat("sub/cat")
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
require.EqualErrno(t, experimentalsys.ENOENT, errno)
|
||||
|
||||
var st sys.Stat_t
|
||||
|
||||
@@ -308,9 +308,9 @@ func requireLinkStat(t *testing.T, testFS fsapi.FS, path string, stat sys.Stat_t
|
||||
|
||||
func testStat(t *testing.T, testFS fsapi.FS) {
|
||||
_, errno := testFS.Stat("cat")
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
require.EqualErrno(t, experimentalsys.ENOENT, errno)
|
||||
_, errno = testFS.Stat("sub/cat")
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
require.EqualErrno(t, experimentalsys.ENOENT, errno)
|
||||
|
||||
st, errno := testFS.Stat("sub/test.txt")
|
||||
require.EqualErrno(t, 0, errno)
|
||||
|
||||
@@ -5,13 +5,13 @@ package sysfs
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func unlink(name string) (errno syscall.Errno) {
|
||||
func unlink(name string) (errno sys.Errno) {
|
||||
err := syscall.Unlink(name)
|
||||
if errno = platform.UnwrapOSError(err); errno == syscall.EPERM {
|
||||
errno = syscall.EISDIR
|
||||
if errno = sys.UnwrapOSError(err); errno == sys.EPERM {
|
||||
errno = sys.EISDIR
|
||||
}
|
||||
return errno
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ package sysfs
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
|
||||
@@ -13,7 +13,7 @@ func TestUnlink(t *testing.T) {
|
||||
t.Run("doesn't exist", func(t *testing.T) {
|
||||
name := "non-existent"
|
||||
errno := unlink(name)
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
require.EqualErrno(t, sys.ENOENT, errno)
|
||||
})
|
||||
|
||||
t.Run("target: dir", func(t *testing.T) {
|
||||
@@ -23,7 +23,7 @@ func TestUnlink(t *testing.T) {
|
||||
require.NoError(t, os.Mkdir(dir, 0o700))
|
||||
|
||||
errno := unlink(dir)
|
||||
require.EqualErrno(t, syscall.EISDIR, errno)
|
||||
require.EqualErrno(t, sys.EISDIR, errno)
|
||||
|
||||
require.NoError(t, os.Remove(dir))
|
||||
})
|
||||
|
||||
@@ -6,21 +6,21 @@ import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func unlink(name string) syscall.Errno {
|
||||
func unlink(name string) sys.Errno {
|
||||
err := syscall.Unlink(name)
|
||||
if err == nil {
|
||||
return 0
|
||||
}
|
||||
errno := platform.UnwrapOSError(err)
|
||||
if errno == syscall.EBADF {
|
||||
errno := sys.UnwrapOSError(err)
|
||||
if errno == sys.EBADF {
|
||||
lstat, errLstat := os.Lstat(name)
|
||||
if errLstat == nil && lstat.Mode()&os.ModeSymlink != 0 {
|
||||
errno = platform.UnwrapOSError(os.Remove(name))
|
||||
errno = sys.UnwrapOSError(os.Remove(name))
|
||||
} else {
|
||||
errno = syscall.EISDIR
|
||||
errno = sys.EISDIR
|
||||
}
|
||||
}
|
||||
return errno
|
||||
|
||||
@@ -13,9 +13,10 @@ import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
// TestingT is an interface wrapper of functions used in TestingT
|
||||
@@ -131,14 +132,14 @@ func Error(t TestingT, err error, formatWithArgs ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// EqualErrno should be used for functions that return syscall.Errno or nil.
|
||||
func EqualErrno(t TestingT, expected syscall.Errno, err error, formatWithArgs ...interface{}) {
|
||||
// EqualErrno should be used for functions that return sys.Errno or nil.
|
||||
func EqualErrno(t TestingT, expected sys.Errno, err error, formatWithArgs ...interface{}) {
|
||||
if err == nil {
|
||||
fail(t, "expected a syscall.Errno, but was nil", "", formatWithArgs...)
|
||||
fail(t, "expected a sys.Errno, but was nil", "", formatWithArgs...)
|
||||
return
|
||||
}
|
||||
if se, ok := err.(syscall.Errno); !ok {
|
||||
fail(t, fmt.Sprintf("expected %v to be a syscall.Errno", err), "", formatWithArgs...)
|
||||
if se, ok := err.(sys.Errno); !ok {
|
||||
fail(t, fmt.Sprintf("expected %v to be a sys.Errno", err), "", formatWithArgs...)
|
||||
} else if se != expected {
|
||||
fail(t, fmt.Sprintf("expected Errno %#[1]v(%[1]s), but was %#[2]v(%[2]s)", expected, err), "", formatWithArgs...)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,9 @@ package require
|
||||
import (
|
||||
"io"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func TestEqualErrno(t *testing.T) {
|
||||
@@ -22,36 +23,36 @@ func TestEqualErrno(t *testing.T) {
|
||||
{
|
||||
name: "EqualErrno passes on equal",
|
||||
require: func(t TestingT) {
|
||||
EqualErrno(t, syscall.ENOENT, syscall.ENOENT)
|
||||
EqualErrno(t, sys.ENOENT, sys.ENOENT)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EqualErrno fails on nil",
|
||||
require: func(t TestingT) {
|
||||
EqualErrno(t, syscall.ENOENT, nil)
|
||||
EqualErrno(t, sys.ENOENT, nil)
|
||||
},
|
||||
expectedLog: "expected a syscall.Errno, but was nil",
|
||||
expectedLog: "expected a sys.Errno, but was nil",
|
||||
},
|
||||
{
|
||||
name: "EqualErrno fails on not Errno",
|
||||
require: func(t TestingT) {
|
||||
EqualErrno(t, syscall.ENOENT, io.EOF)
|
||||
EqualErrno(t, sys.ENOENT, io.EOF)
|
||||
},
|
||||
expectedLog: `expected EOF to be a syscall.Errno`,
|
||||
expectedLog: `expected EOF to be a sys.Errno`,
|
||||
},
|
||||
{
|
||||
name: "EqualErrno fails on not equal",
|
||||
require: func(t TestingT) {
|
||||
EqualErrno(t, syscall.ENOENT, syscall.EIO)
|
||||
EqualErrno(t, sys.ENOENT, sys.EIO)
|
||||
},
|
||||
expectedLog: `expected Errno 0x2(no such file or directory), but was 0x5(input/output error)`,
|
||||
expectedLog: `expected Errno 0xc(no such file or directory), but was 0x8(input/output error)`,
|
||||
},
|
||||
{
|
||||
name: "EqualErrno fails on not equal with format",
|
||||
require: func(t TestingT) {
|
||||
EqualErrno(t, syscall.ENOENT, syscall.EIO, "pay me %d", 5)
|
||||
EqualErrno(t, sys.ENOENT, sys.EIO, "pay me %d", 5)
|
||||
},
|
||||
expectedLog: `expected Errno 0x2(no such file or directory), but was 0x5(input/output error): pay me 5`,
|
||||
expectedLog: `expected Errno 0xc(no such file or directory), but was 0x8(input/output error): pay me 5`,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+22
-21
@@ -2,7 +2,8 @@ package wasip1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
// Errno is neither uint16 nor an alias for parity with wasm.ValueType.
|
||||
@@ -263,47 +264,47 @@ var errnoToString = [...]string{
|
||||
// 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(errno syscall.Errno) Errno {
|
||||
func ToErrno(errno sys.Errno) Errno {
|
||||
switch errno {
|
||||
case 0:
|
||||
return ErrnoSuccess
|
||||
case syscall.EACCES:
|
||||
case sys.EACCES:
|
||||
return ErrnoAcces
|
||||
case syscall.EAGAIN:
|
||||
case sys.EAGAIN:
|
||||
return ErrnoAgain
|
||||
case syscall.EBADF:
|
||||
case sys.EBADF:
|
||||
return ErrnoBadf
|
||||
case syscall.EEXIST:
|
||||
case sys.EEXIST:
|
||||
return ErrnoExist
|
||||
case syscall.EFAULT:
|
||||
case sys.EFAULT:
|
||||
return ErrnoFault
|
||||
case syscall.EINTR:
|
||||
case sys.EINTR:
|
||||
return ErrnoIntr
|
||||
case syscall.EINVAL:
|
||||
case sys.EINVAL:
|
||||
return ErrnoInval
|
||||
case syscall.EIO:
|
||||
case sys.EIO:
|
||||
return ErrnoIo
|
||||
case syscall.EISDIR:
|
||||
case sys.EISDIR:
|
||||
return ErrnoIsdir
|
||||
case syscall.ELOOP:
|
||||
case sys.ELOOP:
|
||||
return ErrnoLoop
|
||||
case syscall.ENAMETOOLONG:
|
||||
case sys.ENAMETOOLONG:
|
||||
return ErrnoNametoolong
|
||||
case syscall.ENOENT:
|
||||
case sys.ENOENT:
|
||||
return ErrnoNoent
|
||||
case syscall.ENOSYS:
|
||||
case sys.ENOSYS:
|
||||
return ErrnoNosys
|
||||
case syscall.ENOTDIR:
|
||||
case sys.ENOTDIR:
|
||||
return ErrnoNotdir
|
||||
case syscall.ENOTEMPTY:
|
||||
case sys.ENOTEMPTY:
|
||||
return ErrnoNotempty
|
||||
case syscall.ENOTSOCK:
|
||||
case sys.ENOTSOCK:
|
||||
return ErrnoNotsock
|
||||
case syscall.ENOTSUP:
|
||||
case sys.ENOTSUP:
|
||||
return ErrnoNotsup
|
||||
case syscall.EPERM:
|
||||
case sys.EPERM:
|
||||
return ErrnoPerm
|
||||
case syscall.EROFS:
|
||||
case sys.EROFS:
|
||||
return ErrnoRofs
|
||||
default:
|
||||
return ErrnoIo
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package wasip1
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
)
|
||||
|
||||
func TestToErrno(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input syscall.Errno
|
||||
input sys.Errno
|
||||
expected Errno
|
||||
}{
|
||||
{
|
||||
@@ -16,98 +17,103 @@ func TestToErrno(t *testing.T) {
|
||||
expected: ErrnoSuccess,
|
||||
},
|
||||
{
|
||||
name: "syscall.EACCES",
|
||||
input: syscall.EACCES,
|
||||
name: "sys.EACCES",
|
||||
input: sys.EACCES,
|
||||
expected: ErrnoAcces,
|
||||
},
|
||||
{
|
||||
name: "syscall.EAGAIN",
|
||||
input: syscall.EAGAIN,
|
||||
name: "sys.EAGAIN",
|
||||
input: sys.EAGAIN,
|
||||
expected: ErrnoAgain,
|
||||
},
|
||||
{
|
||||
name: "syscall.EBADF",
|
||||
input: syscall.EBADF,
|
||||
name: "sys.EBADF",
|
||||
input: sys.EBADF,
|
||||
expected: ErrnoBadf,
|
||||
},
|
||||
{
|
||||
name: "syscall.EEXIST",
|
||||
input: syscall.EEXIST,
|
||||
name: "sys.EEXIST",
|
||||
input: sys.EEXIST,
|
||||
expected: ErrnoExist,
|
||||
},
|
||||
{
|
||||
name: "syscall.EFAULT",
|
||||
input: syscall.EFAULT,
|
||||
name: "sys.EFAULT",
|
||||
input: sys.EFAULT,
|
||||
expected: ErrnoFault,
|
||||
},
|
||||
{
|
||||
name: "syscall.EINTR",
|
||||
input: syscall.EINTR,
|
||||
name: "sys.EINTR",
|
||||
input: sys.EINTR,
|
||||
expected: ErrnoIntr,
|
||||
},
|
||||
{
|
||||
name: "syscall.EINVAL",
|
||||
input: syscall.EINVAL,
|
||||
name: "sys.EINVAL",
|
||||
input: sys.EINVAL,
|
||||
expected: ErrnoInval,
|
||||
},
|
||||
{
|
||||
name: "syscall.EIO",
|
||||
input: syscall.EIO,
|
||||
name: "sys.EIO",
|
||||
input: sys.EIO,
|
||||
expected: ErrnoIo,
|
||||
},
|
||||
{
|
||||
name: "syscall.EISDIR",
|
||||
input: syscall.EISDIR,
|
||||
name: "sys.EISDIR",
|
||||
input: sys.EISDIR,
|
||||
expected: ErrnoIsdir,
|
||||
},
|
||||
{
|
||||
name: "syscall.ELOOP",
|
||||
input: syscall.ELOOP,
|
||||
name: "sys.ELOOP",
|
||||
input: sys.ELOOP,
|
||||
expected: ErrnoLoop,
|
||||
},
|
||||
{
|
||||
name: "syscall.ENAMETOOLONG",
|
||||
input: syscall.ENAMETOOLONG,
|
||||
name: "sys.ENAMETOOLONG",
|
||||
input: sys.ENAMETOOLONG,
|
||||
expected: ErrnoNametoolong,
|
||||
},
|
||||
{
|
||||
name: "syscall.ENOENT",
|
||||
input: syscall.ENOENT,
|
||||
name: "sys.ENOENT",
|
||||
input: sys.ENOENT,
|
||||
expected: ErrnoNoent,
|
||||
},
|
||||
{
|
||||
name: "syscall.ENOSYS",
|
||||
input: syscall.ENOSYS,
|
||||
name: "sys.ENOSYS",
|
||||
input: sys.ENOSYS,
|
||||
expected: ErrnoNosys,
|
||||
},
|
||||
{
|
||||
name: "syscall.ENOTDIR",
|
||||
input: syscall.ENOTDIR,
|
||||
name: "sys.ENOTDIR",
|
||||
input: sys.ENOTDIR,
|
||||
expected: ErrnoNotdir,
|
||||
},
|
||||
{
|
||||
name: "syscall.ENOTEMPTY",
|
||||
input: syscall.ENOTEMPTY,
|
||||
name: "sys.ENOTEMPTY",
|
||||
input: sys.ENOTEMPTY,
|
||||
expected: ErrnoNotempty,
|
||||
},
|
||||
{
|
||||
name: "syscall.ENOTSUP",
|
||||
input: syscall.ENOTSUP,
|
||||
name: "sys.ENOTSOCK",
|
||||
input: sys.ENOTSOCK,
|
||||
expected: ErrnoNotsock,
|
||||
},
|
||||
{
|
||||
name: "sys.ENOTSUP",
|
||||
input: sys.ENOTSUP,
|
||||
expected: ErrnoNotsup,
|
||||
},
|
||||
{
|
||||
name: "syscall.EPERM",
|
||||
input: syscall.EPERM,
|
||||
name: "sys.EPERM",
|
||||
input: sys.EPERM,
|
||||
expected: ErrnoPerm,
|
||||
},
|
||||
{
|
||||
name: "syscall.EROFS",
|
||||
input: syscall.EROFS,
|
||||
name: "sys.EROFS",
|
||||
input: sys.EROFS,
|
||||
expected: ErrnoRofs,
|
||||
},
|
||||
{
|
||||
name: "syscall.EqualErrno unexpected == ErrnoIo",
|
||||
input: syscall.Errno(0xfe),
|
||||
name: "sys.EqualErrno unexpected == ErrnoIo",
|
||||
input: sys.Errno(0xfe),
|
||||
expected: ErrnoIo,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/experimental/sys"
|
||||
internalsys "github.com/tetratelabs/wazero/internal/sys"
|
||||
"github.com/tetratelabs/wazero/internal/sysfs"
|
||||
testfs "github.com/tetratelabs/wazero/internal/testing/fs"
|
||||
@@ -158,8 +158,8 @@ func TestModuleInstance_Close(t *testing.T) {
|
||||
m, err := s.Instantiate(testCtx, &Module{}, t.Name(), sysCtx, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// In fsapi.FS, non syscall errors map to syscall.EIO.
|
||||
require.EqualErrno(t, syscall.EIO, m.Close(testCtx))
|
||||
// In fsapi.FS, non syscall errors map to sys.EIO.
|
||||
require.EqualErrno(t, sys.EIO, m.Close(testCtx))
|
||||
|
||||
// Verify our intended side-effect
|
||||
_, ok := fsCtx.LookupFile(3)
|
||||
@@ -257,8 +257,8 @@ func TestModuleInstance_CallDynamic(t *testing.T) {
|
||||
m, err := s.Instantiate(testCtx, &Module{}, t.Name(), sysCtx, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// In fsapi.FS, non syscall errors map to syscall.EIO.
|
||||
require.EqualErrno(t, syscall.EIO, m.Close(testCtx))
|
||||
// In fsapi.FS, non syscall errors map to sys.EIO.
|
||||
require.EqualErrno(t, sys.EIO, m.Close(testCtx))
|
||||
|
||||
// Verify our intended side-effect
|
||||
_, ok := fsCtx.LookupFile(3)
|
||||
|
||||
+9
-8
@@ -1,4 +1,4 @@
|
||||
package sys
|
||||
package sys_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
type notExitError struct {
|
||||
@@ -17,7 +18,7 @@ func (e *notExitError) Error() string {
|
||||
}
|
||||
|
||||
func TestIs(t *testing.T) {
|
||||
err := NewExitError(2)
|
||||
err := sys.NewExitError(2)
|
||||
tests := []struct {
|
||||
name string
|
||||
target error
|
||||
@@ -30,7 +31,7 @@ func TestIs(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "different exit code",
|
||||
target: NewExitError(1),
|
||||
target: sys.NewExitError(1),
|
||||
matches: false,
|
||||
},
|
||||
{
|
||||
@@ -53,19 +54,19 @@ func TestIs(t *testing.T) {
|
||||
|
||||
func TestExitError_Error(t *testing.T) {
|
||||
t.Run("timeout", func(t *testing.T) {
|
||||
err := NewExitError(ExitCodeDeadlineExceeded)
|
||||
require.Equal(t, ExitCodeDeadlineExceeded, err.ExitCode())
|
||||
err := sys.NewExitError(sys.ExitCodeDeadlineExceeded)
|
||||
require.Equal(t, sys.ExitCodeDeadlineExceeded, err.ExitCode())
|
||||
require.EqualError(t, err, "module closed with context deadline exceeded")
|
||||
require.ErrorIs(t, err, context.DeadlineExceeded, "exit code context deadline exceeded should work")
|
||||
})
|
||||
t.Run("cancel", func(t *testing.T) {
|
||||
err := NewExitError(ExitCodeContextCanceled)
|
||||
require.Equal(t, ExitCodeContextCanceled, err.ExitCode())
|
||||
err := sys.NewExitError(sys.ExitCodeContextCanceled)
|
||||
require.Equal(t, sys.ExitCodeContextCanceled, err.ExitCode())
|
||||
require.EqualError(t, err, "module closed with context canceled")
|
||||
require.ErrorIs(t, err, context.Canceled, "exit code context canceled should work")
|
||||
})
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
err := NewExitError(123)
|
||||
err := sys.NewExitError(123)
|
||||
require.Equal(t, uint32(123), err.ExitCode())
|
||||
require.EqualError(t, err, "module closed with exit_code(123)")
|
||||
})
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package sys
|
||||
|
||||
const SysParseable = sysParseable
|
||||
+10
-9
@@ -1,4 +1,4 @@
|
||||
package sys
|
||||
package sys_test
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"testing/fstest"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
"github.com/tetratelabs/wazero/sys"
|
||||
)
|
||||
|
||||
func Test_NewStat_t(t *testing.T) {
|
||||
@@ -30,7 +31,7 @@ func Test_NewStat_t(t *testing.T) {
|
||||
osSymlinkInfo, err := os.Lstat(link)
|
||||
require.NoError(t, err)
|
||||
|
||||
osFileSt := NewStat_t(osFileInfo)
|
||||
osFileSt := sys.NewStat_t(osFileInfo)
|
||||
testFS := fstest.MapFS{
|
||||
"dir": {
|
||||
Mode: osDirInfo.Mode(),
|
||||
@@ -115,7 +116,7 @@ func Test_NewStat_t(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
st := NewStat_t(tc.info)
|
||||
st := sys.NewStat_t(tc.info)
|
||||
if tc.expectDevIno && runtime.GOOS != "windows" {
|
||||
require.NotEqual(t, uint64(0), st.Dev)
|
||||
require.NotEqual(t, uint64(0), st.Ino)
|
||||
@@ -127,7 +128,7 @@ func Test_NewStat_t(t *testing.T) {
|
||||
// link mode may differ on windows, so mask
|
||||
require.Equal(t, tc.expectedMode, st.Mode&tc.expectedMode)
|
||||
|
||||
if sysParseable && runtime.GOOS != "windows" {
|
||||
if sys.SysParseable && runtime.GOOS != "windows" {
|
||||
switch st.Nlink {
|
||||
case 2, 4: // dirents may include dot entries.
|
||||
require.Equal(t, fs.ModeDir, st.Mode.Type())
|
||||
@@ -140,15 +141,15 @@ func Test_NewStat_t(t *testing.T) {
|
||||
|
||||
require.Equal(t, tc.expectedSize, st.Size)
|
||||
|
||||
if tc.expectAtimCtime && sysParseable {
|
||||
if tc.expectAtimCtime && sys.SysParseable {
|
||||
// We don't validate times strictly because it is os-dependent
|
||||
// what updates times. There are edge cases for symlinks, too.
|
||||
require.NotEqual(t, EpochNanos(0), st.Ctim)
|
||||
require.NotEqual(t, EpochNanos(0), st.Mtim)
|
||||
require.NotEqual(t, EpochNanos(0), st.Mtim)
|
||||
require.NotEqual(t, sys.EpochNanos(0), st.Ctim)
|
||||
require.NotEqual(t, sys.EpochNanos(0), st.Mtim)
|
||||
require.NotEqual(t, sys.EpochNanos(0), st.Mtim)
|
||||
} else { // mtim is used for atim and ctime
|
||||
require.Equal(t, st.Mtim, st.Ctim)
|
||||
require.NotEqual(t, EpochNanos(0), st.Mtim)
|
||||
require.NotEqual(t, sys.EpochNanos(0), st.Mtim)
|
||||
require.Equal(t, st.Mtim, st.Atim)
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user