Revert "sysfs: requires all methods to return syscall.Errno"
This reverts commit 4ea9d1a7b5.
This commit is contained in:
@@ -2,7 +2,6 @@ package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
|
||||
@@ -23,7 +22,7 @@ import (
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is ErrnoSuccess except the following error conditions:
|
||||
// - syscall.EFAULT: there is not enough memory to write results
|
||||
// - ErrnoFault: 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 +42,7 @@ import (
|
||||
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||
var argsGet = newHostFunc(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) Errno {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
argv, argvBuf := uint32(params[0]), uint32(params[1])
|
||||
return writeOffsetsAndNullTerminatedValues(mod.Memory(), sysCtx.Args(), argv, argvBuf, sysCtx.ArgsSize())
|
||||
@@ -61,7 +60,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
|
||||
// - ErrnoFault: 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 +79,7 @@ func argsGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno
|
||||
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||
var argsSizesGet = newHostFunc(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) Errno {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
mem := mod.Memory()
|
||||
resultArgc, resultArgvLen := uint32(params[0]), uint32(params[1])
|
||||
@@ -88,10 +87,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 ErrnoFault
|
||||
}
|
||||
if !mem.WriteUint32Le(resultArgvLen, sysCtx.ArgsSize()) {
|
||||
return syscall.EFAULT
|
||||
return ErrnoFault
|
||||
}
|
||||
return 0
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
|
||||
@@ -20,10 +19,10 @@ 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
|
||||
// The return value is ErrnoSuccess except the following error conditions:
|
||||
// - ErrnoNotsup: the clock ID is not supported.
|
||||
// - ErrnoInval: the clock ID is invalid.
|
||||
// - ErrnoFault: 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 +38,7 @@ import (
|
||||
// See https://linux.die.net/man/3/clock_getres
|
||||
var clockResGet = newHostFunc(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) Errno {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
id, resultResolution := uint32(params[0]), uint32(params[1])
|
||||
|
||||
@@ -50,13 +49,13 @@ func clockResGetFn(_ context.Context, mod api.Module, params []uint64) syscall.E
|
||||
case ClockIDMonotonic:
|
||||
resolution = uint64(sysCtx.NanotimeResolution())
|
||||
default:
|
||||
return syscall.EINVAL
|
||||
return ErrnoInval
|
||||
}
|
||||
|
||||
if !mod.Memory().WriteUint64Le(resultResolution, resolution) {
|
||||
return syscall.EFAULT
|
||||
return ErrnoFault
|
||||
}
|
||||
return 0
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
// clockTimeGet is the WASI function named ClockTimeGetName that returns
|
||||
@@ -72,10 +71,10 @@ 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
|
||||
// The return value is ErrnoSuccess except the following error conditions:
|
||||
// - ErrnoNotsup: the clock ID is not supported.
|
||||
// - ErrnoInval: the clock ID is invalid.
|
||||
// - ErrnoFault: 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 +91,7 @@ func clockResGetFn(_ context.Context, mod api.Module, params []uint64) syscall.E
|
||||
// See https://linux.die.net/man/3/clock_gettime
|
||||
var clockTimeGet = newHostFunc(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) Errno {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
id := uint32(params[0])
|
||||
// TODO: precision is currently ignored.
|
||||
@@ -106,11 +105,11 @@ func clockTimeGetFn(_ context.Context, mod api.Module, params []uint64) syscall.
|
||||
case ClockIDMonotonic:
|
||||
val = sysCtx.Nanotime()
|
||||
default:
|
||||
return syscall.EINVAL
|
||||
return ErrnoInval
|
||||
}
|
||||
|
||||
if !mod.Memory().WriteUint64Le(resultTimestamp, uint64(val)) {
|
||||
return syscall.EFAULT
|
||||
return ErrnoFault
|
||||
}
|
||||
return 0
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
|
||||
@@ -23,8 +22,8 @@ import (
|
||||
//
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is 0 except the following error conditions:
|
||||
// - syscall.EFAULT: there is not enough memory to write results
|
||||
// The return value is ErrnoSuccess except the following error conditions:
|
||||
// - ErrnoFault: 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 +42,7 @@ import (
|
||||
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||
var environGet = newHostFunc(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) Errno {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
environ, environBuf := uint32(params[0]), uint32(params[1])
|
||||
|
||||
@@ -62,8 +61,8 @@ 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
|
||||
// The return value is ErrnoSuccess except the following error conditions:
|
||||
// - ErrnoFault: 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 +82,7 @@ func environGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Er
|
||||
// and https://en.wikipedia.org/wiki/Null-terminated_string
|
||||
var environSizesGet = newHostFunc(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) Errno {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
mem := mod.Memory()
|
||||
resultEnvironc, resultEnvironvLen := uint32(params[0]), uint32(params[1])
|
||||
@@ -91,10 +90,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 ErrnoFault
|
||||
}
|
||||
if !mem.WriteUint32Le(resultEnvironvLen, sysCtx.EnvironSize()) {
|
||||
return syscall.EFAULT
|
||||
return ErrnoFault
|
||||
}
|
||||
return 0
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,6 @@ import (
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -57,8 +56,8 @@ func Test_fdAllocate(t *testing.T) {
|
||||
preopen := fsc.RootFS()
|
||||
defer r.Close(testCtx)
|
||||
|
||||
fd, errno := fsc.OpenFile(preopen, fileName, os.O_RDWR, 0)
|
||||
require.Zero(t, errno)
|
||||
fd, err := fsc.OpenFile(preopen, fileName, os.O_RDWR, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
f, ok := fsc.LookupFile(fd)
|
||||
require.True(t, ok)
|
||||
@@ -135,11 +134,11 @@ func Test_fdClose(t *testing.T) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
preopen := fsc.RootFS()
|
||||
|
||||
fdToClose, errno := fsc.OpenFile(preopen, path1, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fdToClose, err := fsc.OpenFile(preopen, path1, os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
fdToKeep, errno := fsc.OpenFile(preopen, path2, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fdToKeep, err := fsc.OpenFile(preopen, path2, os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Close
|
||||
requireErrnoResult(t, ErrnoSuccess, mod, FdCloseName, uint64(fdToClose))
|
||||
@@ -228,11 +227,11 @@ func Test_fdFdstatGet(t *testing.T) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
preopen := fsc.RootFS()
|
||||
|
||||
fileFD, errno := fsc.OpenFile(preopen, file, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fileFD, err := fsc.OpenFile(preopen, file, os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
dirFD, errno := fsc.OpenFile(preopen, dir, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
dirFD, err := fsc.OpenFile(preopen, dir, os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -379,8 +378,8 @@ func Test_fdFdstatSetFlags(t *testing.T) {
|
||||
defer r.Close(testCtx)
|
||||
|
||||
// First, open it with O_APPEND.
|
||||
fd, errno := fsc.OpenFile(preopen, fileName, os.O_RDWR|os.O_APPEND, 0)
|
||||
require.Zero(t, errno)
|
||||
fd, err := fsc.OpenFile(preopen, fileName, os.O_RDWR|os.O_APPEND, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
writeWazero := func() {
|
||||
iovs := uint32(1) // arbitrary offset
|
||||
@@ -473,11 +472,11 @@ func Test_fdFilestatGet(t *testing.T) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
preopen := fsc.RootFS()
|
||||
|
||||
fileFD, errno := fsc.OpenFile(preopen, file, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fileFD, err := fsc.OpenFile(preopen, file, os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
dirFD, errno := fsc.OpenFile(preopen, dir, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
dirFD, err := fsc.OpenFile(preopen, dir, os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1811,9 +1810,9 @@ var (
|
||||
panic(err)
|
||||
}
|
||||
defer d.Close()
|
||||
dirents, errno := platform.Readdir(d, -1)
|
||||
if errno != 0 {
|
||||
panic(errno)
|
||||
dirents, err := platform.Readdir(d, -1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dots := []*platform.Dirent{
|
||||
{Name: ".", Type: fs.ModeDir},
|
||||
@@ -1885,8 +1884,8 @@ func Test_fdReaddir(t *testing.T) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
preopen := fsc.RootFS()
|
||||
|
||||
fd, errno := fsc.OpenFile(preopen, "dir", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fd, err := fsc.OpenFile(preopen, "dir", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1971,8 +1970,8 @@ func Test_fdReaddir(t *testing.T) {
|
||||
dir: func() *sys.FileEntry {
|
||||
dir, err := fstest.FS.Open("dir")
|
||||
require.NoError(t, err)
|
||||
dirent, errno := platform.Readdir(dir, 1)
|
||||
require.Zero(t, errno)
|
||||
dirent, err := platform.Readdir(dir, 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &sys.FileEntry{
|
||||
File: dir,
|
||||
@@ -1996,8 +1995,8 @@ func Test_fdReaddir(t *testing.T) {
|
||||
dir: func() *sys.FileEntry {
|
||||
dir, err := fstest.FS.Open("dir")
|
||||
require.NoError(t, err)
|
||||
dirent, errno := platform.Readdir(dir, 1)
|
||||
require.Zero(t, errno)
|
||||
dirent, err := platform.Readdir(dir, 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &sys.FileEntry{
|
||||
File: dir,
|
||||
@@ -2022,8 +2021,8 @@ func Test_fdReaddir(t *testing.T) {
|
||||
dir: func() *sys.FileEntry {
|
||||
dir, err := fstest.FS.Open("dir")
|
||||
require.NoError(t, err)
|
||||
dirent, errno := platform.Readdir(dir, 1)
|
||||
require.Zero(t, errno)
|
||||
dirent, err := platform.Readdir(dir, 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &sys.FileEntry{
|
||||
File: dir,
|
||||
@@ -2047,8 +2046,8 @@ func Test_fdReaddir(t *testing.T) {
|
||||
dir: func() *sys.FileEntry {
|
||||
dir, err := fstest.FS.Open("dir")
|
||||
require.NoError(t, err)
|
||||
dirent, errno := platform.Readdir(dir, 1)
|
||||
require.Zero(t, errno)
|
||||
dirent, err := platform.Readdir(dir, 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &sys.FileEntry{
|
||||
File: dir,
|
||||
@@ -2072,8 +2071,8 @@ func Test_fdReaddir(t *testing.T) {
|
||||
dir: func() *sys.FileEntry {
|
||||
dir, err := fstest.FS.Open("dir")
|
||||
require.NoError(t, err)
|
||||
two, errno := platform.Readdir(dir, 2)
|
||||
require.Zero(t, errno)
|
||||
two, err := platform.Readdir(dir, 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &sys.FileEntry{
|
||||
File: dir,
|
||||
@@ -2097,8 +2096,8 @@ func Test_fdReaddir(t *testing.T) {
|
||||
dir: func() *sys.FileEntry {
|
||||
dir, err := fstest.FS.Open("dir")
|
||||
require.NoError(t, err)
|
||||
two, errno := platform.Readdir(dir, 2)
|
||||
require.Zero(t, errno)
|
||||
two, err := platform.Readdir(dir, 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &sys.FileEntry{
|
||||
File: dir,
|
||||
@@ -2122,7 +2121,7 @@ func Test_fdReaddir(t *testing.T) {
|
||||
dir: func() *sys.FileEntry {
|
||||
dir, err := fstest.FS.Open("dir")
|
||||
require.NoError(t, err)
|
||||
_, errno = platform.Readdir(dir, 3)
|
||||
_, err = platform.Readdir(dir, 3)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &sys.FileEntry{
|
||||
@@ -2190,8 +2189,8 @@ func Test_fdReaddir_Rewind(t *testing.T) {
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fd, errno := fsc.OpenFile(fsc.RootFS(), "dir", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fd, err := fsc.OpenFile(fsc.RootFS(), "dir", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
mem := mod.Memory()
|
||||
const resultBufused, buf, bufSize = 0, 8, 200
|
||||
@@ -2254,11 +2253,11 @@ func Test_fdReaddir_Errors(t *testing.T) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
preopen := fsc.RootFS()
|
||||
|
||||
fileFD, errno := fsc.OpenFile(preopen, "animals.txt", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fileFD, err := fsc.OpenFile(preopen, "animals.txt", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
dirFD, errno := fsc.OpenFile(preopen, "dir", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
dirFD, err := fsc.OpenFile(preopen, "dir", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -2454,12 +2453,12 @@ func Test_fdRenumber(t *testing.T) {
|
||||
preopen := fsc.RootFS()
|
||||
|
||||
// Sanity check of the file descriptor assignment.
|
||||
fileFDAssigned, errno := fsc.OpenFile(preopen, "animals.txt", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fileFDAssigned, err := fsc.OpenFile(preopen, "animals.txt", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(fileFD), fileFDAssigned)
|
||||
|
||||
dirFDAssigned, errno := fsc.OpenFile(preopen, "dir", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
dirFDAssigned, err := fsc.OpenFile(preopen, "dir", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(dirFD), dirFDAssigned)
|
||||
|
||||
requireErrnoResult(t, tc.expectedErrno, mod, FdRenumberName, uint64(tc.from), uint64(tc.to))
|
||||
@@ -2566,7 +2565,7 @@ func Test_fdSeek_Errors(t *testing.T) {
|
||||
defer r.Close(testCtx)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
require.Zero(t, fsc.RootFS().Mkdir("dir", 0o0700))
|
||||
require.NoError(t, fsc.RootFS().Mkdir("dir", 0o0700))
|
||||
dirFD := requireOpenFD(t, mod, "dir")
|
||||
|
||||
memorySize := mod.Memory().Size()
|
||||
@@ -3552,10 +3551,10 @@ func Test_pathFilestatSetTimes(t *testing.T) {
|
||||
fsc := sys.FS()
|
||||
|
||||
var oldSt platform.Stat_t
|
||||
var errno syscall.Errno
|
||||
var err error
|
||||
if tc.expectedErrno == ErrnoSuccess {
|
||||
oldSt, errno = fsc.RootFS().Stat(pathName)
|
||||
require.Zero(t, errno)
|
||||
oldSt, err = fsc.RootFS().Stat(pathName)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
requireErrnoResult(t, tc.expectedErrno, mod, PathFilestatSetTimesName, uint64(fd), uint64(tc.flags),
|
||||
@@ -3566,8 +3565,8 @@ func Test_pathFilestatSetTimes(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
newSt, errno := fsc.RootFS().Stat(pathName)
|
||||
require.Zero(t, errno)
|
||||
newSt, err := fsc.RootFS().Stat(pathName)
|
||||
require.NoError(t, err)
|
||||
|
||||
if platform.CompilerSupported() {
|
||||
if tc.fstFlags&FstflagsAtim != 0 {
|
||||
@@ -3605,13 +3604,13 @@ func Test_pathLink(t *testing.T) {
|
||||
newDirPath := joinPath(tmpDir, newDirName)
|
||||
require.NoError(t, os.MkdirAll(joinPath(tmpDir, newDirName), 0o700))
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
newFd, errno := fsc.OpenFile(fsc.RootFS(), newDirName, 0o600, 0)
|
||||
require.Zero(t, errno)
|
||||
newFd, err := fsc.OpenFile(fsc.RootFS(), newDirName, 0o600, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
mem := mod.Memory()
|
||||
|
||||
fileName := "file"
|
||||
err := os.WriteFile(joinPath(oldDirPath, fileName), []byte{1, 2, 3, 4}, 0o700)
|
||||
err = os.WriteFile(joinPath(oldDirPath, fileName), []byte{1, 2, 3, 4}, 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
file := uint32(0xff)
|
||||
@@ -3642,8 +3641,8 @@ func Test_pathLink(t *testing.T) {
|
||||
require.NoError(t, f.Close())
|
||||
}()
|
||||
|
||||
st, errno := platform.StatFile(f)
|
||||
require.Zero(t, errno)
|
||||
st, err := platform.StatFile(f)
|
||||
require.NoError(t, err)
|
||||
require.False(t, st.Mode&os.ModeSymlink == os.ModeSymlink)
|
||||
require.Equal(t, uint64(2), st.Nlink)
|
||||
})
|
||||
@@ -3762,7 +3761,7 @@ func Test_pathOpen(t *testing.T) {
|
||||
contents := []byte("hello")
|
||||
_, err := sys.WriterForFile(fsc, expectedOpenedFd).Write(contents)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, fsc.CloseFile(expectedOpenedFd))
|
||||
require.NoError(t, fsc.CloseFile(expectedOpenedFd))
|
||||
|
||||
// verify the contents were appended
|
||||
b := readFile(t, dir, appendName)
|
||||
@@ -3794,7 +3793,7 @@ func Test_pathOpen(t *testing.T) {
|
||||
contents := []byte("hello")
|
||||
_, err := sys.WriterForFile(fsc, expectedOpenedFd).Write(contents)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, fsc.CloseFile(expectedOpenedFd))
|
||||
require.NoError(t, fsc.CloseFile(expectedOpenedFd))
|
||||
|
||||
// verify the contents were written
|
||||
b := readFile(t, dir, "creat")
|
||||
@@ -3826,7 +3825,7 @@ func Test_pathOpen(t *testing.T) {
|
||||
contents := []byte("hello")
|
||||
_, err := sys.WriterForFile(fsc, expectedOpenedFd).Write(contents)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, fsc.CloseFile(expectedOpenedFd))
|
||||
require.NoError(t, fsc.CloseFile(expectedOpenedFd))
|
||||
|
||||
// verify the contents were written
|
||||
b := readFile(t, dir, joinPath(dirName, "O_CREAT-O_TRUNC"))
|
||||
@@ -3891,7 +3890,7 @@ func Test_pathOpen(t *testing.T) {
|
||||
contents := []byte("hello")
|
||||
_, err := sys.WriterForFile(fsc, expectedOpenedFd).Write(contents)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, fsc.CloseFile(expectedOpenedFd))
|
||||
require.NoError(t, fsc.CloseFile(expectedOpenedFd))
|
||||
|
||||
// verify the contents were truncated
|
||||
b := readFile(t, dir, "trunc")
|
||||
@@ -3959,8 +3958,8 @@ func requireOpenFD(t *testing.T, mod api.Module, path string) uint32 {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
preopen := fsc.RootFS()
|
||||
|
||||
fd, errno := fsc.OpenFile(preopen, path, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fd, err := fsc.OpenFile(preopen, path, os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
return fd
|
||||
}
|
||||
|
||||
@@ -4839,8 +4838,8 @@ func requireOpenFile(t *testing.T, tmpDir string, pathName string, data []byte,
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
preopen := fsc.RootFS()
|
||||
|
||||
fd, errno := fsc.OpenFile(preopen, pathName, oflags, 0)
|
||||
require.Zero(t, errno)
|
||||
fd, err := fsc.OpenFile(preopen, pathName, oflags, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
return mod, fd, log, r
|
||||
}
|
||||
@@ -4868,12 +4867,12 @@ func Test_fdReaddir_dotEntriesHaveRealInodes(t *testing.T) {
|
||||
uint64(sys.FdPreopen), uint64(0), uint64(len(readDirTarget)))
|
||||
|
||||
// Open the directory, before writing files!
|
||||
fd, errno := fsc.OpenFile(preopen, readDirTarget, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fd, err := fsc.OpenFile(preopen, readDirTarget, os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
// get the real inode of the current directory
|
||||
st, errno := preopen.Stat(readDirTarget)
|
||||
require.Zero(t, errno)
|
||||
st, err := preopen.Stat(readDirTarget)
|
||||
require.NoError(t, err)
|
||||
dirents := []byte{1, 0, 0, 0, 0, 0, 0, 0} // d_next = 1
|
||||
dirents = append(dirents, u64.LeBytes(st.Ino)...) // d_ino
|
||||
dirents = append(dirents, 1, 0, 0, 0) // d_namlen = 1 character
|
||||
@@ -4881,8 +4880,8 @@ func Test_fdReaddir_dotEntriesHaveRealInodes(t *testing.T) {
|
||||
dirents = append(dirents, '.') // name
|
||||
|
||||
// get the real inode of the parent directory
|
||||
st, errno = preopen.Stat(".")
|
||||
require.Zero(t, errno)
|
||||
st, err = preopen.Stat(".")
|
||||
require.NoError(t, err)
|
||||
dirents = append(dirents, 2, 0, 0, 0, 0, 0, 0, 0) // d_next = 2
|
||||
dirents = append(dirents, u64.LeBytes(st.Ino)...) // d_ino
|
||||
dirents = append(dirents, 2, 0, 0, 0) // d_namlen = 2 characters
|
||||
@@ -4927,8 +4926,8 @@ func Test_fdReaddir_opened_file_written(t *testing.T) {
|
||||
uint64(sys.FdPreopen), uint64(0), uint64(len(dirName)))
|
||||
|
||||
// Open the directory, before writing files!
|
||||
dirFD, errno := fsc.OpenFile(preopen, dirName, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
dirFD, err := fsc.OpenFile(preopen, dirName, os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Then write a file to the directory.
|
||||
f, err := os.Create(joinPath(dirPath, "file"))
|
||||
@@ -4936,8 +4935,8 @@ func Test_fdReaddir_opened_file_written(t *testing.T) {
|
||||
defer f.Close()
|
||||
|
||||
// get the real inode of the current directory
|
||||
st, errno := preopen.Stat(dirName)
|
||||
require.Zero(t, errno)
|
||||
st, err := preopen.Stat(dirName)
|
||||
require.NoError(t, err)
|
||||
dirents := []byte{1, 0, 0, 0, 0, 0, 0, 0} // d_next = 1
|
||||
dirents = append(dirents, u64.LeBytes(st.Ino)...) // d_ino
|
||||
dirents = append(dirents, 1, 0, 0, 0) // d_namlen = 1 character
|
||||
@@ -4945,8 +4944,8 @@ func Test_fdReaddir_opened_file_written(t *testing.T) {
|
||||
dirents = append(dirents, '.') // name
|
||||
|
||||
// get the real inode of the parent directory
|
||||
st, errno = preopen.Stat(".")
|
||||
require.Zero(t, errno)
|
||||
st, err = preopen.Stat(".")
|
||||
require.NoError(t, err)
|
||||
dirents = append(dirents, 2, 0, 0, 0, 0, 0, 0, 0) // d_next = 2
|
||||
dirents = append(dirents, u64.LeBytes(st.Ino)...) // d_ino
|
||||
dirents = append(dirents, 2, 0, 0, 0) // d_namlen = 2 characters
|
||||
@@ -4954,8 +4953,8 @@ func Test_fdReaddir_opened_file_written(t *testing.T) {
|
||||
dirents = append(dirents, '.', '.') // name
|
||||
|
||||
// get the real inode of the file
|
||||
st, errno = platform.StatFile(f)
|
||||
require.Zero(t, errno)
|
||||
st, err = platform.StatFile(f)
|
||||
require.NoError(t, err)
|
||||
dirents = append(dirents, 3, 0, 0, 0, 0, 0, 0, 0) // d_next = 3
|
||||
dirents = append(dirents, u64.LeBytes(st.Ino)...) // d_ino
|
||||
dirents = append(dirents, 4, 0, 0, 0) // d_namlen = 4 characters
|
||||
|
||||
@@ -19,7 +19,7 @@ func Test_fdRead_shouldContinueRead(t *testing.T) {
|
||||
n, l uint32
|
||||
err error
|
||||
expectedOk bool
|
||||
expectedErrno syscall.Errno
|
||||
expectedErrno Errno
|
||||
}{
|
||||
{
|
||||
name: "break when nothing to read",
|
||||
@@ -66,13 +66,13 @@ func Test_fdRead_shouldContinueRead(t *testing.T) {
|
||||
{
|
||||
name: "return ErrnoIo on error on nothing to read",
|
||||
err: io.ErrClosedPipe,
|
||||
expectedErrno: syscall.EIO,
|
||||
expectedErrno: ErrnoIo,
|
||||
},
|
||||
{
|
||||
name: "return ErrnoIo on error on nothing read",
|
||||
l: 4,
|
||||
err: io.ErrClosedPipe,
|
||||
expectedErrno: syscall.EIO,
|
||||
expectedErrno: ErrnoIo,
|
||||
},
|
||||
{ // Special case, allows processing data before err
|
||||
name: "break on error on partial read",
|
||||
@@ -93,7 +93,7 @@ func Test_fdRead_shouldContinueRead(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ok, errno := fdRead_shouldContinueRead(tc.n, tc.l, tc.err)
|
||||
require.Equal(t, tc.expectedOk, ok)
|
||||
require.EqualErrno(t, tc.expectedErrno, errno)
|
||||
require.Equal(t, tc.expectedErrno, errno)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ func Test_lastDirents(t *testing.T) {
|
||||
f *sys.ReadDir
|
||||
cookie int64
|
||||
expectedDirents []*platform.Dirent
|
||||
expectedErrno syscall.Errno
|
||||
expectedErrno Errno
|
||||
}{
|
||||
{
|
||||
name: "no prior call",
|
||||
@@ -112,7 +112,7 @@ func Test_lastDirents(t *testing.T) {
|
||||
{
|
||||
name: "no prior call, but passed a cookie",
|
||||
cookie: 1,
|
||||
expectedErrno: syscall.EINVAL,
|
||||
expectedErrno: ErrnoInval,
|
||||
},
|
||||
{
|
||||
name: "cookie is negative",
|
||||
@@ -121,7 +121,7 @@ func Test_lastDirents(t *testing.T) {
|
||||
Dirents: testDirents,
|
||||
},
|
||||
cookie: -1,
|
||||
expectedErrno: syscall.EINVAL,
|
||||
expectedErrno: ErrnoInval,
|
||||
},
|
||||
{
|
||||
name: "cookie is greater than last d_next",
|
||||
@@ -130,7 +130,7 @@ func Test_lastDirents(t *testing.T) {
|
||||
Dirents: testDirents,
|
||||
},
|
||||
cookie: 5,
|
||||
expectedErrno: syscall.EINVAL,
|
||||
expectedErrno: ErrnoInval,
|
||||
},
|
||||
{
|
||||
name: "cookie is last pos",
|
||||
@@ -157,7 +157,7 @@ func Test_lastDirents(t *testing.T) {
|
||||
Dirents: testDirents,
|
||||
},
|
||||
cookie: 1,
|
||||
expectedErrno: syscall.ENOSYS, // not implemented
|
||||
expectedErrno: ErrnoNosys, // not implemented
|
||||
},
|
||||
{
|
||||
name: "read from the beginning (cookie=0)",
|
||||
@@ -179,7 +179,7 @@ func Test_lastDirents(t *testing.T) {
|
||||
f = &sys.ReadDir{}
|
||||
}
|
||||
entries, errno := lastDirents(f, tc.cookie)
|
||||
require.EqualErrno(t, tc.expectedErrno, errno)
|
||||
require.Equal(t, tc.expectedErrno, errno)
|
||||
require.Equal(t, tc.expectedDirents, entries)
|
||||
})
|
||||
}
|
||||
@@ -286,9 +286,9 @@ var (
|
||||
panic(err)
|
||||
}
|
||||
defer dir.Close()
|
||||
dirents, errno := platform.Readdir(dir, -1)
|
||||
if errno != 0 {
|
||||
panic(errno)
|
||||
dirents, err := platform.Readdir(dir, -1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return dirents
|
||||
}()
|
||||
|
||||
@@ -2,7 +2,6 @@ package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
@@ -18,20 +17,20 @@ 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 ErrnoInval.
|
||||
// - 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
|
||||
// The return value is ErrnoSuccess except the following error conditions:
|
||||
// - ErrnoInval: the parameters are invalid
|
||||
// - ErrnoNotsup: a parameters is valid, but not yet supported.
|
||||
// - ErrnoFault: there is not enough memory to read the subscriptions or
|
||||
// write results.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - Since the `out` pointer nests Errno, the result is always 0.
|
||||
// - Since the `out` pointer nests Errno, the result is always ErrnoSuccess.
|
||||
// - This is similar to `poll` in POSIX.
|
||||
//
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#poll_oneoff
|
||||
@@ -42,14 +41,14 @@ var pollOneoff = newHostFunc(
|
||||
"in", "out", "nsubscriptions", "result.nevents",
|
||||
)
|
||||
|
||||
func pollOneoffFn(ctx context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func pollOneoffFn(ctx context.Context, mod api.Module, params []uint64) Errno {
|
||||
in := uint32(params[0])
|
||||
out := uint32(params[1])
|
||||
nsubscriptions := uint32(params[2])
|
||||
resultNevents := uint32(params[3])
|
||||
|
||||
if nsubscriptions == 0 {
|
||||
return syscall.EINVAL
|
||||
return ErrnoInval
|
||||
}
|
||||
|
||||
mem := mod.Memory()
|
||||
@@ -57,17 +56,17 @@ func pollOneoffFn(ctx context.Context, mod api.Module, params []uint64) syscall.
|
||||
// Ensure capacity prior to the read loop to reduce error handling.
|
||||
inBuf, ok := mem.Read(in, nsubscriptions*48)
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return ErrnoFault
|
||||
}
|
||||
outBuf, ok := mem.Read(out, nsubscriptions*32)
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return ErrnoFault
|
||||
}
|
||||
|
||||
// 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 ErrnoFault
|
||||
}
|
||||
|
||||
// Loop through all subscriptions and write their output.
|
||||
@@ -79,7 +78,7 @@ func pollOneoffFn(ctx context.Context, mod api.Module, params []uint64) syscall.
|
||||
outOffset := i * 32
|
||||
|
||||
eventType := inBuf[inOffset+8] // +8 past userdata
|
||||
var errno syscall.Errno // errno for this specific event (1-byte)
|
||||
var errno Errno // errno for this specific event (1-byte)
|
||||
switch eventType {
|
||||
case EventTypeClock: // handle later
|
||||
// +8 past userdata +8 contents_offset
|
||||
@@ -88,23 +87,23 @@ func pollOneoffFn(ctx context.Context, mod api.Module, params []uint64) syscall.
|
||||
// +8 past userdata +8 contents_offset
|
||||
errno = processFDEvent(mod, eventType, inBuf[inOffset+8+8:])
|
||||
default:
|
||||
return syscall.EINVAL
|
||||
return ErrnoInval
|
||||
}
|
||||
|
||||
// Write the event corresponding to the processed subscription.
|
||||
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-event-struct
|
||||
copy(outBuf, inBuf[inOffset:inOffset+8]) // userdata
|
||||
outBuf[outOffset+8] = byte(ToErrno(errno)) // uint16, but safe as < 255
|
||||
copy(outBuf, inBuf[inOffset:inOffset+8]) // userdata
|
||||
outBuf[outOffset+8] = byte(errno) // uint16, but safe as < 255
|
||||
outBuf[outOffset+9] = 0
|
||||
le.PutUint32(outBuf[outOffset+10:], uint32(eventType))
|
||||
// TODO: When FD events are supported, write outOffset+16
|
||||
}
|
||||
return 0
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
// 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(_ context.Context, mod api.Module, inBuf []byte) syscall.Errno {
|
||||
func processClockEvent(_ context.Context, mod api.Module, inBuf []byte) Errno {
|
||||
_ /* ID */ = le.Uint32(inBuf[0:8]) // See below
|
||||
timeout := le.Uint64(inBuf[8:16]) // nanos if relative
|
||||
_ /* precision */ = le.Uint64(inBuf[16:24]) // Unused
|
||||
@@ -114,9 +113,9 @@ func processClockEvent(_ context.Context, mod api.Module, inBuf []byte) syscall.
|
||||
switch flags {
|
||||
case 0: // relative time
|
||||
case 1: // subscription_clock_abstime
|
||||
return syscall.ENOTSUP
|
||||
return ErrnoNotsup
|
||||
default: // subclockflags has only one flag defined.
|
||||
return syscall.EINVAL
|
||||
return ErrnoInval
|
||||
}
|
||||
|
||||
// https://linux.die.net/man/3/clock_settime says relative timers are
|
||||
@@ -125,29 +124,29 @@ func processClockEvent(_ context.Context, mod api.Module, inBuf []byte) syscall.
|
||||
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
sysCtx.Nanosleep(int64(timeout))
|
||||
return 0
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
// processFDEvent returns a validation error or syscall.ENOTSUP as file or socket
|
||||
// processFDEvent returns a validation error or ErrnoNotsup as file or socket
|
||||
// subscriptions are not yet supported.
|
||||
func processFDEvent(mod api.Module, eventType byte, inBuf []byte) syscall.Errno {
|
||||
func processFDEvent(mod api.Module, eventType byte, inBuf []byte) Errno {
|
||||
fd := le.Uint32(inBuf)
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
// Choose the best error, which falls back to unsupported, until we support
|
||||
// files.
|
||||
errno := syscall.ENOTSUP
|
||||
errno := ErrnoNotsup
|
||||
if eventType == EventTypeFdRead {
|
||||
if _, ok := fsc.LookupFile(fd); ok {
|
||||
// If fd is a pipe, IsTerminal is false.
|
||||
if platform.IsTerminal(uintptr(fd)) {
|
||||
errno = syscall.EBADF
|
||||
errno = ErrnoBadf
|
||||
}
|
||||
} else {
|
||||
errno = syscall.EBADF
|
||||
errno = ErrnoBadf
|
||||
}
|
||||
} else if eventType == EventTypeFdWrite && internalsys.WriterForFile(fsc, fd) == nil {
|
||||
errno = syscall.EBADF
|
||||
errno = ErrnoBadf
|
||||
}
|
||||
|
||||
return errno
|
||||
|
||||
@@ -3,7 +3,6 @@ package wasi_snapshot_preview1
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
|
||||
@@ -21,8 +20,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
|
||||
// - ErrnoFault: `buf` or `bufLen` point to an offset out of memory
|
||||
// - ErrnoIo: a file system error
|
||||
//
|
||||
// For example, if underlying random source was seeded like
|
||||
// `rand.NewSource(42)`, we expect api.Memory to contain:
|
||||
@@ -36,20 +35,20 @@ import (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-bufLen-size---errno
|
||||
var randomGet = newHostFunc(RandomGetName, randomGetFn, []api.ValueType{i32, i32}, "buf", "buf_len")
|
||||
|
||||
func randomGetFn(_ context.Context, mod api.Module, params []uint64) syscall.Errno {
|
||||
func randomGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
sysCtx := mod.(*wasm.CallContext).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 ErrnoFault
|
||||
}
|
||||
|
||||
// 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 ErrnoIo
|
||||
}
|
||||
|
||||
return 0
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
. "github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
|
||||
@@ -15,8 +14,8 @@ import (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sched_yield---errno
|
||||
var schedYield = newHostFunc(SchedYieldName, schedYieldFn, nil)
|
||||
|
||||
func schedYieldFn(_ context.Context, mod api.Module, _ []uint64) syscall.Errno {
|
||||
func schedYieldFn(_ context.Context, mod api.Module, _ []uint64) Errno {
|
||||
sysCtx := mod.(*wasm.CallContext).Sys
|
||||
sysCtx.Osyield()
|
||||
return 0
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package wasi_snapshot_preview1
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
@@ -219,18 +218,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) 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 ErrnoFault
|
||||
}
|
||||
bytesBuf, ok := mem.Read(bytes, bytesLen)
|
||||
if !ok {
|
||||
return syscall.EFAULT
|
||||
return ErrnoFault
|
||||
}
|
||||
|
||||
// Loop through the values, first writing the location of its data to
|
||||
@@ -253,7 +252,7 @@ func writeOffsetsAndNullTerminatedValues(mem api.Memory, values [][]byte, offset
|
||||
bI++
|
||||
}
|
||||
|
||||
return 0
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
func newHostFunc(
|
||||
@@ -275,12 +274,12 @@ 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) Errno
|
||||
|
||||
// Call implements the same method as documented on api.GoModuleFunction.
|
||||
func (f wasiFunc) Call(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
// Write the result back onto the stack
|
||||
stack[0] = uint64(ToErrno(f(ctx, mod, stack)))
|
||||
stack[0] = uint64(f(ctx, mod, stack))
|
||||
}
|
||||
|
||||
// stubFunction stubs for GrainLang per #271.
|
||||
|
||||
@@ -192,9 +192,9 @@ func Benchmark_fdReaddir(b *testing.B) {
|
||||
|
||||
// Open the root directory as a file-descriptor.
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
fd, errno := fsc.OpenFile(fsc.RootFS(), ".", os.O_RDONLY, 0)
|
||||
if errno != 0 {
|
||||
b.Fatal(errno)
|
||||
fd, err := fsc.OpenFile(fsc.RootFS(), ".", os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
f, ok := fsc.LookupFile(fd)
|
||||
if !ok {
|
||||
@@ -216,8 +216,8 @@ func Benchmark_fdReaddir(b *testing.B) {
|
||||
if err = f.File.Close(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if f.File, errno = fsc.RootFS().OpenFile(".", os.O_RDONLY, 0); errno != 0 {
|
||||
b.Fatal(errno)
|
||||
if f.File, err = fsc.RootFS().OpenFile(".", os.O_RDONLY, 0); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
f.ReadDir = nil
|
||||
|
||||
@@ -318,9 +318,9 @@ func Benchmark_pathFilestat(b *testing.B) {
|
||||
fd := sys.FdPreopen
|
||||
if bc.fd != sys.FdPreopen {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
fd, errno := fsc.OpenFile(fsc.RootFS(), "zig", os.O_RDONLY, 0)
|
||||
if errno != 0 {
|
||||
b.Fatal(errno)
|
||||
fd, err = fsc.OpenFile(fsc.RootFS(), "zig", os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer fsc.CloseFile(fd) //nolint
|
||||
}
|
||||
|
||||
@@ -100,9 +100,9 @@ func WriteTestFiles(tmpDir string) (err error) {
|
||||
}
|
||||
|
||||
// os.Stat uses GetFileInformationByHandle internally.
|
||||
st, errno := platform.Stat(path)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
var st platform.Stat_t
|
||||
if st, err = platform.Stat(path); err != nil {
|
||||
return err
|
||||
}
|
||||
if st.Mtim == info.ModTime().UnixNano() {
|
||||
return nil // synced!
|
||||
|
||||
@@ -30,8 +30,6 @@ var (
|
||||
ErrnoBadf = &Errno{"EBADF"}
|
||||
// ErrnoExist File exists.
|
||||
ErrnoExist = &Errno{"EEXIST"}
|
||||
// ErrnoFault Bad address.
|
||||
ErrnoFault = &Errno{"EFAULT"}
|
||||
// ErrnoIntr Interrupted function.
|
||||
ErrnoIntr = &Errno{"EINTR"}
|
||||
// ErrnoInval Invalid argument.
|
||||
@@ -79,8 +77,6 @@ func ToErrno(err error) *Errno {
|
||||
return ErrnoBadf
|
||||
case syscall.EEXIST:
|
||||
return ErrnoExist
|
||||
case syscall.EFAULT:
|
||||
return ErrnoFault
|
||||
case syscall.EINTR:
|
||||
return ErrnoIntr
|
||||
case syscall.EINVAL:
|
||||
|
||||
@@ -39,11 +39,6 @@ func TestToErrno(t *testing.T) {
|
||||
input: syscall.EEXIST,
|
||||
expected: ErrnoExist,
|
||||
},
|
||||
{
|
||||
name: "syscall.EFAULT",
|
||||
input: syscall.EFAULT,
|
||||
expected: ErrnoFault,
|
||||
},
|
||||
{
|
||||
name: "syscall.EINTR",
|
||||
input: syscall.EINTR,
|
||||
|
||||
@@ -110,9 +110,9 @@ func (o *jsfsOpen) invoke(ctx context.Context, mod api.Module, args ...interface
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
fd, errno := fsc.OpenFile(fsc.RootFS(), path, int(flags), perm)
|
||||
fd, err := fsc.OpenFile(fsc.RootFS(), path, int(flags), perm)
|
||||
|
||||
return callback.invoke(ctx, mod, goos.RefJsfs, maybeError(errno), fd) // note: error first
|
||||
return callback.invoke(ctx, mod, goos.RefJsfs, err, fd) // note: error first
|
||||
}
|
||||
|
||||
// jsfsStat implements jsFn for syscall.Stat
|
||||
@@ -134,8 +134,8 @@ func (s *jsfsStat) invoke(ctx context.Context, mod api.Module, args ...interface
|
||||
func syscallStat(mod api.Module, path string) (*jsSt, error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
if st, errno := fsc.RootFS().Stat(path); errno != 0 {
|
||||
return nil, errno
|
||||
if st, err := fsc.RootFS().Stat(path); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return newJsSt(st), nil
|
||||
}
|
||||
@@ -161,8 +161,8 @@ func (l *jsfsLstat) invoke(ctx context.Context, mod api.Module, args ...interfac
|
||||
func syscallLstat(mod api.Module, path string) (*jsSt, error) {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
if st, errno := fsc.RootFS().Lstat(path); errno != 0 {
|
||||
return nil, errno
|
||||
if st, err := fsc.RootFS().Lstat(path); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return newJsSt(st), nil
|
||||
}
|
||||
@@ -191,7 +191,7 @@ func syscallFstat(fsc *internalsys.FSContext, fd uint32) (*jsSt, error) {
|
||||
}
|
||||
|
||||
if st, err := f.Stat(); err != nil {
|
||||
return nil, platform.UnwrapOSError(err)
|
||||
return nil, err
|
||||
} else {
|
||||
return newJsSt(st), nil
|
||||
}
|
||||
@@ -222,9 +222,9 @@ func (jsfsClose) invoke(ctx context.Context, mod api.Module, args ...interface{}
|
||||
fd := goos.ValueToUint32(args[0])
|
||||
callback := args[1].(funcWrapper)
|
||||
|
||||
errno := fsc.CloseFile(fd)
|
||||
err := fsc.CloseFile(fd)
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsRead implements jsFn for syscall.Read and syscall.Pread, called by
|
||||
@@ -345,14 +345,14 @@ func syscallReaddir(_ context.Context, mod api.Module, name string) (*objectArra
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
// don't allocate a file descriptor
|
||||
f, errno := fsc.RootFS().OpenFile(name, os.O_RDONLY, 0)
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
f, err := fsc.RootFS().OpenFile(name, os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close() //nolint
|
||||
|
||||
if names, errno := platform.Readdirnames(f, -1); errno != 0 {
|
||||
return nil, errno
|
||||
if names, err := platform.Readdirnames(f, -1); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
entries := make([]interface{}, 0, len(names))
|
||||
for _, e := range names {
|
||||
@@ -378,16 +378,16 @@ func (m *jsfsMkdir) invoke(ctx context.Context, mod api.Module, args ...interfac
|
||||
root := fsc.RootFS()
|
||||
|
||||
var fd uint32
|
||||
var errno syscall.Errno
|
||||
var err error
|
||||
// We need at least read access to open the file descriptor
|
||||
if perm == 0 {
|
||||
perm = 0o0500
|
||||
}
|
||||
if errno = root.Mkdir(path, perm); errno == 0 {
|
||||
fd, errno = fsc.OpenFile(root, path, os.O_RDONLY, 0)
|
||||
if err = root.Mkdir(path, perm); err == nil {
|
||||
fd, err = fsc.OpenFile(root, path, os.O_RDONLY, 0)
|
||||
}
|
||||
|
||||
return callback.invoke(ctx, mod, goos.RefJsfs, maybeError(errno), fd) // note: error first
|
||||
return callback.invoke(ctx, mod, goos.RefJsfs, err, fd) // note: error first
|
||||
}
|
||||
|
||||
// jsfsRmdir implements jsFn for the following
|
||||
@@ -402,9 +402,9 @@ func (r *jsfsRmdir) invoke(ctx context.Context, mod api.Module, args ...interfac
|
||||
callback := args[1].(funcWrapper)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
errno := fsc.RootFS().Rmdir(path)
|
||||
err := fsc.RootFS().Rmdir(path)
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsRename implements jsFn for the following
|
||||
@@ -421,9 +421,9 @@ func (r *jsfsRename) invoke(ctx context.Context, mod api.Module, args ...interfa
|
||||
callback := args[2].(funcWrapper)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
errno := fsc.RootFS().Rename(from, to)
|
||||
err := fsc.RootFS().Rename(from, to)
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsUnlink implements jsFn for the following
|
||||
@@ -438,9 +438,9 @@ func (u *jsfsUnlink) invoke(ctx context.Context, mod api.Module, args ...interfa
|
||||
callback := args[1].(funcWrapper)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
errno := fsc.RootFS().Unlink(path)
|
||||
err := fsc.RootFS().Unlink(path)
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsUtimes implements jsFn for the following
|
||||
@@ -460,9 +460,9 @@ func (u *jsfsUtimes) invoke(ctx context.Context, mod api.Module, args ...interfa
|
||||
times := [2]syscall.Timespec{
|
||||
syscall.NsecToTimespec(atimeSec * 1e9), syscall.NsecToTimespec(mtimeSec * 1e9),
|
||||
}
|
||||
errno := fsc.RootFS().Utimens(path, ×, true)
|
||||
err := fsc.RootFS().Utimens(path, ×, true)
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsChmod implements jsFn for the following
|
||||
@@ -478,9 +478,9 @@ func (c *jsfsChmod) invoke(ctx context.Context, mod api.Module, args ...interfac
|
||||
callback := args[2].(funcWrapper)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
errno := fsc.RootFS().Chmod(path, mode)
|
||||
err := fsc.RootFS().Chmod(path, mode)
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsFchmod implements jsFn for the following
|
||||
@@ -495,16 +495,16 @@ func (jsfsFchmod) invoke(ctx context.Context, mod api.Module, args ...interface{
|
||||
|
||||
// Check to see if the file descriptor is available
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
var errno syscall.Errno
|
||||
var err error
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
errno = syscall.EBADF
|
||||
err = syscall.EBADF
|
||||
} else if chmodFile, ok := f.File.(chmodFile); !ok {
|
||||
errno = syscall.EBADF // possibly a fake file
|
||||
err = syscall.EBADF // possibly a fake file
|
||||
} else {
|
||||
errno = platform.UnwrapOSError(chmodFile.Chmod(mode))
|
||||
err = chmodFile.Chmod(mode)
|
||||
}
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsChown implements jsFn for the following
|
||||
@@ -521,9 +521,9 @@ func (c *jsfsChown) invoke(ctx context.Context, mod api.Module, args ...interfac
|
||||
callback := args[3].(funcWrapper)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
errno := fsc.RootFS().Chown(path, int(uid), int(gid))
|
||||
err := fsc.RootFS().Chown(path, int(uid), int(gid))
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsFchown implements jsFn for the following
|
||||
@@ -539,14 +539,14 @@ func (jsfsFchown) invoke(ctx context.Context, mod api.Module, args ...interface{
|
||||
|
||||
// Check to see if the file descriptor is available
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
var errno syscall.Errno
|
||||
var err error
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
errno = syscall.EBADF
|
||||
err = syscall.EBADF
|
||||
} else {
|
||||
errno = platform.ChownFile(f.File, int(uid), int(gid))
|
||||
err = platform.ChownFile(f.File, int(uid), int(gid))
|
||||
}
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsLchown implements jsFn for the following
|
||||
@@ -563,9 +563,9 @@ func (l *jsfsLchown) invoke(ctx context.Context, mod api.Module, args ...interfa
|
||||
callback := args[3].(funcWrapper)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
errno := fsc.RootFS().Lchown(path, int(uid), int(gid))
|
||||
err := fsc.RootFS().Lchown(path, int(uid), int(gid))
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsTruncate implements jsFn for the following
|
||||
@@ -581,9 +581,9 @@ func (t *jsfsTruncate) invoke(ctx context.Context, mod api.Module, args ...inter
|
||||
callback := args[2].(funcWrapper)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
errno := fsc.RootFS().Truncate(path, length)
|
||||
err := fsc.RootFS().Truncate(path, length)
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsFtruncate implements jsFn for the following
|
||||
@@ -598,16 +598,16 @@ func (jsfsFtruncate) invoke(ctx context.Context, mod api.Module, args ...interfa
|
||||
|
||||
// Check to see if the file descriptor is available
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
var errno syscall.Errno
|
||||
var err error
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
errno = syscall.EBADF
|
||||
err = syscall.EBADF
|
||||
} else if truncateFile, ok := f.File.(truncateFile); !ok {
|
||||
errno = syscall.EBADF // possibly a fake file
|
||||
err = syscall.EBADF // possibly a fake file
|
||||
} else {
|
||||
errno = platform.UnwrapOSError(truncateFile.Truncate(length))
|
||||
err = truncateFile.Truncate(length)
|
||||
}
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsReadlink implements jsFn for syscall.Readlink
|
||||
@@ -622,9 +622,9 @@ func (r *jsfsReadlink) invoke(ctx context.Context, mod api.Module, args ...inter
|
||||
callback := args[1].(funcWrapper)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
dst, errno := fsc.RootFS().Readlink(path)
|
||||
dst, err := fsc.RootFS().Readlink(path)
|
||||
|
||||
return callback.invoke(ctx, mod, goos.RefJsfs, maybeError(errno), dst) // note: error first
|
||||
return callback.invoke(ctx, mod, goos.RefJsfs, err, dst) // note: error first
|
||||
}
|
||||
|
||||
// jsfsLink implements jsFn for the following
|
||||
@@ -641,9 +641,9 @@ func (l *jsfsLink) invoke(ctx context.Context, mod api.Module, args ...interface
|
||||
callback := args[2].(funcWrapper)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
errno := fsc.RootFS().Link(path, link)
|
||||
err := fsc.RootFS().Link(path, link)
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsSymlink implements jsFn for the following
|
||||
@@ -659,9 +659,9 @@ func (s *jsfsSymlink) invoke(ctx context.Context, mod api.Module, args ...interf
|
||||
callback := args[2].(funcWrapper)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
errno := fsc.RootFS().Symlink(dst, link)
|
||||
err := fsc.RootFS().Symlink(dst, link)
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsfsFsync implements jsFn for the following
|
||||
@@ -675,16 +675,16 @@ func (jsfsFsync) invoke(ctx context.Context, mod api.Module, args ...interface{}
|
||||
|
||||
// Check to see if the file descriptor is available
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
var errno syscall.Errno
|
||||
var err error
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
errno = syscall.EBADF
|
||||
err = syscall.EBADF
|
||||
} else if syncFile, ok := f.File.(syncFile); !ok {
|
||||
errno = syscall.EBADF // possibly a fake file
|
||||
err = syscall.EBADF // possibly a fake file
|
||||
} else {
|
||||
errno = platform.UnwrapOSError(syncFile.Sync())
|
||||
err = syncFile.Sync()
|
||||
}
|
||||
|
||||
return jsfsInvoke(ctx, mod, callback, errno)
|
||||
return jsfsInvoke(ctx, mod, callback, err)
|
||||
}
|
||||
|
||||
// jsSt is pre-parsed from fs_js.go setStat to avoid thrashing
|
||||
@@ -751,13 +751,6 @@ 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) {
|
||||
return callback.invoke(ctx, mod, goos.RefJsfs, maybeError(err), err == 0) // note: error first
|
||||
}
|
||||
|
||||
func maybeError(errno syscall.Errno) error {
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
func jsfsInvoke(ctx context.Context, mod api.Module, callback funcWrapper, err error) (interface{}, error) {
|
||||
return callback.invoke(ctx, mod, goos.RefJsfs, err, err == nil) // note: error first
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func Benchmark_UtimensFile(b *testing.B) {
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if err := UtimensFile(f, times); err != 0 {
|
||||
if err := UtimensFile(f, times); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,22 +8,20 @@ import (
|
||||
|
||||
// Chown is like os.Chown, except it returns a syscall.Errno, not a
|
||||
// fs.PathError. For example, this returns syscall.ENOENT if the path doesn't
|
||||
// exist. A syscall.Errno of zero is success.
|
||||
// exist. See https://linux.die.net/man/3/chown
|
||||
//
|
||||
// Note: This always returns syscall.ENOSYS on windows.
|
||||
// See https://linux.die.net/man/3/chown
|
||||
func Chown(path string, uid, gid int) syscall.Errno {
|
||||
func Chown(path string, uid, gid int) error {
|
||||
err := os.Chown(path, uid, gid)
|
||||
return UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Lchown is like os.Lchown, except it returns a syscall.Errno, not a
|
||||
// fs.PathError. For example, this returns syscall.ENOENT if the path doesn't
|
||||
// exist. A syscall.Errno of zero is success.
|
||||
// exist. See https://linux.die.net/man/3/lchown
|
||||
//
|
||||
// Note: This always returns syscall.ENOSYS on windows.
|
||||
// See https://linux.die.net/man/3/lchown
|
||||
func Lchown(path string, uid, gid int) syscall.Errno {
|
||||
func Lchown(path string, uid, gid int) error {
|
||||
err := os.Lchown(path, uid, gid)
|
||||
return UnwrapOSError(err)
|
||||
}
|
||||
@@ -33,9 +31,10 @@ func Lchown(path string, uid, gid int) syscall.Errno {
|
||||
// or directory was closed. See https://linux.die.net/man/3/fchown
|
||||
//
|
||||
// Note: This always returns syscall.ENOSYS on windows.
|
||||
func ChownFile(f fs.File, uid, gid int) syscall.Errno {
|
||||
func ChownFile(f fs.File, uid, gid int) error {
|
||||
if f, ok := f.(fdFile); ok {
|
||||
return fchown(f.Fd(), uid, gid)
|
||||
err := fchown(f.Fd(), uid, gid)
|
||||
return UnwrapOSError(err)
|
||||
}
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
@@ -4,6 +4,6 @@ package platform
|
||||
|
||||
import "syscall"
|
||||
|
||||
func fchown(fd uintptr, uid, gid int) syscall.Errno {
|
||||
return UnwrapOSError(syscall.Fchown(int(fd), uid, gid))
|
||||
func fchown(fd uintptr, uid, gid int) error {
|
||||
return syscall.Fchown(int(fd), uid, gid)
|
||||
}
|
||||
|
||||
@@ -17,10 +17,8 @@ func TestChown(t *testing.T) {
|
||||
|
||||
dir := path.Join(tmpDir, "dir")
|
||||
require.NoError(t, os.Mkdir(dir, 0o0777))
|
||||
|
||||
dirF, errno := OpenFile(dir, syscall.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
|
||||
dirF, err := OpenFile(dir, syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
dirStat, err := dirF.Stat()
|
||||
require.NoError(t, err)
|
||||
dirSys := dirStat.Sys().(*syscall.Stat_t)
|
||||
@@ -32,12 +30,12 @@ func TestChown(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("-1 parameters means leave alone", func(t *testing.T) {
|
||||
require.Zero(t, Chown(dir, -1, -1))
|
||||
require.NoError(t, Chown(dir, -1, -1))
|
||||
checkUidGid(t, dir, dirSys.Uid, dirSys.Gid)
|
||||
})
|
||||
|
||||
t.Run("change gid, but not uid", func(t *testing.T) {
|
||||
require.Zero(t, Chown(dir, -1, gid))
|
||||
require.NoError(t, Chown(dir, -1, gid))
|
||||
checkUidGid(t, dir, dirSys.Uid, uint32(gid))
|
||||
})
|
||||
|
||||
@@ -46,11 +44,11 @@ func TestChown(t *testing.T) {
|
||||
g := g
|
||||
t.Run(fmt.Sprintf("change to gid %d", g), func(t *testing.T) {
|
||||
// Test using our Chown
|
||||
require.Zero(t, Chown(dir, -1, g))
|
||||
require.NoError(t, Chown(dir, -1, g))
|
||||
checkUidGid(t, dir, dirSys.Uid, uint32(g))
|
||||
|
||||
// Revert back with os.File.Chown
|
||||
require.NoError(t, dirF.(*os.File).Chown(-1, gid))
|
||||
require.NoError(t, dirF.Chown(-1, gid))
|
||||
checkUidGid(t, dir, dirSys.Uid, uint32(gid))
|
||||
})
|
||||
}
|
||||
@@ -65,13 +63,10 @@ func TestChownFile(t *testing.T) {
|
||||
|
||||
dir := path.Join(tmpDir, "dir")
|
||||
require.NoError(t, os.Mkdir(dir, 0o0777))
|
||||
|
||||
dirF, errno := OpenFile(dir, syscall.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
|
||||
dirF, err := OpenFile(dir, syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
dirStat, err := dirF.Stat()
|
||||
require.NoError(t, err)
|
||||
|
||||
dirSys := dirStat.Sys().(*syscall.Stat_t)
|
||||
|
||||
// Similar to TestChownFile in os_unix_test.go, we can't expect to change
|
||||
@@ -81,12 +76,12 @@ func TestChownFile(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("-1 parameters means leave alone", func(t *testing.T) {
|
||||
require.Zero(t, ChownFile(dirF, -1, -1))
|
||||
require.NoError(t, ChownFile(dirF, -1, -1))
|
||||
checkUidGid(t, dir, dirSys.Uid, dirSys.Gid)
|
||||
})
|
||||
|
||||
t.Run("change gid, but not uid", func(t *testing.T) {
|
||||
require.Zero(t, ChownFile(dirF, -1, gid))
|
||||
require.NoError(t, ChownFile(dirF, -1, gid))
|
||||
checkUidGid(t, dir, dirSys.Uid, uint32(gid))
|
||||
})
|
||||
|
||||
@@ -95,11 +90,11 @@ func TestChownFile(t *testing.T) {
|
||||
g := g
|
||||
t.Run(fmt.Sprintf("change to gid %d", g), func(t *testing.T) {
|
||||
// Test using our ChownFile
|
||||
require.Zero(t, ChownFile(dirF, -1, g))
|
||||
require.NoError(t, ChownFile(dirF, -1, g))
|
||||
checkUidGid(t, dir, dirSys.Uid, uint32(g))
|
||||
|
||||
// Revert back with os.File.Chown
|
||||
require.NoError(t, dirF.(*os.File).Chown(-1, gid))
|
||||
require.NoError(t, dirF.Chown(-1, gid))
|
||||
checkUidGid(t, dir, dirSys.Uid, uint32(gid))
|
||||
})
|
||||
}
|
||||
@@ -115,24 +110,18 @@ func TestLchown(t *testing.T) {
|
||||
|
||||
dir := path.Join(tmpDir, "dir")
|
||||
require.NoError(t, os.Mkdir(dir, 0o0777))
|
||||
|
||||
dirF, errno := OpenFile(dir, syscall.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
|
||||
dirF, err := OpenFile(dir, syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
dirStat, err := dirF.Stat()
|
||||
require.NoError(t, err)
|
||||
|
||||
dirSys := dirStat.Sys().(*syscall.Stat_t)
|
||||
|
||||
link := path.Join(tmpDir, "link")
|
||||
require.NoError(t, os.Symlink(dir, link))
|
||||
|
||||
linkF, errno := OpenFile(link, syscall.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
|
||||
linkF, err := OpenFile(link, syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
linkStat, err := linkF.Stat()
|
||||
require.NoError(t, err)
|
||||
|
||||
linkSys := linkStat.Sys().(*syscall.Stat_t)
|
||||
|
||||
// Similar to TestLchown in os_unix_test.go, we can't expect to change
|
||||
@@ -142,12 +131,12 @@ func TestLchown(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("-1 parameters means leave alone", func(t *testing.T) {
|
||||
require.Zero(t, Lchown(link, -1, -1))
|
||||
require.NoError(t, Lchown(link, -1, -1))
|
||||
checkUidGid(t, link, linkSys.Uid, linkSys.Gid)
|
||||
})
|
||||
|
||||
t.Run("change gid, but not uid", func(t *testing.T) {
|
||||
require.Zero(t, Chown(dir, -1, gid))
|
||||
require.NoError(t, Chown(dir, -1, gid))
|
||||
checkUidGid(t, link, linkSys.Uid, uint32(gid))
|
||||
// Make sure the target didn't change.
|
||||
checkUidGid(t, dir, dirSys.Uid, dirSys.Gid)
|
||||
@@ -158,7 +147,7 @@ func TestLchown(t *testing.T) {
|
||||
g := g
|
||||
t.Run(fmt.Sprintf("change to gid %d", g), func(t *testing.T) {
|
||||
// Test using our Lchown
|
||||
require.Zero(t, Lchown(link, -1, g))
|
||||
require.NoError(t, Lchown(link, -1, g))
|
||||
checkUidGid(t, link, linkSys.Uid, uint32(g))
|
||||
// Make sure the target didn't change.
|
||||
checkUidGid(t, dir, dirSys.Uid, dirSys.Gid)
|
||||
|
||||
@@ -6,6 +6,6 @@ import "syscall"
|
||||
|
||||
// fchown is not supported on windows. For example, syscall.Fchown returns
|
||||
// syscall.EWINDOWS, which is the same as syscall.ENOSYS.
|
||||
func fchown(fd uintptr, uid, gid int) syscall.Errno {
|
||||
func fchown(fd uintptr, uid, gid int) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
@@ -16,22 +16,23 @@ import (
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success.
|
||||
// If the error is non-nil, it is a syscall.Errno. io.EOF is not returned
|
||||
// because implementations return that value inconsistently.
|
||||
//
|
||||
// For portability reasons, no error is returned on io.EOF, when the file is
|
||||
// closed or removed while open.
|
||||
// For portability reasons, no error is returned when the file is closed or
|
||||
// removed while open.
|
||||
// See https://github.com/ziglang/zig/blob/0.10.1/lib/std/fs.zig#L635-L637
|
||||
func Readdirnames(f fs.File, n int) (names []string, errno syscall.Errno) {
|
||||
func Readdirnames(f fs.File, n int) (names []string, err error) {
|
||||
switch f := f.(type) {
|
||||
case readdirnamesFile:
|
||||
var err error
|
||||
names, err = f.Readdirnames(n)
|
||||
if errno = adjustReaddirErr(err); errno != 0 {
|
||||
if err = adjustReaddirErr(err); err != nil {
|
||||
return
|
||||
}
|
||||
case fs.ReadDirFile:
|
||||
entries, err := f.ReadDir(n)
|
||||
if errno = adjustReaddirErr(err); errno != 0 {
|
||||
var entries []fs.DirEntry
|
||||
entries, err = f.ReadDir(n)
|
||||
if err = adjustReaddirErr(err); err != nil {
|
||||
return
|
||||
}
|
||||
names = make([]string, 0, len(entries))
|
||||
@@ -39,8 +40,9 @@ func Readdirnames(f fs.File, n int) (names []string, errno syscall.Errno) {
|
||||
names = append(names, e.Name())
|
||||
}
|
||||
default:
|
||||
errno = syscall.ENOTDIR
|
||||
err = syscall.ENOTDIR
|
||||
}
|
||||
err = UnwrapOSError(err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -81,18 +83,20 @@ func (d *Dirent) IsDir() bool {
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// A zero syscall.Errno is success.
|
||||
// If the error is non-nil, it is a syscall.Errno. io.EOF is not returned
|
||||
// because implementations return that value inconsistently.
|
||||
//
|
||||
// For portability reasons, no error is returned on io.EOF, when the file is
|
||||
// closed or removed while open.
|
||||
// For portability reasons, no error is returned when the file is closed or
|
||||
// removed while open.
|
||||
// See https://github.com/ziglang/zig/blob/0.10.1/lib/std/fs.zig#L635-L637
|
||||
func Readdir(f fs.File, n int) (dirents []*Dirent, errno syscall.Errno) {
|
||||
func Readdir(f fs.File, n int) (dirents []*Dirent, err error) {
|
||||
// ^^ case format is to match POSIX and similar to os.File.Readdir
|
||||
|
||||
switch f := f.(type) {
|
||||
case readdirFile:
|
||||
fis, e := f.Readdir(n)
|
||||
if errno = adjustReaddirErr(e); errno != 0 {
|
||||
var fis []fs.FileInfo
|
||||
fis, err = f.Readdir(n)
|
||||
if err = adjustReaddirErr(err); err != nil {
|
||||
return
|
||||
}
|
||||
dirents = make([]*Dirent, 0, len(fis))
|
||||
@@ -100,14 +104,15 @@ func Readdir(f fs.File, n int) (dirents []*Dirent, errno syscall.Errno) {
|
||||
// linux/darwin won't have to fan out to lstat, but windows will.
|
||||
var ino uint64
|
||||
for _, t := range fis {
|
||||
if ino, errno = inoFromFileInfo(f, t); errno != 0 {
|
||||
if ino, err = inoFromFileInfo(f, t); err != nil {
|
||||
return
|
||||
}
|
||||
dirents = append(dirents, &Dirent{Name: t.Name(), Ino: ino, Type: t.Mode().Type()})
|
||||
}
|
||||
case fs.ReadDirFile:
|
||||
entries, e := f.ReadDir(n)
|
||||
if errno = adjustReaddirErr(e); errno != 0 {
|
||||
var entries []fs.DirEntry
|
||||
entries, err = f.ReadDir(n)
|
||||
if err = adjustReaddirErr(err); err != nil {
|
||||
return
|
||||
}
|
||||
dirents = make([]*Dirent, 0, len(entries))
|
||||
@@ -116,23 +121,23 @@ func Readdir(f fs.File, n int) (dirents []*Dirent, errno syscall.Errno) {
|
||||
dirents = append(dirents, &Dirent{Name: e.Name(), Type: e.Type()})
|
||||
}
|
||||
default:
|
||||
errno = syscall.ENOTDIR
|
||||
err = syscall.ENOTDIR
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func adjustReaddirErr(err error) syscall.Errno {
|
||||
func adjustReaddirErr(err error) error {
|
||||
if err == io.EOF {
|
||||
return 0 // e.g. Readdir on darwin returns io.EOF, but linux doesn't.
|
||||
} else if errno := UnwrapOSError(err); errno != 0 {
|
||||
return nil // e.g. Readdir on darwin returns io.EOF, but linux doesn't.
|
||||
} else if err = UnwrapOSError(err); err != nil {
|
||||
// Ignore errors when the file was closed or removed.
|
||||
switch errno {
|
||||
switch err {
|
||||
case syscall.EIO, syscall.EBADF: // closed while open
|
||||
return 0
|
||||
return nil
|
||||
case syscall.ENOENT: // Linux error when removed while open
|
||||
return 0
|
||||
return nil
|
||||
}
|
||||
return errno
|
||||
return err
|
||||
}
|
||||
return 0
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -38,22 +38,21 @@ func TestReaddirnames(t *testing.T) {
|
||||
defer dotF.Close()
|
||||
|
||||
t.Run("dir", func(t *testing.T) {
|
||||
names, errno := platform.Readdirnames(dotF, -1)
|
||||
require.Zero(t, errno)
|
||||
|
||||
names, err := platform.Readdirnames(dotF, -1)
|
||||
require.NoError(t, err)
|
||||
sort.Strings(names)
|
||||
require.Equal(t, []string{"animals.txt", "dir", "empty.txt", "emptydir", "sub"}, names)
|
||||
|
||||
// read again even though it is exhausted
|
||||
_, errno = platform.Readdirnames(dotF, 100)
|
||||
require.Zero(t, errno)
|
||||
_, err = platform.Readdirnames(dotF, 100)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
// Don't err if something else closed the directory while reading.
|
||||
t.Run("closed dir", func(t *testing.T) {
|
||||
require.NoError(t, dotF.Close())
|
||||
_, errno := platform.Readdir(dotF, -1)
|
||||
require.Zero(t, errno)
|
||||
_, err := platform.Readdir(dotF, -1)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
dirF, err := tc.fs.Open("dir")
|
||||
@@ -61,17 +60,17 @@ func TestReaddirnames(t *testing.T) {
|
||||
defer dirF.Close()
|
||||
|
||||
t.Run("partial", func(t *testing.T) {
|
||||
names1, errno := platform.Readdirnames(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
names1, err := platform.Readdirnames(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(names1))
|
||||
|
||||
names2, errno := platform.Readdirnames(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
names2, err := platform.Readdirnames(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(names2))
|
||||
|
||||
// read exactly the last entry
|
||||
names3, errno := platform.Readdirnames(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
names3, err := platform.Readdirnames(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(names3))
|
||||
|
||||
names := []string{names1[0], names2[0], names3[0]}
|
||||
@@ -80,8 +79,8 @@ func TestReaddirnames(t *testing.T) {
|
||||
require.Equal(t, []string{"-", "a-", "ab-"}, names)
|
||||
|
||||
// no error reading an exhausted directory
|
||||
_, errno = platform.Readdirnames(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
_, err = platform.Readdirnames(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
fileF, err := tc.fs.Open("empty.txt")
|
||||
@@ -89,8 +88,8 @@ func TestReaddirnames(t *testing.T) {
|
||||
defer fileF.Close()
|
||||
|
||||
t.Run("file", func(t *testing.T) {
|
||||
_, errno := platform.Readdirnames(fileF, -1)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, errno)
|
||||
_, err := platform.Readdirnames(fileF, -1)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, err)
|
||||
})
|
||||
|
||||
subdirF, err := tc.fs.Open("sub")
|
||||
@@ -98,9 +97,8 @@ func TestReaddirnames(t *testing.T) {
|
||||
defer subdirF.Close()
|
||||
|
||||
t.Run("subdir", func(t *testing.T) {
|
||||
names, errno := platform.Readdirnames(subdirF, -1)
|
||||
require.Zero(t, errno)
|
||||
|
||||
names, err := platform.Readdirnames(subdirF, -1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{"test.txt"}, names)
|
||||
})
|
||||
})
|
||||
@@ -132,8 +130,8 @@ func TestReaddir(t *testing.T) {
|
||||
defer dotF.Close()
|
||||
|
||||
t.Run("dir", func(t *testing.T) {
|
||||
dirents, errno := platform.Readdir(dotF, -1)
|
||||
require.Zero(t, errno) // no io.EOF when -1 is used
|
||||
dirents, err := platform.Readdir(dotF, -1)
|
||||
require.NoError(t, err) // no io.EOF when -1 is used
|
||||
sort.Slice(dirents, func(i, j int) bool { return dirents[i].Name < dirents[j].Name })
|
||||
|
||||
requireIno(t, dirents, tc.expectIno)
|
||||
@@ -147,16 +145,16 @@ func TestReaddir(t *testing.T) {
|
||||
}, dirents)
|
||||
|
||||
// read again even though it is exhausted
|
||||
dirents, errno = platform.Readdir(dotF, 100)
|
||||
require.Zero(t, errno)
|
||||
dirents, err = platform.Readdir(dotF, 100)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(dirents))
|
||||
})
|
||||
|
||||
// Don't err if something else closed the directory while reading.
|
||||
t.Run("closed dir", func(t *testing.T) {
|
||||
require.NoError(t, dotF.Close())
|
||||
_, errno := platform.Readdir(dotF, -1)
|
||||
require.Zero(t, errno)
|
||||
_, err := platform.Readdir(dotF, -1)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
fileF, err := tc.fs.Open("empty.txt")
|
||||
@@ -164,8 +162,8 @@ func TestReaddir(t *testing.T) {
|
||||
defer fileF.Close()
|
||||
|
||||
t.Run("file", func(t *testing.T) {
|
||||
_, errno := platform.Readdir(fileF, -1)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, errno)
|
||||
_, err := platform.Readdir(fileF, -1)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, err)
|
||||
})
|
||||
|
||||
dirF, err := tc.fs.Open("dir")
|
||||
@@ -173,17 +171,17 @@ func TestReaddir(t *testing.T) {
|
||||
defer dirF.Close()
|
||||
|
||||
t.Run("partial", func(t *testing.T) {
|
||||
dirents1, errno := platform.Readdir(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
dirents1, err := platform.Readdir(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(dirents1))
|
||||
|
||||
dirents2, errno := platform.Readdir(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
dirents2, err := platform.Readdir(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(dirents2))
|
||||
|
||||
// read exactly the last entry
|
||||
dirents3, errno := platform.Readdir(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
dirents3, err := platform.Readdir(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(dirents3))
|
||||
|
||||
dirents := []*platform.Dirent{dirents1[0], dirents2[0], dirents3[0]}
|
||||
@@ -198,8 +196,8 @@ func TestReaddir(t *testing.T) {
|
||||
}, dirents)
|
||||
|
||||
// no error reading an exhausted directory
|
||||
_, errno = platform.Readdir(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
_, err = platform.Readdir(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
subdirF, err := tc.fs.Open("sub")
|
||||
@@ -207,8 +205,8 @@ func TestReaddir(t *testing.T) {
|
||||
defer subdirF.Close()
|
||||
|
||||
t.Run("subdir", func(t *testing.T) {
|
||||
dirents, errno := platform.Readdir(subdirF, -1)
|
||||
require.Zero(t, errno)
|
||||
dirents, err := platform.Readdir(subdirF, -1)
|
||||
require.NoError(t, err)
|
||||
sort.Slice(dirents, func(i, j int) bool { return dirents[i].Name < dirents[j].Name })
|
||||
|
||||
require.Equal(t, 1, len(dirents))
|
||||
@@ -224,8 +222,8 @@ func TestReaddir(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer dirF.Close()
|
||||
|
||||
dirents, errno := platform.Readdir(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
dirents, err := platform.Readdir(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(dirents))
|
||||
|
||||
// Speculatively try to remove even if it won't likely work
|
||||
@@ -237,8 +235,8 @@ func TestReaddir(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_, errno = platform.Readdir(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
_, err = platform.Readdir(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
// don't validate the contents as due to caching it might be present.
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
package platform
|
||||
|
||||
import "syscall"
|
||||
|
||||
func adjustErrno(err syscall.Errno) syscall.Errno {
|
||||
func adjustErrno(err error) error {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ const (
|
||||
ERROR_PRIVILEGE_NOT_HELD = syscall.Errno(0x522)
|
||||
)
|
||||
|
||||
func adjustErrno(err syscall.Errno) syscall.Errno {
|
||||
func adjustErrno(err syscall.Errno) error {
|
||||
// Note: In windows, ERROR_PATH_NOT_FOUND(0x3) maps to syscall.ENOTDIR
|
||||
switch err {
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package platform
|
||||
|
||||
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 a syscall.Errno or nil if the input is nil.
|
||||
func UnwrapOSError(err error) error {
|
||||
if err == nil {
|
||||
return 0
|
||||
return nil
|
||||
}
|
||||
err = underlyingError(err)
|
||||
if se, ok := err.(syscall.Errno); ok {
|
||||
@@ -20,8 +19,7 @@ func UnwrapOSError(err error) syscall.Errno {
|
||||
//
|
||||
// Note: Once we have our own file type, we should never see these.
|
||||
switch err {
|
||||
case nil, io.EOF:
|
||||
return 0
|
||||
case nil:
|
||||
case fs.ErrInvalid:
|
||||
return syscall.EINVAL
|
||||
case fs.ErrPermission:
|
||||
|
||||
@@ -3,7 +3,6 @@ package platform
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"syscall"
|
||||
@@ -18,11 +17,6 @@ func TestUnwrapOSError(t *testing.T) {
|
||||
input error
|
||||
expected syscall.Errno
|
||||
}{
|
||||
{
|
||||
name: "io.EOF is not an error",
|
||||
input: io.EOF,
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "LinkError ErrInvalid",
|
||||
input: &os.LinkError{Err: fs.ErrInvalid},
|
||||
@@ -83,7 +77,7 @@ func TestUnwrapOSError(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("nil -> zero", func(t *testing.T) {
|
||||
require.Zero(t, UnwrapOSError(nil))
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
require.Nil(t, UnwrapOSError(nil))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ const (
|
||||
// values UTIME_NOW or UTIME_NOW.
|
||||
// - This is like `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) error {
|
||||
err := utimens(path, times, symlinkFollow)
|
||||
return UnwrapOSError(err)
|
||||
}
|
||||
@@ -58,7 +58,7 @@ func Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) syscal
|
||||
// cannot use this to update timestamps on a directory (syscall.EPERM).
|
||||
// - This is like the function `futimens` in POSIX. See
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html
|
||||
func UtimensFile(f fs.File, times *[2]syscall.Timespec) syscall.Errno {
|
||||
func UtimensFile(f fs.File, times *[2]syscall.Timespec) error {
|
||||
if f, ok := f.(fdFile); ok {
|
||||
err := futimens(f.Fd(), times)
|
||||
return UnwrapOSError(err)
|
||||
@@ -102,16 +102,16 @@ func utimensPortable(path string, times *[2]syscall.Timespec, symlinkFollow bool
|
||||
|
||||
// Now, either one of the inputs is a special value, or neither. This means
|
||||
// we don't have a risk of re-reading the clock or re-doing stat.
|
||||
if atim, err := normalizeTimespec(path, times, 0); err != 0 {
|
||||
if atim, err := normalizeTimespec(path, times, 0); err != nil {
|
||||
return err
|
||||
} else if mtim, err := normalizeTimespec(path, times, 1); err != 0 {
|
||||
} else if mtim, err := normalizeTimespec(path, times, 1); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return syscall.UtimesNano(path, []syscall.Timespec{atim, mtim})
|
||||
}
|
||||
}
|
||||
|
||||
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 error) { //nolint:unused
|
||||
switch times[i].Nsec {
|
||||
case UTIME_NOW: // declined in Go per golang/go#31880.
|
||||
ts = nowTimespec()
|
||||
@@ -122,7 +122,7 @@ func normalizeTimespec(path string, times *[2]syscall.Timespec, i int) (ts sysca
|
||||
// - https://github.com/golang/go/issues/32558.
|
||||
// - https://go-review.googlesource.com/c/go/+/219638 (unmerged)
|
||||
var st Stat_t
|
||||
if st, err = stat(path); err != 0 {
|
||||
if st, err = stat(path); err != nil {
|
||||
return
|
||||
}
|
||||
switch i {
|
||||
|
||||
@@ -15,7 +15,6 @@ 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)
|
||||
|
||||
err = Utimens("nope", nil, false)
|
||||
if SupportsSymlinkNoFollow {
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
@@ -147,8 +146,8 @@ func testFutimens(t *testing.T, usePath bool) {
|
||||
panic(tc)
|
||||
}
|
||||
|
||||
oldSt, errno := Lstat(statPath)
|
||||
require.Zero(t, errno)
|
||||
oldSt, err := Lstat(statPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
if usePath {
|
||||
err = Utimens(path, tc.times, !symlinkNoFollow)
|
||||
@@ -156,7 +155,7 @@ func testFutimens(t *testing.T, usePath bool) {
|
||||
require.EqualErrno(t, syscall.ENOSYS, err)
|
||||
return
|
||||
}
|
||||
require.Zero(t, err)
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
flag := syscall.O_RDWR
|
||||
if path == dir {
|
||||
@@ -166,17 +165,15 @@ func testFutimens(t *testing.T, usePath bool) {
|
||||
t.Skip("windows cannot update timestamps on a dir")
|
||||
}
|
||||
}
|
||||
|
||||
f, errno := OpenFile(path, flag, 0)
|
||||
require.Zero(t, errno)
|
||||
|
||||
errno = UtimensFile(f, tc.times)
|
||||
f, err := OpenFile(path, flag, 0)
|
||||
require.NoError(t, err)
|
||||
err = UtimensFile(f, tc.times)
|
||||
require.NoError(t, f.Close())
|
||||
require.Zero(t, errno)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
newSt, errno := Lstat(statPath)
|
||||
require.Zero(t, errno)
|
||||
newSt, err := Lstat(statPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
if CompilerSupported() {
|
||||
if tc.times != nil && tc.times[0].Nsec == UTIME_OMIT {
|
||||
@@ -221,22 +218,20 @@ func TestUtimensFile(t *testing.T) {
|
||||
file := path.Join(t.TempDir(), "file")
|
||||
err := os.WriteFile(file, []byte{}, 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
fileF, errno := OpenFile(file, syscall.O_RDWR, 0)
|
||||
require.Zero(t, errno)
|
||||
fileF, err := OpenFile(file, syscall.O_RDWR, 0)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fileF.Close())
|
||||
|
||||
errno = UtimensFile(fileF, nil)
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
err = UtimensFile(fileF, nil)
|
||||
require.EqualErrno(t, syscall.EBADF, err)
|
||||
})
|
||||
|
||||
t.Run("closed dir", func(t *testing.T) {
|
||||
dir := path.Join(t.TempDir(), "dir")
|
||||
err := os.Mkdir(dir, 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
dirF, errno := OpenFile(dir, syscall.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
dirF, err := OpenFile(dir, syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, dirF.Close())
|
||||
|
||||
err = UtimensFile(dirF, nil)
|
||||
|
||||
@@ -15,9 +15,9 @@ const (
|
||||
O_NOFOLLOW = syscall.O_NOFOLLOW
|
||||
)
|
||||
|
||||
// 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) (File, syscall.Errno) {
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
return f, UnwrapOSError(err)
|
||||
// OpenFile is like os.OpenFile except it returns syscall.Errno
|
||||
func OpenFile(name string, flag int, perm fs.FileMode) (f *os.File, err error) {
|
||||
f, err = os.OpenFile(name, flag, perm)
|
||||
err = UnwrapOSError(err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package platform
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// See the comments on the same constants in open_file_windows.go
|
||||
@@ -12,8 +11,9 @@ const (
|
||||
O_NOFOLLOW = 1 << 30
|
||||
)
|
||||
|
||||
func OpenFile(path string, flag int, perm fs.FileMode) (File, syscall.Errno) {
|
||||
func OpenFile(name string, flag int, perm fs.FileMode) (f *os.File, err error) {
|
||||
flag &= ^(O_DIRECTORY | O_NOFOLLOW) // erase placeholders
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
return f, UnwrapOSError(err)
|
||||
f, err = os.OpenFile(name, flag, perm)
|
||||
err = UnwrapOSError(err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ func TestOpenFile(t *testing.T) {
|
||||
// from os.TestDirFSPathsValid
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Run("strange name", func(t *testing.T) {
|
||||
f, errno := OpenFile(path.Join(tmpDir, `e:xperi\ment.txt`), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
|
||||
require.Zero(t, errno)
|
||||
f, err := OpenFile(path.Join(tmpDir, `e:xperi\ment.txt`), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.Close())
|
||||
})
|
||||
}
|
||||
@@ -27,30 +27,30 @@ func TestOpenFile_Errors(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
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)
|
||||
_, err := OpenFile(path.Join(tmpDir, "not-really-exist.txt"), os.O_RDONLY, 0o600)
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
})
|
||||
|
||||
// This is the same as https://github.com/ziglang/zig/blob/d24ebf1d12cf66665b52136a2807f97ff021d78d/lib/std/os/test.zig#L105-L112
|
||||
t.Run("try creating on existing file must be EEXIST", func(t *testing.T) {
|
||||
filepath := path.Join(tmpDir, "file.txt")
|
||||
f, errno := OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o666)
|
||||
require.Zero(t, errno)
|
||||
f, err := OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o666)
|
||||
defer require.NoError(t, f.Close())
|
||||
require.NoError(t, err)
|
||||
|
||||
_, errno = OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o666)
|
||||
require.EqualErrno(t, syscall.EEXIST, errno)
|
||||
_, err = OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o666)
|
||||
require.EqualErrno(t, syscall.EEXIST, err)
|
||||
})
|
||||
|
||||
t.Run("writing to a read-only file is EBADF", func(t *testing.T) {
|
||||
path := path.Join(tmpDir, "file")
|
||||
require.NoError(t, os.WriteFile(path, nil, 0o600))
|
||||
|
||||
f, errno := OpenFile(path, os.O_RDONLY, 0)
|
||||
f, err := OpenFile(path, os.O_RDONLY, 0)
|
||||
defer require.NoError(t, f.Close())
|
||||
require.Zero(t, errno)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err := f.Write([]byte{1, 2, 3, 4})
|
||||
_, err = f.Write([]byte{1, 2, 3, 4})
|
||||
require.EqualErrno(t, syscall.EBADF, UnwrapOSError(err))
|
||||
})
|
||||
|
||||
@@ -58,11 +58,11 @@ func TestOpenFile_Errors(t *testing.T) {
|
||||
path := path.Join(tmpDir, "diragain")
|
||||
require.NoError(t, os.Mkdir(path, 0o755))
|
||||
|
||||
f, errno := OpenFile(path, os.O_RDONLY, 0)
|
||||
f, err := OpenFile(path, os.O_RDONLY, 0)
|
||||
defer require.NoError(t, f.Close())
|
||||
require.Zero(t, errno)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err := f.Write([]byte{1, 2, 3, 4})
|
||||
_, err = f.Write([]byte{1, 2, 3, 4})
|
||||
require.EqualErrno(t, syscall.EBADF, UnwrapOSError(err))
|
||||
})
|
||||
|
||||
@@ -74,10 +74,10 @@ func TestOpenFile_Errors(t *testing.T) {
|
||||
err := os.Symlink(target, symlink)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, errno := OpenFile(symlink, O_DIRECTORY|O_NOFOLLOW, 0o0666)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, errno)
|
||||
_, err = OpenFile(symlink, O_DIRECTORY|O_NOFOLLOW, 0o0666)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, err)
|
||||
|
||||
_, errno = OpenFile(symlink, O_NOFOLLOW, 0o0666)
|
||||
require.EqualErrno(t, syscall.ELOOP, errno)
|
||||
_, err = OpenFile(symlink, O_NOFOLLOW, 0o0666)
|
||||
require.EqualErrno(t, syscall.ELOOP, err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -27,36 +27,35 @@ const (
|
||||
O_NOFOLLOW = 1 << 30
|
||||
)
|
||||
|
||||
func OpenFile(path string, flag int, perm fs.FileMode) (File, syscall.Errno) {
|
||||
if f, errno := OpenFile(path, flag, perm); err != 0 {
|
||||
return nil, UnwrapOSError(err)
|
||||
func OpenFile(path string, flag int, perm fs.FileMode) (File, error) {
|
||||
if f, err := openFile(path, flag, perm); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return &windowsWrappedFile{File: f, path: path, flag: flag, perm: perm}, 0
|
||||
return &windowsWrappedFile{File: f, path: path, flag: flag, perm: perm}, 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, error) {
|
||||
isDir := flag&O_DIRECTORY > 0
|
||||
flag &= ^(O_DIRECTORY | O_NOFOLLOW) // erase placeholders
|
||||
|
||||
// TODO: document why we are opening twice
|
||||
fd, err := open(path, flag|syscall.O_CLOEXEC, uint32(perm))
|
||||
if err == nil {
|
||||
return os.NewFile(uintptr(fd), path), 0
|
||||
return os.NewFile(uintptr(fd), path), nil
|
||||
}
|
||||
|
||||
// TODO: Set FILE_SHARE_DELETE for directory as well.
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
errno := UnwrapOSError(err)
|
||||
if errno == 0 {
|
||||
return f, 0
|
||||
if err = UnwrapOSError(err); err == nil {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
switch errno {
|
||||
switch err {
|
||||
// To match expectations of WASI, e.g. TinyGo TestStatBadDir, return
|
||||
// ENOENT, not ENOTDIR.
|
||||
case syscall.ENOTDIR:
|
||||
errno = syscall.ENOENT
|
||||
err = syscall.ENOENT
|
||||
case syscall.ENOENT:
|
||||
if isSymlink(path) {
|
||||
// Either symlink or hard link not found. We change the returned
|
||||
@@ -64,13 +63,13 @@ func openFile(path string, flag int, perm fs.FileMode) (*os.File, syscall.Errno)
|
||||
// behavior across OSes.
|
||||
if isDir {
|
||||
// Dangling symlink dir must raise ENOTDIR.
|
||||
errno = syscall.ENOTDIR
|
||||
err = syscall.ENOTDIR
|
||||
} else {
|
||||
errno = syscall.ELOOP
|
||||
err = syscall.ELOOP
|
||||
}
|
||||
}
|
||||
}
|
||||
return f, errno
|
||||
return f, err
|
||||
}
|
||||
|
||||
func isSymlink(path string) bool {
|
||||
|
||||
@@ -4,9 +4,9 @@ package platform
|
||||
|
||||
import "syscall"
|
||||
|
||||
func Rename(from, to string) syscall.Errno {
|
||||
func Rename(from, to string) error {
|
||||
if from == to {
|
||||
return 0
|
||||
return nil
|
||||
}
|
||||
return UnwrapOSError(syscall.Rename(from, to))
|
||||
return syscall.Rename(from, to)
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ func TestRename(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
file2Path := path.Join(tmpDir, "file2")
|
||||
errno := Rename(file1Path, file2Path)
|
||||
require.Zero(t, errno)
|
||||
err = Rename(file1Path, file2Path)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err = os.Stat(file1Path)
|
||||
@@ -48,12 +48,12 @@ func TestRename(t *testing.T) {
|
||||
require.NoError(t, os.Mkdir(dir1Path, 0o700))
|
||||
|
||||
dir2Path := path.Join(tmpDir, "dir2")
|
||||
errno := Rename(dir1Path, dir2Path)
|
||||
require.Zero(t, errno)
|
||||
err := Rename(dir1Path, dir2Path)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err := os.Stat(dir1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, UnwrapOSError(err))
|
||||
_, err = os.Stat(dir1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, errors.Unwrap(err))
|
||||
|
||||
s, err := os.Stat(dir2Path)
|
||||
require.NoError(t, err)
|
||||
@@ -107,8 +107,8 @@ func TestRename(t *testing.T) {
|
||||
dir2Path := path.Join(tmpDir, "dir2")
|
||||
require.NoError(t, os.Mkdir(dir2Path, 0o700))
|
||||
|
||||
errno := Rename(dir1Path, dir2Path)
|
||||
require.Zero(t, errno)
|
||||
err = Rename(dir1Path, dir2Path)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err = os.Stat(dir1Path)
|
||||
@@ -158,8 +158,8 @@ func TestRename(t *testing.T) {
|
||||
err = os.WriteFile(file2Path, file2Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
errno := Rename(file1Path, file2Path)
|
||||
require.Zero(t, errno)
|
||||
err = Rename(file1Path, file2Path)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err = os.Stat(file1Path)
|
||||
@@ -176,8 +176,8 @@ func TestRename(t *testing.T) {
|
||||
dir1Path := path.Join(tmpDir, "dir1")
|
||||
require.NoError(t, os.Mkdir(dir1Path, 0o700))
|
||||
|
||||
errno := Rename(dir1Path, dir1Path)
|
||||
require.Zero(t, errno)
|
||||
err := Rename(dir1Path, dir1Path)
|
||||
require.NoError(t, err)
|
||||
|
||||
s, err := os.Stat(dir1Path)
|
||||
require.NoError(t, err)
|
||||
@@ -191,8 +191,8 @@ func TestRename(t *testing.T) {
|
||||
err := os.WriteFile(file1Path, file1Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
errno := Rename(file1Path, file1Path)
|
||||
require.Zero(t, errno)
|
||||
err = Rename(file1Path, file1Path)
|
||||
require.NoError(t, err)
|
||||
|
||||
b, err := os.ReadFile(file1Path)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -58,32 +58,34 @@ type Stat_t struct {
|
||||
// The primary difference between this and Stat is, when the path is a
|
||||
// symbolic link, the stat is about the link, not its target, such as directory
|
||||
// listings.
|
||||
func Lstat(path string) (Stat_t, syscall.Errno) {
|
||||
return lstat(path) // extracted to override more expensively in windows
|
||||
func Lstat(path string) (Stat_t, error) {
|
||||
st, err := lstat(path) // extracted to override more expensively in windows
|
||||
return st, UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Stat is like syscall.Stat. This returns syscall.ENOENT if the path doesn't
|
||||
// exist.
|
||||
func Stat(path string) (Stat_t, syscall.Errno) {
|
||||
return stat(path) // extracted to override more expensively in windows
|
||||
func Stat(path string) (Stat_t, error) {
|
||||
st, err := stat(path) // extracted to override more expensively in windows
|
||||
return st, UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// StatFile is like syscall.Fstat, but for fs.File instead of a file
|
||||
// descriptor. This returns syscall.EBADF if the file or directory was closed.
|
||||
// Note: windows allows you to stat a closed directory.
|
||||
func StatFile(f fs.File) (Stat_t, syscall.Errno) {
|
||||
st, errno := statFile(f)
|
||||
if errno == syscall.EIO {
|
||||
errno = syscall.EBADF
|
||||
func StatFile(f fs.File) (Stat_t, error) {
|
||||
st, err := statFile(f)
|
||||
if err = UnwrapOSError(err); err == syscall.EIO {
|
||||
err = syscall.EBADF
|
||||
}
|
||||
return st, errno
|
||||
return st, err
|
||||
}
|
||||
|
||||
func defaultStatFile(f fs.File) (Stat_t, syscall.Errno) {
|
||||
func defaultStatFile(f fs.File) (Stat_t, error) {
|
||||
if t, err := f.Stat(); err != nil {
|
||||
return Stat_t{}, UnwrapOSError(err)
|
||||
return Stat_t{}, err
|
||||
} else {
|
||||
return statFromFileInfo(t), 0
|
||||
return statFromFileInfo(t), nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,27 +8,27 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func lstat(path string) (Stat_t, syscall.Errno) {
|
||||
func lstat(path string) (Stat_t, error) {
|
||||
if t, err := os.Lstat(path); err != nil {
|
||||
return Stat_t{}, UnwrapOSError(err)
|
||||
return Stat_t{}, err
|
||||
} else {
|
||||
return statFromFileInfo(t), 0
|
||||
return statFromFileInfo(t), nil
|
||||
}
|
||||
}
|
||||
|
||||
func stat(path string) (Stat_t, syscall.Errno) {
|
||||
func stat(path string) (Stat_t, error) {
|
||||
if t, err := os.Stat(path); err != nil {
|
||||
return Stat_t{}, UnwrapOSError(err)
|
||||
return Stat_t{}, err
|
||||
} else {
|
||||
return statFromFileInfo(t), 0
|
||||
return statFromFileInfo(t), nil
|
||||
}
|
||||
}
|
||||
|
||||
func statFile(f fs.File) (Stat_t, syscall.Errno) {
|
||||
func statFile(f fs.File) (Stat_t, error) {
|
||||
return defaultStatFile(f)
|
||||
}
|
||||
|
||||
func inoFromFileInfo(_ readdirFile, t fs.FileInfo) (ino uint64, err syscall.Errno) {
|
||||
func inoFromFileInfo(_ readdirFile, t fs.FileInfo) (ino uint64, err error) {
|
||||
if d, ok := t.Sys().(*syscall.Stat_t); ok {
|
||||
ino = d.Ino
|
||||
}
|
||||
|
||||
@@ -11,27 +11,27 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func lstat(path string) (Stat_t, syscall.Errno) {
|
||||
func lstat(path string) (Stat_t, error) {
|
||||
if t, err := os.Lstat(path); err != nil {
|
||||
return Stat_t{}, UnwrapOSError(err)
|
||||
return Stat_t{}, err
|
||||
} else {
|
||||
return statFromFileInfo(t), 0
|
||||
return statFromFileInfo(t), nil
|
||||
}
|
||||
}
|
||||
|
||||
func stat(path string) (Stat_t, syscall.Errno) {
|
||||
func stat(path string) (Stat_t, error) {
|
||||
if t, err := os.Stat(path); err != nil {
|
||||
return Stat_t{}, UnwrapOSError(err)
|
||||
return Stat_t{}, err
|
||||
} else {
|
||||
return statFromFileInfo(t), 0
|
||||
return statFromFileInfo(t), nil
|
||||
}
|
||||
}
|
||||
|
||||
func statFile(f fs.File) (Stat_t, syscall.Errno) {
|
||||
func statFile(f fs.File) (Stat_t, error) {
|
||||
return defaultStatFile(f)
|
||||
}
|
||||
|
||||
func inoFromFileInfo(_ readdirFile, t fs.FileInfo) (ino uint64, err syscall.Errno) {
|
||||
func inoFromFileInfo(_ readdirFile, t fs.FileInfo) (ino uint64, err error) {
|
||||
if d, ok := t.Sys().(*syscall.Stat_t); ok {
|
||||
ino = d.Ino
|
||||
}
|
||||
|
||||
@@ -15,16 +15,15 @@ import (
|
||||
func TestLstat(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
_, errno := Lstat(path.Join(tmpDir, "cat"))
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
_, errno = Lstat(path.Join(tmpDir, "sub/cat"))
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
_, err := Lstat(path.Join(tmpDir, "cat"))
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
_, err = Lstat(path.Join(tmpDir, "sub/cat"))
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
|
||||
var st Stat_t
|
||||
t.Run("dir", func(t *testing.T) {
|
||||
st, errno = Lstat(tmpDir)
|
||||
require.Zero(t, errno)
|
||||
|
||||
st, err = Lstat(tmpDir)
|
||||
require.NoError(t, err)
|
||||
require.True(t, st.Mode.IsDir())
|
||||
require.NotEqual(t, uint64(0), st.Ino)
|
||||
})
|
||||
@@ -34,9 +33,8 @@ func TestLstat(t *testing.T) {
|
||||
|
||||
t.Run("file", func(t *testing.T) {
|
||||
require.NoError(t, os.WriteFile(file, []byte{1, 2}, 0o400))
|
||||
stFile, errno = Lstat(file)
|
||||
require.Zero(t, errno)
|
||||
|
||||
stFile, err = Lstat(file)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, stFile.Mode.Type())
|
||||
require.Equal(t, int64(2), stFile.Size)
|
||||
require.NotEqual(t, uint64(0), stFile.Ino)
|
||||
@@ -51,9 +49,8 @@ func TestLstat(t *testing.T) {
|
||||
t.Run("subdir", func(t *testing.T) {
|
||||
require.NoError(t, os.Mkdir(subdir, 0o500))
|
||||
|
||||
stSubdir, errno = Lstat(subdir)
|
||||
require.Zero(t, errno)
|
||||
|
||||
stSubdir, err = Lstat(subdir)
|
||||
require.NoError(t, err)
|
||||
require.True(t, stSubdir.Mode.IsDir())
|
||||
require.NotEqual(t, uint64(0), stSubdir.Ino)
|
||||
})
|
||||
@@ -64,8 +61,8 @@ func TestLstat(t *testing.T) {
|
||||
|
||||
t.Run("link to dir link", func(t *testing.T) {
|
||||
pathLink := subdir + "-link"
|
||||
stLink, errno := Lstat(pathLink)
|
||||
require.Zero(t, errno)
|
||||
stLink, err := Lstat(pathLink)
|
||||
require.NoError(t, err)
|
||||
|
||||
requireLinkStat(t, pathLink, stLink)
|
||||
})
|
||||
@@ -75,8 +72,8 @@ func requireLinkStat(t *testing.T, path string, stat Stat_t) {
|
||||
link := path + "-link"
|
||||
require.NoError(t, os.Symlink(path, link))
|
||||
|
||||
stLink, errno := Lstat(link)
|
||||
require.Zero(t, errno)
|
||||
stLink, err := Lstat(link)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotEqual(t, uint64(0), stLink.Ino)
|
||||
require.NotEqual(t, stat.Ino, stLink.Ino) // inodes are not equal
|
||||
@@ -94,17 +91,16 @@ func requireLinkStat(t *testing.T, path string, stat Stat_t) {
|
||||
func TestStat(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
_, errno := Stat(path.Join(tmpDir, "cat"))
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
_, errno = Stat(path.Join(tmpDir, "sub/cat"))
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
_, err := Stat(path.Join(tmpDir, "cat"))
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
_, err = Stat(path.Join(tmpDir, "sub/cat"))
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
|
||||
var st Stat_t
|
||||
|
||||
t.Run("dir", func(t *testing.T) {
|
||||
st, errno = Stat(tmpDir)
|
||||
require.Zero(t, errno)
|
||||
|
||||
st, err = Stat(tmpDir)
|
||||
require.NoError(t, err)
|
||||
require.True(t, st.Mode.IsDir())
|
||||
require.NotEqual(t, uint64(0), st.Ino)
|
||||
})
|
||||
@@ -115,9 +111,8 @@ func TestStat(t *testing.T) {
|
||||
t.Run("file", func(t *testing.T) {
|
||||
require.NoError(t, os.WriteFile(file, nil, 0o400))
|
||||
|
||||
stFile, errno = Stat(file)
|
||||
require.Zero(t, errno)
|
||||
|
||||
stFile, err = Stat(file)
|
||||
require.NoError(t, err)
|
||||
require.False(t, stFile.Mode.IsDir())
|
||||
require.NotEqual(t, uint64(0), st.Ino)
|
||||
})
|
||||
@@ -126,9 +121,8 @@ func TestStat(t *testing.T) {
|
||||
link := path.Join(tmpDir, "file-link")
|
||||
require.NoError(t, os.Symlink(file, link))
|
||||
|
||||
stLink, errno := Stat(link)
|
||||
require.Zero(t, errno)
|
||||
|
||||
stLink, err := Stat(link)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, stFile, stLink) // resolves to the file
|
||||
})
|
||||
|
||||
@@ -137,9 +131,8 @@ func TestStat(t *testing.T) {
|
||||
t.Run("subdir", func(t *testing.T) {
|
||||
require.NoError(t, os.Mkdir(subdir, 0o500))
|
||||
|
||||
stSubdir, errno = Stat(subdir)
|
||||
require.Zero(t, errno)
|
||||
|
||||
stSubdir, err = Stat(subdir)
|
||||
require.NoError(t, err)
|
||||
require.True(t, stSubdir.Mode.IsDir())
|
||||
require.NotEqual(t, uint64(0), st.Ino)
|
||||
})
|
||||
@@ -148,9 +141,8 @@ func TestStat(t *testing.T) {
|
||||
link := path.Join(tmpDir, "dir-link")
|
||||
require.NoError(t, os.Symlink(subdir, link))
|
||||
|
||||
stLink, errno := Stat(link)
|
||||
require.Zero(t, errno)
|
||||
|
||||
stLink, err := Stat(link)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, stSubdir, stLink) // resolves to the dir
|
||||
})
|
||||
}
|
||||
@@ -160,14 +152,13 @@ func TestStatFile(t *testing.T) {
|
||||
|
||||
var st Stat_t
|
||||
|
||||
tmpDirF, errno := OpenFile(tmpDir, syscall.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
tmpDirF, err := OpenFile(tmpDir, syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer tmpDirF.Close()
|
||||
|
||||
t.Run("dir", func(t *testing.T) {
|
||||
st, errno = StatFile(tmpDirF)
|
||||
require.Zero(t, errno)
|
||||
|
||||
st, err = StatFile(tmpDirF)
|
||||
require.NoError(t, err)
|
||||
require.True(t, st.Mode.IsDir())
|
||||
requireDirectoryDevIno(t, st)
|
||||
})
|
||||
@@ -177,41 +168,39 @@ func TestStatFile(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Run("closed dir", func(t *testing.T) {
|
||||
require.NoError(t, tmpDirF.Close())
|
||||
st, errno = StatFile(tmpDirF)
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
st, err = StatFile(tmpDirF)
|
||||
require.EqualErrno(t, syscall.EBADF, err)
|
||||
})
|
||||
}
|
||||
|
||||
file := path.Join(tmpDir, "file")
|
||||
require.NoError(t, os.WriteFile(file, nil, 0o400))
|
||||
fileF, errno := OpenFile(file, syscall.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fileF, err := OpenFile(file, syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer fileF.Close()
|
||||
|
||||
t.Run("file", func(t *testing.T) {
|
||||
st, errno = StatFile(fileF)
|
||||
require.Zero(t, errno)
|
||||
|
||||
st, err = StatFile(fileF)
|
||||
require.NoError(t, err)
|
||||
require.False(t, st.Mode.IsDir())
|
||||
require.NotEqual(t, uint64(0), st.Ino)
|
||||
})
|
||||
|
||||
t.Run("closed file", func(t *testing.T) {
|
||||
require.NoError(t, fileF.Close())
|
||||
_, errno = StatFile(fileF)
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
_, err = StatFile(fileF)
|
||||
require.EqualErrno(t, syscall.EBADF, err)
|
||||
})
|
||||
|
||||
subdir := path.Join(tmpDir, "sub")
|
||||
require.NoError(t, os.Mkdir(subdir, 0o500))
|
||||
subdirF, errno := OpenFile(subdir, syscall.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
subdirF, err := OpenFile(subdir, syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer subdirF.Close()
|
||||
|
||||
t.Run("subdir", func(t *testing.T) {
|
||||
st, errno = StatFile(subdirF)
|
||||
require.Zero(t, errno)
|
||||
|
||||
st, err = StatFile(subdirF)
|
||||
require.NoError(t, err)
|
||||
require.True(t, st.Mode.IsDir())
|
||||
requireDirectoryDevIno(t, st)
|
||||
})
|
||||
@@ -219,8 +208,8 @@ func TestStatFile(t *testing.T) {
|
||||
if runtime.GOOS != "windows" { // windows allows you to stat a closed dir
|
||||
t.Run("closed subdir", func(t *testing.T) {
|
||||
require.NoError(t, subdirF.Close())
|
||||
st, errno = StatFile(subdirF)
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
st, err = StatFile(subdirF)
|
||||
require.EqualErrno(t, syscall.EBADF, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -268,9 +257,8 @@ func Test_StatFile_times(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
st, errno := StatFile(f)
|
||||
require.Zero(t, errno)
|
||||
|
||||
st, err := StatFile(f)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, st.Atim, tc.atimeNsec)
|
||||
require.Equal(t, st.Mtim, tc.mtimeNsec)
|
||||
})
|
||||
@@ -301,20 +289,19 @@ func TestStatFile_dev_inode(t *testing.T) {
|
||||
defer l2.Close()
|
||||
|
||||
// First, stat the directory
|
||||
st1, errno := StatFile(d)
|
||||
require.Zero(t, errno)
|
||||
|
||||
st1, err := StatFile(d)
|
||||
require.NoError(t, err)
|
||||
requireDirectoryDevIno(t, st1)
|
||||
|
||||
// Now, stat the files in it
|
||||
st1, errno = StatFile(f1)
|
||||
require.Zero(t, errno)
|
||||
st1, err = StatFile(f1)
|
||||
require.NoError(t, err)
|
||||
|
||||
st2, errno := StatFile(f2)
|
||||
require.Zero(t, errno)
|
||||
st2, err := StatFile(f2)
|
||||
require.NoError(t, err)
|
||||
|
||||
st3, errno := StatFile(l2)
|
||||
require.Zero(t, errno)
|
||||
st3, err := StatFile(l2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// The files should be on the same device, but different inodes
|
||||
require.Equal(t, st1.Dev, st2.Dev)
|
||||
@@ -322,8 +309,8 @@ func TestStatFile_dev_inode(t *testing.T) {
|
||||
require.Equal(t, st2, st3) // stat on a link is for its target
|
||||
|
||||
// Redoing stat should result in the same inodes
|
||||
st1Again, errno := StatFile(f1)
|
||||
require.Zero(t, errno)
|
||||
st1Again, err := StatFile(f1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, st1.Dev, st1Again.Dev)
|
||||
|
||||
// On Windows, we cannot rename while opening.
|
||||
@@ -333,13 +320,13 @@ func TestStatFile_dev_inode(t *testing.T) {
|
||||
require.NoError(t, l2.Close())
|
||||
|
||||
// Renaming a file shouldn't change its inodes.
|
||||
require.Zero(t, Rename(path1, path2))
|
||||
require.NoError(t, Rename(path1, path2))
|
||||
f1, err = os.Open(path2)
|
||||
require.NoError(t, err)
|
||||
defer f1.Close()
|
||||
|
||||
st1Again, errno = StatFile(f1)
|
||||
require.Zero(t, errno)
|
||||
st1Again, err = StatFile(f1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, st1.Dev, st1Again.Dev)
|
||||
require.Equal(t, st1.Ino, st1Again.Ino)
|
||||
}
|
||||
@@ -372,11 +359,10 @@ func TestStat_uid_gid(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
dir := path.Join(tmpDir, "dir")
|
||||
require.NoError(t, os.Mkdir(dir, 0o0700))
|
||||
require.Zero(t, chgid(dir, gid))
|
||||
|
||||
st, errno := Stat(dir)
|
||||
require.Zero(t, errno)
|
||||
require.NoError(t, chgid(dir, gid))
|
||||
|
||||
st, err := Stat(dir)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uid, st.Uid)
|
||||
require.Equal(t, gid, st.Gid)
|
||||
})
|
||||
@@ -385,11 +371,10 @@ func TestStat_uid_gid(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
link := path.Join(tmpDir, "link")
|
||||
require.NoError(t, os.Symlink(tmpDir, link))
|
||||
require.Zero(t, chgid(link, gid))
|
||||
|
||||
st, errno := Lstat(link)
|
||||
require.Zero(t, errno)
|
||||
require.NoError(t, chgid(link, gid))
|
||||
|
||||
st, err := Lstat(link)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uid, st.Uid)
|
||||
require.Equal(t, gid, st.Gid)
|
||||
})
|
||||
@@ -398,11 +383,10 @@ func TestStat_uid_gid(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
file := path.Join(tmpDir, "file")
|
||||
require.NoError(t, os.WriteFile(file, nil, 0o0600))
|
||||
require.Zero(t, chgid(file, gid))
|
||||
|
||||
st, errno := Lstat(file)
|
||||
require.Zero(t, errno)
|
||||
require.NoError(t, chgid(file, gid))
|
||||
|
||||
st, err := Lstat(file)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uid, st.Uid)
|
||||
require.Equal(t, gid, st.Gid)
|
||||
})
|
||||
|
||||
@@ -5,32 +5,29 @@ package platform
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func lstat(path string) (Stat_t, syscall.Errno) {
|
||||
func lstat(path string) (Stat_t, error) {
|
||||
t, err := os.Lstat(path)
|
||||
if errno := UnwrapOSError(err); errno == 0 {
|
||||
return statFromFileInfo(t), 0
|
||||
} else {
|
||||
return Stat_t{}, errno
|
||||
if err = UnwrapOSError(err); err != nil {
|
||||
return statFromFileInfo(t), nil
|
||||
}
|
||||
return Stat_t{}, err
|
||||
}
|
||||
|
||||
func stat(path string) (Stat_t, syscall.Errno) {
|
||||
func stat(path string) (Stat_t, error) {
|
||||
t, err := os.Stat(path)
|
||||
if errno := UnwrapOSError(err); errno == 0 {
|
||||
return statFromFileInfo(t), 0
|
||||
} else {
|
||||
return Stat_t{}, errno
|
||||
if err = UnwrapOSError(err); err == nil {
|
||||
return statFromFileInfo(t), nil
|
||||
}
|
||||
return Stat_t{}, err
|
||||
}
|
||||
|
||||
func statFile(f fs.File) (Stat_t, syscall.Errno) {
|
||||
func statFile(f fs.File) (Stat_t, error) {
|
||||
return defaultStatFile(f)
|
||||
}
|
||||
|
||||
func inoFromFileInfo(_ readdirFile, t fs.FileInfo) (ino uint64, err syscall.Errno) {
|
||||
func inoFromFileInfo(readdirFile, fs.FileInfo) (ino uint64, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func lstat(path string) (Stat_t, syscall.Errno) {
|
||||
func lstat(path string) (Stat_t, error) {
|
||||
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
|
||||
@@ -16,12 +16,12 @@ func lstat(path string) (Stat_t, syscall.Errno) {
|
||||
return statPath(attrs, path)
|
||||
}
|
||||
|
||||
func stat(path string) (Stat_t, syscall.Errno) {
|
||||
func stat(path string) (Stat_t, error) {
|
||||
attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
|
||||
return statPath(attrs, path)
|
||||
}
|
||||
|
||||
func statPath(createFileAttrs uint32, path string) (Stat_t, syscall.Errno) {
|
||||
func statPath(createFileAttrs uint32, path string) (Stat_t, error) {
|
||||
if len(path) == 0 {
|
||||
return Stat_t{}, syscall.ENOENT
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func statPath(createFileAttrs uint32, path string) (Stat_t, syscall.Errno) {
|
||||
return statHandle(h)
|
||||
}
|
||||
|
||||
func statFile(f fs.File) (Stat_t, syscall.Errno) {
|
||||
func statFile(f fs.File) (Stat_t, error) {
|
||||
if of, ok := f.(fdFile); ok {
|
||||
// Attempt to get the stat by handle, which works for normal files
|
||||
st, err := statHandle(syscall.Handle(of.Fd()))
|
||||
@@ -61,11 +61,10 @@ func statFile(f fs.File) (Stat_t, syscall.Errno) {
|
||||
}
|
||||
|
||||
// inoFromFileInfo uses stat to get the inode information of the file.
|
||||
func inoFromFileInfo(_ readdirFile, t fs.FileInfo) (ino uint64, errno syscall.Errno) {
|
||||
func inoFromFileInfo(f readdirFile, t fs.FileInfo) (ino uint64, err error) {
|
||||
if pf, ok := f.(PathFile); ok {
|
||||
inoPath := path.Clean(path.Join(pf.Path(), t.Name()))
|
||||
var st Stat_t
|
||||
if st, errno = Lstat(inoPath); errno == 0 {
|
||||
if st, err := lstat(inoPath); err == nil {
|
||||
ino = st.Ino
|
||||
}
|
||||
}
|
||||
@@ -89,7 +88,7 @@ func statFromFileInfo(t fs.FileInfo) Stat_t {
|
||||
}
|
||||
}
|
||||
|
||||
func statHandle(h syscall.Handle) (Stat_t, syscall.Errno) {
|
||||
func statHandle(h syscall.Handle) (Stat_t, error) {
|
||||
winFt, err := syscall.GetFileType(h)
|
||||
if err != nil {
|
||||
return Stat_t{}, err
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
package platform
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"syscall"
|
||||
)
|
||||
import "io/fs"
|
||||
|
||||
// Fdatasync is like syscall.Fdatasync except that's only defined in linux.
|
||||
//
|
||||
// Note: This returns with no error instead of syscall.ENOSYS when
|
||||
// unimplemented. This prevents fake filesystems from erring.
|
||||
func Fdatasync(f fs.File) syscall.Errno {
|
||||
func Fdatasync(f fs.File) (err error) {
|
||||
return fdatasync(f)
|
||||
}
|
||||
|
||||
@@ -7,14 +7,14 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func fdatasync(f fs.File) syscall.Errno {
|
||||
func fdatasync(f fs.File) (err error) {
|
||||
if fd, ok := f.(fdFile); ok {
|
||||
return UnwrapOSError(syscall.Fdatasync(int(fd.Fd())))
|
||||
return syscall.Fdatasync(int(fd.Fd()))
|
||||
}
|
||||
|
||||
// Attempt to sync everything, even if we only need to sync the data.
|
||||
if s, ok := f.(syncFile); ok {
|
||||
return UnwrapOSError(s.Sync())
|
||||
err = s.Sync()
|
||||
}
|
||||
return 0
|
||||
return
|
||||
}
|
||||
|
||||
@@ -14,30 +14,30 @@ import (
|
||||
// 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 Test_Fdatasync(t *testing.T) {
|
||||
f, errno := os.CreateTemp("", t.Name())
|
||||
require.NoError(t, errno)
|
||||
f, err := os.CreateTemp("", t.Name())
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
expected := "hello world!"
|
||||
|
||||
// Write the expected data
|
||||
_, errno = f.Write([]byte(expected))
|
||||
require.NoError(t, errno)
|
||||
_, err = f.Write([]byte(expected))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Sync the data.
|
||||
if errno = Fdatasync(f); errno == syscall.ENOSYS {
|
||||
if err = Fdatasync(f); err == syscall.ENOSYS {
|
||||
return // don't continue if it isn't supported.
|
||||
}
|
||||
require.Zero(t, errno)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Rewind while the file is still open.
|
||||
_, err := f.Seek(0, io.SeekStart)
|
||||
_, err = f.Seek(0, io.SeekStart)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read data from the file
|
||||
var buf bytes.Buffer
|
||||
_, errno = io.Copy(&buf, f)
|
||||
require.NoError(t, errno)
|
||||
_, err = io.Copy(&buf, f)
|
||||
require.NoError(t, err)
|
||||
|
||||
// It may be the case that sync worked.
|
||||
require.Equal(t, expected, buf.String())
|
||||
|
||||
@@ -4,13 +4,12 @@ package platform
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func fdatasync(f fs.File) syscall.Errno {
|
||||
func fdatasync(f fs.File) error {
|
||||
// Attempt to sync everything, even if we only need to sync the data.
|
||||
if s, ok := f.(syncFile); ok {
|
||||
return UnwrapOSError(s.Sync())
|
||||
return s.Sync()
|
||||
}
|
||||
return 0
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ package platform
|
||||
|
||||
import "syscall"
|
||||
|
||||
func Unlink(name string) (errno syscall.Errno) {
|
||||
func Unlink(name string) error {
|
||||
err := syscall.Unlink(name)
|
||||
if errno = UnwrapOSError(err); errno == syscall.EPERM {
|
||||
errno = syscall.EISDIR
|
||||
if err = UnwrapOSError(err); err == syscall.EPERM {
|
||||
err = syscall.EISDIR
|
||||
}
|
||||
return errno
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
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)
|
||||
err := Unlink(name)
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
})
|
||||
|
||||
t.Run("target: dir", func(t *testing.T) {
|
||||
@@ -22,8 +22,8 @@ func TestUnlink(t *testing.T) {
|
||||
dir := path.Join(tmpDir, "dir")
|
||||
require.NoError(t, os.Mkdir(dir, 0o700))
|
||||
|
||||
errno := Unlink(dir)
|
||||
require.EqualErrno(t, syscall.EISDIR, errno)
|
||||
err := Unlink(dir)
|
||||
require.EqualErrno(t, syscall.EISDIR, err)
|
||||
|
||||
require.NoError(t, os.Remove(dir))
|
||||
})
|
||||
@@ -40,8 +40,8 @@ func TestUnlink(t *testing.T) {
|
||||
require.NoError(t, os.Symlink("subdir", symlinkName))
|
||||
|
||||
// Unlinking the symlink should suceed.
|
||||
errno := Unlink(symlinkName)
|
||||
require.Zero(t, errno)
|
||||
err := Unlink(symlinkName)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("file exists", func(t *testing.T) {
|
||||
@@ -51,7 +51,7 @@ func TestUnlink(t *testing.T) {
|
||||
|
||||
require.NoError(t, os.WriteFile(name, []byte{}, 0o600))
|
||||
|
||||
require.Zero(t, Unlink(name))
|
||||
require.NoError(t, Unlink(name))
|
||||
_, err := os.Stat(name)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
@@ -88,7 +88,7 @@ func (w *windowsWrappedFile) maybeInitDir() error {
|
||||
if err := w.File.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
newW, errno := OpenFile(w.path, w.flag, w.perm)
|
||||
newW, err := openFile(w.path, w.flag, w.perm)
|
||||
if err != nil {
|
||||
return &fs.PathError{Op: "OpenFile", Path: w.path, Err: err}
|
||||
}
|
||||
@@ -120,7 +120,7 @@ func (w *windowsWrappedFile) requireFile(op string, readOnly, isDir bool) error
|
||||
// getFileType caches the file type as this cannot change on an open file.
|
||||
func (w *windowsWrappedFile) getFileType() (fs.FileMode, error) {
|
||||
if w.fileType == nil {
|
||||
st, errno := StatFile(w.File)
|
||||
st, err := StatFile(w.File)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
@@ -115,26 +115,26 @@ type lazyDir struct {
|
||||
|
||||
// Stat implements fs.File
|
||||
func (r *lazyDir) Stat() (fs.FileInfo, error) {
|
||||
if f, err := r.file(); err != 0 {
|
||||
if f, err := r.file(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return f.Stat()
|
||||
}
|
||||
}
|
||||
|
||||
func (r *lazyDir) file() (f fs.File, errno syscall.Errno) {
|
||||
func (r *lazyDir) file() (f fs.File, err error) {
|
||||
if f = r.f; r.f != nil {
|
||||
return
|
||||
}
|
||||
r.f, errno = r.fs.OpenFile(".", os.O_RDONLY, 0)
|
||||
r.f, err = r.fs.OpenFile(".", os.O_RDONLY, 0)
|
||||
f = r.f
|
||||
return
|
||||
}
|
||||
|
||||
// Read implements fs.File
|
||||
func (r *lazyDir) Read(p []byte) (n int, err error) {
|
||||
if f, errno := r.file(); errno != 0 {
|
||||
return 0, errno
|
||||
if f, err := r.file(); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
return f.Read(p)
|
||||
}
|
||||
@@ -142,14 +142,10 @@ func (r *lazyDir) Read(p []byte) (n int, err error) {
|
||||
|
||||
// Close implements fs.File
|
||||
func (r *lazyDir) Close() error {
|
||||
f, errno := r.file()
|
||||
switch errno {
|
||||
case 0:
|
||||
return f.Close()
|
||||
case syscall.ENOENT:
|
||||
if f, err := r.file(); err != nil {
|
||||
return nil
|
||||
default:
|
||||
return errno
|
||||
} else {
|
||||
return f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,19 +199,16 @@ func (f *FileEntry) CachedStat() (ino uint64, fileType fs.FileMode, err error) {
|
||||
|
||||
// Stat returns the underlying stat of this file.
|
||||
func (f *FileEntry) Stat() (st platform.Stat_t, err error) {
|
||||
var errno syscall.Errno
|
||||
if ld, ok := f.File.(*lazyDir); ok {
|
||||
var sf fs.File
|
||||
if sf, errno = ld.file(); errno == 0 {
|
||||
st, errno = platform.StatFile(sf)
|
||||
if sf, err = ld.file(); err == nil {
|
||||
st, err = platform.StatFile(sf)
|
||||
}
|
||||
} else {
|
||||
st, errno = platform.StatFile(f.File)
|
||||
st, err = platform.StatFile(f.File)
|
||||
}
|
||||
|
||||
if errno != 0 {
|
||||
err = errno
|
||||
} else {
|
||||
if err == nil {
|
||||
f.cachedStat = &cachedStat{Ino: st.Ino, Type: st.Mode & fs.ModeType}
|
||||
}
|
||||
return
|
||||
@@ -332,9 +325,9 @@ func (c *FSContext) RootFS() sysfs.FS {
|
||||
|
||||
// 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 sysfs.FS, path string, flag int, perm fs.FileMode) (uint32, syscall.Errno) {
|
||||
if f, errno := fs.OpenFile(path, flag, perm); errno != 0 {
|
||||
return 0, errno
|
||||
func (c *FSContext) OpenFile(fs sysfs.FS, path string, flag int, perm fs.FileMode) (uint32, error) {
|
||||
if f, err := fs.OpenFile(path, flag, perm); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
fe := &FileEntry{openPath: path, FS: fs, File: f, openFlag: flag, openPerm: perm}
|
||||
if path == "/" || path == "." {
|
||||
@@ -343,54 +336,54 @@ func (c *FSContext) OpenFile(fs sysfs.FS, path string, flag int, perm fs.FileMod
|
||||
fe.Name = path
|
||||
}
|
||||
newFD := c.openedFiles.Insert(fe)
|
||||
return newFD, 0
|
||||
return newFD, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ReOpenDir re-opens the directory while keeping the same file descriptor.
|
||||
// TODO: this might not be necessary once we have our own File type.
|
||||
func (c *FSContext) ReOpenDir(fd uint32) (*FileEntry, syscall.Errno) {
|
||||
func (c *FSContext) ReOpenDir(fd uint32) (*FileEntry, error) {
|
||||
f, ok := c.openedFiles.Lookup(fd)
|
||||
if !ok {
|
||||
return nil, syscall.EBADF
|
||||
} else if _, ft, err := f.CachedStat(); err != nil {
|
||||
return nil, platform.UnwrapOSError(err)
|
||||
return nil, err
|
||||
} else if ft.Type() != fs.ModeDir {
|
||||
return nil, syscall.EISDIR
|
||||
}
|
||||
|
||||
if errno := c.reopen(f); errno != 0 {
|
||||
return nil, errno
|
||||
if err := c.reopen(f); err != nil {
|
||||
return f, err
|
||||
}
|
||||
|
||||
f.ReadDir.CountRead, f.ReadDir.Dirents = 0, nil
|
||||
return f, 0
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (c *FSContext) reopen(f *FileEntry) syscall.Errno {
|
||||
func (c *FSContext) reopen(f *FileEntry) error {
|
||||
if err := f.File.Close(); err != nil {
|
||||
return platform.UnwrapOSError(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Re-opens with the same parameters as before.
|
||||
opened, errno := f.FS.OpenFile(f.openPath, f.openFlag, f.openPerm)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
opened, err := f.FS.OpenFile(f.openPath, f.openFlag, f.openPerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Reset the state.
|
||||
f.File = opened
|
||||
return 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChangeOpenFlag changes the open flag of the given opened file pointed by `fd`.
|
||||
// Currently, this only supports the change of syscall.O_APPEND flag.
|
||||
func (c *FSContext) ChangeOpenFlag(fd uint32, flag int) syscall.Errno {
|
||||
func (c *FSContext) ChangeOpenFlag(fd uint32, flag int) error {
|
||||
f, ok := c.LookupFile(fd)
|
||||
if !ok {
|
||||
return syscall.EBADF
|
||||
} else if _, ft, err := f.CachedStat(); err != nil {
|
||||
return platform.UnwrapOSError(err)
|
||||
return err
|
||||
} else if ft.Type() == fs.ModeDir {
|
||||
return syscall.EISDIR
|
||||
}
|
||||
@@ -411,7 +404,10 @@ func (c *FSContext) ChangeOpenFlag(fd uint32, flag int) syscall.Errno {
|
||||
//
|
||||
// Therefore, here we re-open the file while keeping the file descriptor.
|
||||
// TODO: this might be improved once we have our own File type.
|
||||
return c.reopen(f)
|
||||
if err := c.reopen(f); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LookupFile returns a file if it is in the table.
|
||||
@@ -421,7 +417,7 @@ func (c *FSContext) LookupFile(fd uint32) (*FileEntry, bool) {
|
||||
}
|
||||
|
||||
// Renumber assigns the file pointed by the descriptor `from` to `to`.
|
||||
func (c *FSContext) Renumber(from, to uint32) syscall.Errno {
|
||||
func (c *FSContext) Renumber(from, to uint32) error {
|
||||
fromFile, ok := c.openedFiles.Lookup(from)
|
||||
if !ok {
|
||||
return syscall.EBADF
|
||||
@@ -443,11 +439,11 @@ func (c *FSContext) Renumber(from, to uint32) syscall.Errno {
|
||||
|
||||
c.openedFiles.Delete(from)
|
||||
c.openedFiles.InsertAt(fromFile, to)
|
||||
return 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloseFile returns any error closing the existing file.
|
||||
func (c *FSContext) CloseFile(fd uint32) syscall.Errno {
|
||||
func (c *FSContext) CloseFile(fd uint32) error {
|
||||
f, ok := c.openedFiles.Lookup(fd)
|
||||
if !ok {
|
||||
return syscall.EBADF
|
||||
@@ -457,7 +453,7 @@ func (c *FSContext) CloseFile(fd uint32) syscall.Errno {
|
||||
return syscall.ENOTSUP
|
||||
}
|
||||
c.openedFiles.Delete(fd)
|
||||
return platform.UnwrapOSError(f.File.Close())
|
||||
return f.File.Close()
|
||||
}
|
||||
|
||||
// Close implements api.Closer
|
||||
|
||||
@@ -76,8 +76,8 @@ func TestNewFSContext(t *testing.T) {
|
||||
|
||||
// Verify that each call to OpenFile returns a different file
|
||||
// descriptor.
|
||||
f1, errno := fsc.OpenFile(preopenedDir.FS, preopenedDir.Name, 0, 0)
|
||||
require.Zero(t, errno)
|
||||
f1, err := fsc.OpenFile(preopenedDir.FS, preopenedDir.Name, 0, 0)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, FdPreopen, f1)
|
||||
|
||||
// Verify that file descriptors are reused.
|
||||
@@ -88,9 +88,9 @@ func TestNewFSContext(t *testing.T) {
|
||||
// test to ensure that our implementation properly reuses descriptor
|
||||
// numbers but if we were to change the reuse strategy, this test
|
||||
// would likely break and need to be updated.
|
||||
require.Zero(t, fsc.CloseFile(f1))
|
||||
f2, errno := fsc.OpenFile(preopenedDir.FS, preopenedDir.Name, 0, 0)
|
||||
require.Zero(t, errno)
|
||||
require.NoError(t, fsc.CloseFile(f1))
|
||||
f2, err := fsc.OpenFile(preopenedDir.FS, preopenedDir.Name, 0, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, f1, f2)
|
||||
})
|
||||
}
|
||||
@@ -105,14 +105,14 @@ func TestFSContext_CloseFile(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer fsc.Close(testCtx)
|
||||
|
||||
fdToClose, errno := fsc.OpenFile(testFS, "empty.txt", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fdToClose, err := fsc.OpenFile(testFS, "empty.txt", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
fdToKeep, errno := fsc.OpenFile(testFS, "test.txt", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fdToKeep, err := fsc.OpenFile(testFS, "test.txt", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Close
|
||||
require.Zero(t, fsc.CloseFile(fdToClose))
|
||||
require.NoError(t, fsc.CloseFile(fdToClose))
|
||||
|
||||
// Verify fdToClose is closed and removed from the opened FDs.
|
||||
_, ok := fsc.LookupFile(fdToClose)
|
||||
@@ -123,10 +123,10 @@ 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.Equal(t, syscall.EBADF, fsc.CloseFile(42)) // 42 is an arbitrary invalid FD
|
||||
})
|
||||
t.Run("ENOTSUP for a preopen", func(t *testing.T) {
|
||||
require.EqualErrno(t, syscall.ENOTSUP, fsc.CloseFile(FdPreopen)) // 42 is an arbitrary invalid FD
|
||||
require.Equal(t, syscall.ENOTSUP, fsc.CloseFile(FdPreopen)) // 42 is an arbitrary invalid FD
|
||||
})
|
||||
}
|
||||
|
||||
@@ -187,8 +187,8 @@ func TestContext_Close(t *testing.T) {
|
||||
// Verify base case
|
||||
require.Equal(t, 1+FdPreopen, uint32(fsc.openedFiles.Len()))
|
||||
|
||||
_, errno := fsc.OpenFile(testFS, "foo", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
_, err = fsc.OpenFile(testFS, "foo", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2+FdPreopen, uint32(fsc.openedFiles.Len()))
|
||||
|
||||
// Closing should not err.
|
||||
@@ -210,8 +210,8 @@ func TestContext_Close_Error(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// open another file
|
||||
_, errno := fsc.OpenFile(testFS, "foo", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
_, err = fsc.OpenFile(testFS, "foo", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.EqualError(t, fsc.Close(testCtx), "error closing")
|
||||
|
||||
@@ -224,8 +224,8 @@ func TestFSContext_ReOpenDir(t *testing.T) {
|
||||
dirFs := sysfs.NewDirFS(tmpDir)
|
||||
|
||||
const dirName = "dir"
|
||||
errno := dirFs.Mkdir(dirName, 0o700)
|
||||
require.Zero(t, errno)
|
||||
err := dirFs.Mkdir(dirName, 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
fsc, err := NewFSContext(nil, nil, nil, dirFs)
|
||||
require.NoError(t, err)
|
||||
@@ -234,8 +234,8 @@ func TestFSContext_ReOpenDir(t *testing.T) {
|
||||
}()
|
||||
|
||||
t.Run("ok", func(t *testing.T) {
|
||||
dirFd, errno := fsc.OpenFile(dirFs, dirName, os.O_RDONLY, 0o600)
|
||||
require.Zero(t, errno)
|
||||
dirFd, err := fsc.OpenFile(dirFs, dirName, os.O_RDONLY, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
ent, ok := fsc.LookupFile(dirFd)
|
||||
require.True(t, ok)
|
||||
@@ -244,25 +244,24 @@ func TestFSContext_ReOpenDir(t *testing.T) {
|
||||
ent.ReadDir = &ReadDir{Dirents: make([]*platform.Dirent, 10), CountRead: 12345}
|
||||
|
||||
// Then reopen the same file descriptor.
|
||||
ent, errno = fsc.ReOpenDir(dirFd)
|
||||
require.Zero(t, errno)
|
||||
ent, err = fsc.ReOpenDir(dirFd)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify the read dir state has been reset.
|
||||
require.Equal(t, &ReadDir{}, ent.ReadDir)
|
||||
})
|
||||
|
||||
t.Run("non existing ", func(t *testing.T) {
|
||||
_, errno = fsc.ReOpenDir(12345)
|
||||
require.EqualErrno(t, syscall.EBADF, errno)
|
||||
_, err = fsc.ReOpenDir(12345)
|
||||
require.ErrorIs(t, err, syscall.EBADF)
|
||||
})
|
||||
|
||||
t.Run("not dir", func(t *testing.T) {
|
||||
const fileName = "dog"
|
||||
fd, errno := fsc.OpenFile(dirFs, fileName, os.O_CREATE, 0o600)
|
||||
require.Zero(t, errno)
|
||||
|
||||
_, errno = fsc.ReOpenDir(fd)
|
||||
require.EqualErrno(t, syscall.EISDIR, errno)
|
||||
fd, err := fsc.OpenFile(dirFs, fileName, os.O_CREATE, 0o600)
|
||||
require.NoError(t, err)
|
||||
_, err = fsc.ReOpenDir(fd)
|
||||
require.ErrorIs(t, err, syscall.EISDIR)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -271,8 +270,8 @@ func TestFSContext_Renumber(t *testing.T) {
|
||||
dirFs := sysfs.NewDirFS(tmpDir)
|
||||
|
||||
const dirName = "dir"
|
||||
errno := dirFs.Mkdir(dirName, 0o700)
|
||||
require.Zero(t, errno)
|
||||
err := dirFs.Mkdir(dirName, 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := NewFSContext(nil, nil, nil, dirFs)
|
||||
require.NoError(t, err)
|
||||
@@ -281,13 +280,13 @@ func TestFSContext_Renumber(t *testing.T) {
|
||||
}()
|
||||
|
||||
for _, toFd := range []uint32{10, 100, 100} {
|
||||
fromFd, errno := c.OpenFile(dirFs, dirName, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
fromFd, err := c.OpenFile(dirFs, dirName, os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
prevDirFile, ok := c.LookupFile(fromFd)
|
||||
require.True(t, ok)
|
||||
|
||||
require.Zero(t, c.Renumber(fromFd, toFd))
|
||||
require.Equal(t, nil, c.Renumber(fromFd, toFd))
|
||||
|
||||
renumberedDirFile, ok := c.LookupFile(toFd)
|
||||
require.True(t, ok)
|
||||
@@ -323,28 +322,27 @@ func TestFSContext_ChangeOpenFlag(t *testing.T) {
|
||||
const fileName = "dir"
|
||||
require.NoError(t, os.WriteFile(path.Join(tmpDir, fileName), []byte("0123456789"), 0o600))
|
||||
|
||||
c, errno := NewFSContext(nil, nil, nil, dirFs)
|
||||
require.NoError(t, errno)
|
||||
c, err := NewFSContext(nil, nil, nil, dirFs)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
require.NoError(t, c.Close(context.Background()))
|
||||
}()
|
||||
|
||||
// Without APPEND.
|
||||
fd, errno := c.OpenFile(dirFs, fileName, os.O_RDWR, 0o600)
|
||||
require.Zero(t, errno)
|
||||
|
||||
fd, err := c.OpenFile(dirFs, fileName, os.O_RDWR, 0o600)
|
||||
require.NoError(t, err)
|
||||
f0, ok := c.openedFiles.Lookup(fd)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, f0.openFlag&syscall.O_APPEND, 0)
|
||||
|
||||
// Set the APPEND flag.
|
||||
require.Zero(t, c.ChangeOpenFlag(fd, syscall.O_APPEND))
|
||||
require.NoError(t, c.ChangeOpenFlag(fd, syscall.O_APPEND))
|
||||
f1, ok := c.openedFiles.Lookup(fd)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, f1.openFlag&syscall.O_APPEND, syscall.O_APPEND)
|
||||
|
||||
// Remove the APPEND flag.
|
||||
require.Zero(t, c.ChangeOpenFlag(fd, 0))
|
||||
require.NoError(t, c.ChangeOpenFlag(fd, 0))
|
||||
f2, ok := c.openedFiles.Lookup(fd)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, f2.openFlag&syscall.O_APPEND, 0)
|
||||
|
||||
@@ -88,8 +88,8 @@ func TestFileEntry_cachedStat(t *testing.T) {
|
||||
dirFS := sysfs.NewDirFS(tmpDir)
|
||||
|
||||
// get the expected inode
|
||||
st, errno := platform.Stat(tmpDir)
|
||||
require.Zero(t, errno)
|
||||
st, err := platform.Stat(tmpDir)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
)
|
||||
@@ -45,14 +44,14 @@ func (a *adapter) Open(name string) (fs.File, error) {
|
||||
}
|
||||
|
||||
// OpenFile implements FS.OpenFile
|
||||
func (a *adapter) OpenFile(path string, flag int, perm fs.FileMode) (fs.File, syscall.Errno) {
|
||||
func (a *adapter) OpenFile(path string, flag int, perm fs.FileMode) (fs.File, error) {
|
||||
path = cleanPath(path)
|
||||
f, err := a.fs.Open(path)
|
||||
return f, platform.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Stat implements FS.Stat
|
||||
func (a *adapter) Stat(path string) (platform.Stat_t, syscall.Errno) {
|
||||
func (a *adapter) Stat(path string) (platform.Stat_t, error) {
|
||||
name := cleanPath(path)
|
||||
f, err := a.fs.Open(name)
|
||||
if err != nil {
|
||||
@@ -63,7 +62,7 @@ func (a *adapter) Stat(path string) (platform.Stat_t, syscall.Errno) {
|
||||
}
|
||||
|
||||
// Lstat implements FS.Lstat
|
||||
func (a *adapter) Lstat(path string) (platform.Stat_t, syscall.Errno) {
|
||||
func (a *adapter) Lstat(path string) (platform.Stat_t, error) {
|
||||
// At this time, we make the assumption that fs.FS instances do not support
|
||||
// symbolic links, therefore Lstat is the same as Stat. This is obviously
|
||||
// not true but until fs.FS has a solid story for how to handle symlinks we
|
||||
@@ -104,7 +103,7 @@ func fsOpen(f FS, name string) (fs.File, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if f, err := f.OpenFile(name, os.O_RDONLY, 0); err != 0 {
|
||||
if f, err := f.OpenFile(name, os.O_RDONLY, 0); err != nil {
|
||||
return nil, &fs.PathError{Op: "open", Path: name, Err: err}
|
||||
} else {
|
||||
return f, nil
|
||||
|
||||
@@ -125,9 +125,8 @@ func TestAdapt_Lstat(t *testing.T) {
|
||||
fullPath := joinPath(tmpDir, path)
|
||||
linkPath := joinPath(tmpDir, path+"-link")
|
||||
require.NoError(t, os.Symlink(fullPath, linkPath))
|
||||
|
||||
_, errno := testFS.Lstat(filepath.Base(linkPath))
|
||||
require.Zero(t, errno)
|
||||
_, err := testFS.Lstat(filepath.Base(linkPath))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,95 +41,96 @@ func (d *dirFS) Open(name string) (fs.File, error) {
|
||||
}
|
||||
|
||||
// OpenFile implements FS.OpenFile
|
||||
func (d *dirFS) OpenFile(path string, flag int, perm fs.FileMode) (fs.File, syscall.Errno) {
|
||||
func (d *dirFS) OpenFile(path string, flag int, perm fs.FileMode) (fs.File, error) {
|
||||
return platform.OpenFile(d.join(path), flag, perm)
|
||||
}
|
||||
|
||||
// Lstat implements FS.Lstat
|
||||
func (d *dirFS) Lstat(path string) (platform.Stat_t, syscall.Errno) {
|
||||
func (d *dirFS) Lstat(path string) (platform.Stat_t, error) {
|
||||
return platform.Lstat(d.join(path))
|
||||
}
|
||||
|
||||
// Stat implements FS.Stat
|
||||
func (d *dirFS) Stat(path string) (platform.Stat_t, syscall.Errno) {
|
||||
func (d *dirFS) Stat(path string) (platform.Stat_t, error) {
|
||||
return platform.Stat(d.join(path))
|
||||
}
|
||||
|
||||
// Mkdir implements FS.Mkdir
|
||||
func (d *dirFS) Mkdir(path string, perm fs.FileMode) (errno syscall.Errno) {
|
||||
err := os.Mkdir(d.join(path), perm)
|
||||
if errno = platform.UnwrapOSError(err); errno == syscall.ENOTDIR {
|
||||
errno = syscall.ENOENT
|
||||
func (d *dirFS) Mkdir(path string, perm fs.FileMode) (err error) {
|
||||
err = os.Mkdir(d.join(path), perm)
|
||||
if err = platform.UnwrapOSError(err); err == syscall.ENOTDIR {
|
||||
err = syscall.ENOENT
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Chmod implements FS.Chmod
|
||||
func (d *dirFS) Chmod(path string, perm fs.FileMode) syscall.Errno {
|
||||
func (d *dirFS) Chmod(path string, perm fs.FileMode) error {
|
||||
err := os.Chmod(d.join(path), perm)
|
||||
return platform.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Chown implements FS.Chown
|
||||
func (d *dirFS) Chown(path string, uid, gid int) syscall.Errno {
|
||||
func (d *dirFS) Chown(path string, uid, gid int) error {
|
||||
return platform.Chown(d.join(path), uid, gid)
|
||||
}
|
||||
|
||||
// Lchown implements FS.Lchown
|
||||
func (d *dirFS) Lchown(path string, uid, gid int) syscall.Errno {
|
||||
func (d *dirFS) Lchown(path string, uid, gid int) error {
|
||||
return platform.Lchown(d.join(path), uid, gid)
|
||||
}
|
||||
|
||||
// Rename implements FS.Rename
|
||||
func (d *dirFS) Rename(from, to string) syscall.Errno {
|
||||
func (d *dirFS) Rename(from, to string) error {
|
||||
from, to = d.join(from), d.join(to)
|
||||
return platform.Rename(from, to)
|
||||
err := platform.Rename(from, to)
|
||||
return platform.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Readlink implements FS.Readlink
|
||||
func (d *dirFS) Readlink(path string) (string, syscall.Errno) {
|
||||
func (d *dirFS) Readlink(path string) (string, error) {
|
||||
// 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 platform.ToPosixPath(dst), 0
|
||||
return platform.ToPosixPath(dst), nil
|
||||
}
|
||||
|
||||
// Link implements FS.Link.
|
||||
func (d *dirFS) Link(oldName, newName string) syscall.Errno {
|
||||
func (d *dirFS) Link(oldName, newName string) error {
|
||||
err := os.Link(d.join(oldName), d.join(newName))
|
||||
return platform.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Rmdir implements FS.Rmdir
|
||||
func (d *dirFS) Rmdir(path string) syscall.Errno {
|
||||
func (d *dirFS) Rmdir(path string) error {
|
||||
err := syscall.Rmdir(d.join(path))
|
||||
return platform.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Unlink implements FS.Unlink
|
||||
func (d *dirFS) Unlink(path string) (err syscall.Errno) {
|
||||
func (d *dirFS) Unlink(path string) (err error) {
|
||||
return platform.Unlink(d.join(path))
|
||||
}
|
||||
|
||||
// Symlink implements FS.Symlink
|
||||
func (d *dirFS) Symlink(oldName, link string) syscall.Errno {
|
||||
func (d *dirFS) Symlink(oldName, link string) (err error) {
|
||||
// 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))
|
||||
err = os.Symlink(oldName, d.join(link))
|
||||
return platform.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
// Utimens implements FS.Utimens
|
||||
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) error {
|
||||
return platform.Utimens(d.join(path), times, symlinkFollow)
|
||||
}
|
||||
|
||||
// Truncate implements FS.Truncate
|
||||
func (d *dirFS) Truncate(path string, size int64) syscall.Errno {
|
||||
func (d *dirFS) Truncate(path string, size int64) error {
|
||||
// Use os.Truncate as syscall.Truncate doesn't exist on Windows.
|
||||
err := os.Truncate(d.join(path), size)
|
||||
return platform.UnwrapOSError(err)
|
||||
|
||||
@@ -19,22 +19,22 @@ func TestNewDirFS(t *testing.T) {
|
||||
testFS := NewDirFS(".")
|
||||
|
||||
// Guest can look up /
|
||||
f, errno := testFS.OpenFile("/", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
f, err := testFS.OpenFile("/", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.Close())
|
||||
|
||||
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)
|
||||
_, err = testFS.OpenFile(".", os.O_RDONLY, 0)
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
})
|
||||
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.
|
||||
|
||||
testFS := NewDirFS(arg0)
|
||||
d, errno := testFS.OpenFile(".", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
_, err := d.(fs.ReadDirFile).ReadDir(-1)
|
||||
d, err := testFS.OpenFile(".", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
_, err = d.(fs.ReadDirFile).ReadDir(-1)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, platform.UnwrapOSError(err))
|
||||
})
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func TestDirFS_Lstat(t *testing.T) {
|
||||
|
||||
testFS := NewDirFS(tmpDir)
|
||||
for _, path := range []string{"animals.txt", "sub", "sub-link"} {
|
||||
require.Zero(t, testFS.Symlink(path, path+"-link"))
|
||||
require.NoError(t, testFS.Symlink(path, path+"-link"))
|
||||
}
|
||||
|
||||
testLstat(t, testFS)
|
||||
@@ -80,11 +80,9 @@ func TestDirFS_MkDir(t *testing.T) {
|
||||
realPath := path.Join(tmpDir, name)
|
||||
|
||||
t.Run("doesn't exist", func(t *testing.T) {
|
||||
require.Zero(t, testFS.Mkdir(name, fs.ModeDir))
|
||||
|
||||
require.NoError(t, testFS.Mkdir(name, fs.ModeDir))
|
||||
stat, err := os.Stat(realPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, name, stat.Name())
|
||||
require.True(t, stat.IsDir())
|
||||
})
|
||||
@@ -131,20 +129,19 @@ func testChmod(t *testing.T, testFS FS, path string) {
|
||||
requireMode(t, testFS, path, 0o444)
|
||||
|
||||
// Test adding write, using 0o666 not 0o600 for read-back on windows.
|
||||
require.Zero(t, testFS.Chmod(path, 0o666))
|
||||
require.NoError(t, testFS.Chmod(path, 0o666))
|
||||
requireMode(t, testFS, path, 0o666)
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
// Test clearing group and world, setting owner read+execute.
|
||||
require.Zero(t, testFS.Chmod(path, 0o500))
|
||||
require.NoError(t, testFS.Chmod(path, 0o500))
|
||||
requireMode(t, testFS, path, 0o500)
|
||||
}
|
||||
}
|
||||
|
||||
func requireMode(t *testing.T, testFS FS, path string, mode fs.FileMode) {
|
||||
st, errno := testFS.Stat(path)
|
||||
require.Zero(t, errno)
|
||||
|
||||
st, err := testFS.Stat(path)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, mode, st.Mode.Perm())
|
||||
}
|
||||
|
||||
@@ -168,17 +165,17 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
file1 := "file1"
|
||||
file1Path := path.Join(tmpDir, file1)
|
||||
file1Contents := []byte{1}
|
||||
errno := os.WriteFile(file1Path, file1Contents, 0o600)
|
||||
require.NoError(t, errno)
|
||||
err := os.WriteFile(file1Path, file1Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
file2 := "file2"
|
||||
file2Path := path.Join(tmpDir, file2)
|
||||
errno = testFS.Rename(file1, file2)
|
||||
require.Zero(t, errno)
|
||||
err = testFS.Rename(file1, file2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, errno = os.Stat(file1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, platform.UnwrapOSError(errno))
|
||||
_, err = os.Stat(file1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, platform.UnwrapOSError(err))
|
||||
|
||||
s, err := os.Stat(file2Path)
|
||||
require.NoError(t, err)
|
||||
@@ -194,11 +191,11 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
|
||||
dir2 := "dir2"
|
||||
dir2Path := path.Join(tmpDir, dir2)
|
||||
errrno := testFS.Rename(dir1, dir2)
|
||||
require.Zero(t, errrno)
|
||||
err := testFS.Rename(dir1, dir2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err := os.Stat(dir1Path)
|
||||
_, err = os.Stat(dir1Path)
|
||||
require.EqualErrno(t, syscall.ENOENT, platform.UnwrapOSError(err))
|
||||
|
||||
s, err := os.Stat(dir2Path)
|
||||
@@ -221,8 +218,8 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.Close())
|
||||
|
||||
errno := testFS.Rename(dir1, dir2)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, errno)
|
||||
err = testFS.Rename(dir1, dir2)
|
||||
require.EqualErrno(t, syscall.ENOTDIR, err)
|
||||
})
|
||||
t.Run("file to dir", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
@@ -238,8 +235,8 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
dir1Path := path.Join(tmpDir, dir1)
|
||||
require.NoError(t, os.Mkdir(dir1Path, 0o700))
|
||||
|
||||
errno := testFS.Rename(file1, dir1)
|
||||
require.EqualErrno(t, syscall.EISDIR, errno)
|
||||
err = testFS.Rename(file1, dir1)
|
||||
require.EqualErrno(t, syscall.EISDIR, err)
|
||||
})
|
||||
|
||||
// Similar to https://github.com/ziglang/zig/blob/0.10.1/lib/std/fs/test.zig#L567-L582
|
||||
@@ -262,8 +259,8 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
dir2Path := path.Join(tmpDir, dir2)
|
||||
require.NoError(t, os.Mkdir(dir2Path, 0o700))
|
||||
|
||||
errno := testFS.Rename(dir1, dir2)
|
||||
require.Zero(t, errno)
|
||||
err = testFS.Rename(dir1, dir2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err = os.Stat(dir1Path)
|
||||
@@ -299,8 +296,8 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
err = os.WriteFile(path.Join(dir2Path, "existing.txt"), []byte("any thing"), 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
errno := testFS.Rename(dir1, dir2)
|
||||
require.EqualErrno(t, syscall.ENOTEMPTY, errno)
|
||||
err = testFS.Rename(dir1, dir2)
|
||||
require.EqualErrno(t, syscall.ENOTEMPTY, err)
|
||||
})
|
||||
|
||||
t.Run("file to file", func(t *testing.T) {
|
||||
@@ -319,8 +316,8 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
err = os.WriteFile(file2Path, file2Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
errno := testFS.Rename(file1, file2)
|
||||
require.Zero(t, errno)
|
||||
err = testFS.Rename(file1, file2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Show the prior path no longer exists
|
||||
_, err = os.Stat(file1Path)
|
||||
@@ -339,8 +336,8 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
dir1Path := path.Join(tmpDir, dir1)
|
||||
require.NoError(t, os.Mkdir(dir1Path, 0o700))
|
||||
|
||||
errno := testFS.Rename(dir1, dir1)
|
||||
require.Zero(t, errno)
|
||||
err := testFS.Rename(dir1, dir1)
|
||||
require.NoError(t, err)
|
||||
|
||||
s, err := os.Stat(dir1Path)
|
||||
require.NoError(t, err)
|
||||
@@ -356,8 +353,8 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
err := os.WriteFile(file1Path, file1Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
errno := testFS.Rename(file1, file1)
|
||||
require.Zero(t, errno)
|
||||
err = testFS.Rename(file1, file1)
|
||||
require.NoError(t, err)
|
||||
|
||||
b, err := os.ReadFile(file1Path)
|
||||
require.NoError(t, err)
|
||||
@@ -407,8 +404,8 @@ func TestDirFS_Rmdir(t *testing.T) {
|
||||
require.NoError(t, os.Remove(fileInDir))
|
||||
|
||||
// After deletion, try removing directory.
|
||||
errno := testFS.Rmdir(name)
|
||||
require.Zero(t, errno)
|
||||
err := testFS.Rmdir(name)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("dir empty", func(t *testing.T) {
|
||||
@@ -418,7 +415,7 @@ func TestDirFS_Rmdir(t *testing.T) {
|
||||
name := "rmdir"
|
||||
realPath := path.Join(tmpDir, name)
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
require.Zero(t, testFS.Rmdir(name))
|
||||
require.NoError(t, testFS.Rmdir(name))
|
||||
_, err := os.Stat(realPath)
|
||||
require.Error(t, err)
|
||||
})
|
||||
@@ -431,14 +428,14 @@ func TestDirFS_Rmdir(t *testing.T) {
|
||||
realPath := path.Join(tmpDir, name)
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
|
||||
f, errno := testFS.OpenFile(name, platform.O_DIRECTORY, 0o700)
|
||||
require.Zero(t, errno)
|
||||
f, err := testFS.OpenFile(name, platform.O_DIRECTORY, 0o700)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
require.NoError(t, f.Close())
|
||||
}()
|
||||
|
||||
require.Zero(t, testFS.Rmdir(name))
|
||||
_, err := os.Stat(realPath)
|
||||
require.NoError(t, testFS.Rmdir(name))
|
||||
_, err = os.Stat(realPath)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
@@ -494,11 +491,11 @@ func TestDirFS_Unlink(t *testing.T) {
|
||||
|
||||
// Create a symlink to the subdirectory.
|
||||
const symlinkName = "symlink-to-dir"
|
||||
require.Zero(t, testFS.Symlink("subdir", symlinkName))
|
||||
require.NoError(t, testFS.Symlink("subdir", symlinkName))
|
||||
|
||||
// Unlinking the symlink should suceed.
|
||||
err := testFS.Unlink(symlinkName)
|
||||
require.Zero(t, err)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("file exists", func(t *testing.T) {
|
||||
@@ -510,8 +507,7 @@ func TestDirFS_Unlink(t *testing.T) {
|
||||
|
||||
require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600))
|
||||
|
||||
require.Zero(t, testFS.Unlink(name))
|
||||
|
||||
require.NoError(t, testFS.Unlink(name))
|
||||
_, err := os.Stat(realPath)
|
||||
require.Error(t, err)
|
||||
})
|
||||
@@ -614,15 +610,15 @@ func TestDirFS_Utimesns(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
file := path.Join(tmpDir, "file")
|
||||
errno := os.WriteFile(file, []byte{}, 0o700)
|
||||
require.NoError(t, errno)
|
||||
err := os.WriteFile(file, []byte{}, 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
link := file + "-link"
|
||||
require.NoError(t, os.Symlink(file, link))
|
||||
|
||||
dir := path.Join(tmpDir, "dir")
|
||||
errno = os.Mkdir(dir, 0o700)
|
||||
require.NoError(t, errno)
|
||||
err = os.Mkdir(dir, 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
var path, statPath string
|
||||
switch fileType {
|
||||
@@ -642,18 +638,18 @@ func TestDirFS_Utimesns(t *testing.T) {
|
||||
panic(tc)
|
||||
}
|
||||
|
||||
oldSt, errno := testFS.Lstat(statPath)
|
||||
require.Zero(t, errno)
|
||||
oldSt, err := testFS.Lstat(statPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
errno = testFS.Utimens(path, tc.times, !symlinkNoFollow)
|
||||
err = testFS.Utimens(path, tc.times, !symlinkNoFollow)
|
||||
if symlinkNoFollow && !platform.SupportsSymlinkNoFollow {
|
||||
require.EqualErrno(t, syscall.ENOSYS, errno)
|
||||
require.EqualErrno(t, syscall.ENOSYS, err)
|
||||
return
|
||||
}
|
||||
require.Zero(t, errno)
|
||||
require.NoError(t, err)
|
||||
|
||||
newSt, errno := testFS.Lstat(statPath)
|
||||
require.Zero(t, errno)
|
||||
newSt, err := testFS.Lstat(statPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
if platform.CompilerSupported() {
|
||||
if tc.times != nil && tc.times[0].Nsec == platform.UTIME_OMIT {
|
||||
@@ -715,8 +711,8 @@ func TestDirFS_Stat(t *testing.T) {
|
||||
name := `e:xperi\ment.txt`
|
||||
require.NoError(t, os.WriteFile(path.Join(tmpDir, name), nil, 0o600))
|
||||
|
||||
_, errno := testFS.Stat(name)
|
||||
require.Zero(t, errno)
|
||||
_, err := testFS.Stat(name)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -762,8 +758,8 @@ func TestDirFS_Truncate(t *testing.T) {
|
||||
realPath := path.Join(tmpDir, name)
|
||||
require.NoError(t, os.WriteFile(realPath, content, 0o0600))
|
||||
|
||||
errno := testFS.Truncate(name, tc.size)
|
||||
require.Zero(t, errno)
|
||||
err := testFS.Truncate(name, tc.size)
|
||||
require.NoError(t, err)
|
||||
|
||||
actual, err := os.ReadFile(realPath)
|
||||
require.NoError(t, err)
|
||||
@@ -825,12 +821,12 @@ func Test_fdReaddir_opened_file_written(t *testing.T) {
|
||||
testFS := NewDirFS(root)
|
||||
|
||||
const readDirTarget = "dir"
|
||||
errno := testFS.Mkdir(readDirTarget, 0o700)
|
||||
require.Zero(t, errno)
|
||||
err := testFS.Mkdir(readDirTarget, 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Open the directory, before writing files!
|
||||
dirFile, errno := testFS.OpenFile(readDirTarget, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
dirFile, err := testFS.OpenFile(readDirTarget, os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer dirFile.Close()
|
||||
|
||||
// Then write a file to the directory.
|
||||
@@ -857,12 +853,12 @@ 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.Zero(t, testFS.Link("sub/test.txt", "foo"))
|
||||
require.ErrorIs(t, testFS.Link("cat", ""), syscall.ENOENT)
|
||||
require.ErrorIs(t, testFS.Link("sub/test.txt", "sub/test.txt"), syscall.EEXIST)
|
||||
require.ErrorIs(t, testFS.Link("sub/test.txt", "."), syscall.EEXIST)
|
||||
require.ErrorIs(t, testFS.Link("sub/test.txt", ""), syscall.EEXIST)
|
||||
require.ErrorIs(t, testFS.Link("sub/test.txt", "/"), syscall.EEXIST)
|
||||
require.NoError(t, testFS.Link("sub/test.txt", "foo"))
|
||||
}
|
||||
|
||||
func TestDirFS_Symlink(t *testing.T) {
|
||||
@@ -874,10 +870,10 @@ func TestDirFS_Symlink(t *testing.T) {
|
||||
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
require.EqualErrno(t, testFS.Symlink("sub/test.txt", "sub/test.txt"), syscall.EEXIST)
|
||||
require.ErrorIs(t, testFS.Symlink("sub/test.txt", "sub/test.txt"), syscall.EEXIST)
|
||||
// Non-existing old name is allowed.
|
||||
require.Zero(t, testFS.Symlink("non-existing", "aa"))
|
||||
require.Zero(t, testFS.Symlink("sub/", "symlinked-subdir"))
|
||||
require.NoError(t, testFS.Symlink("non-existing", "aa"))
|
||||
require.NoError(t, testFS.Symlink("sub/", "symlinked-subdir"))
|
||||
|
||||
st, err := os.Lstat(path.Join(tmpDir, "aa"))
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -17,13 +17,11 @@ func TestDirFS_Chown(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
require.Zero(t, testFS.Mkdir("dir", 0o0777))
|
||||
dirF, errno := testFS.OpenFile("dir", syscall.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
|
||||
require.NoError(t, testFS.Mkdir("dir", 0o0777))
|
||||
dirF, err := testFS.OpenFile("dir", syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
dirStat, err := dirF.Stat()
|
||||
require.NoError(t, err)
|
||||
|
||||
dirSys := dirStat.Sys().(*syscall.Stat_t)
|
||||
|
||||
// Similar to TestChown in os_unix_test.go, we can't expect to change
|
||||
@@ -33,12 +31,12 @@ func TestDirFS_Chown(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("-1 parameters means leave alone", func(t *testing.T) {
|
||||
require.Zero(t, testFS.Chown("dir", -1, -1))
|
||||
require.NoError(t, testFS.Chown("dir", -1, -1))
|
||||
checkUidGid(t, path.Join(tmpDir, "dir"), dirSys.Uid, dirSys.Gid)
|
||||
})
|
||||
|
||||
t.Run("change gid, but not uid", func(t *testing.T) {
|
||||
require.Zero(t, testFS.Chown("dir", -1, gid))
|
||||
require.NoError(t, testFS.Chown("dir", -1, gid))
|
||||
checkUidGid(t, path.Join(tmpDir, "dir"), dirSys.Uid, uint32(gid))
|
||||
})
|
||||
|
||||
@@ -47,11 +45,11 @@ func TestDirFS_Chown(t *testing.T) {
|
||||
g := g
|
||||
t.Run(fmt.Sprintf("change to gid %d", g), func(t *testing.T) {
|
||||
// Test using our Chown
|
||||
require.Zero(t, testFS.Chown("dir", -1, g))
|
||||
require.NoError(t, testFS.Chown("dir", -1, g))
|
||||
checkUidGid(t, path.Join(tmpDir, "dir"), dirSys.Uid, uint32(g))
|
||||
|
||||
// Revert back with platform.ChownFile
|
||||
require.Zero(t, platform.ChownFile(dirF, -1, gid))
|
||||
require.NoError(t, platform.ChownFile(dirF, -1, gid))
|
||||
checkUidGid(t, path.Join(tmpDir, "dir"), dirSys.Uid, uint32(gid))
|
||||
})
|
||||
}
|
||||
@@ -65,22 +63,18 @@ func TestDirFS_Lchown(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
require.Zero(t, testFS.Mkdir("dir", 0o0777))
|
||||
dirF, errno := testFS.OpenFile("dir", syscall.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
|
||||
require.NoError(t, testFS.Mkdir("dir", 0o0777))
|
||||
dirF, err := testFS.OpenFile("dir", syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
dirStat, err := dirF.Stat()
|
||||
require.NoError(t, err)
|
||||
|
||||
dirSys := dirStat.Sys().(*syscall.Stat_t)
|
||||
|
||||
require.Zero(t, testFS.Symlink("dir", "link"))
|
||||
linkF, errno := testFS.OpenFile("link", syscall.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
|
||||
require.NoError(t, testFS.Symlink("dir", "link"))
|
||||
linkF, err := testFS.OpenFile("link", syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
linkStat, err := linkF.Stat()
|
||||
require.NoError(t, err)
|
||||
|
||||
linkSys := linkStat.Sys().(*syscall.Stat_t)
|
||||
|
||||
// Similar to TestLchown in os_unix_test.go, we can't expect to change
|
||||
@@ -90,12 +84,12 @@ func TestDirFS_Lchown(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("-1 parameters means leave alone", func(t *testing.T) {
|
||||
require.Zero(t, testFS.Lchown("link", -1, -1))
|
||||
require.NoError(t, testFS.Lchown("link", -1, -1))
|
||||
checkUidGid(t, path.Join(tmpDir, "link"), linkSys.Uid, linkSys.Gid)
|
||||
})
|
||||
|
||||
t.Run("change gid, but not uid", func(t *testing.T) {
|
||||
require.Zero(t, testFS.Chown("dir", -1, gid))
|
||||
require.NoError(t, testFS.Chown("dir", -1, gid))
|
||||
checkUidGid(t, path.Join(tmpDir, "link"), linkSys.Uid, uint32(gid))
|
||||
// Make sure the target didn't change.
|
||||
checkUidGid(t, path.Join(tmpDir, "dir"), dirSys.Uid, dirSys.Gid)
|
||||
@@ -106,7 +100,7 @@ func TestDirFS_Lchown(t *testing.T) {
|
||||
g := g
|
||||
t.Run(fmt.Sprintf("change to gid %d", g), func(t *testing.T) {
|
||||
// Test using our Lchown
|
||||
require.Zero(t, testFS.Lchown("link", -1, g))
|
||||
require.NoError(t, testFS.Lchown("link", -1, g))
|
||||
checkUidGid(t, path.Join(tmpDir, "link"), linkSys.Uid, uint32(g))
|
||||
// Make sure the target didn't change.
|
||||
checkUidGid(t, path.Join(tmpDir, "dir"), dirSys.Uid, dirSys.Gid)
|
||||
|
||||
@@ -37,7 +37,7 @@ func (r *readFS) Open(name string) (fs.File, error) {
|
||||
}
|
||||
|
||||
// OpenFile implements FS.OpenFile
|
||||
func (r *readFS) OpenFile(path string, flag int, perm fs.FileMode) (fs.File, syscall.Errno) {
|
||||
func (r *readFS) OpenFile(path string, flag int, perm fs.FileMode) (fs.File, error) {
|
||||
// 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.
|
||||
@@ -63,11 +63,11 @@ func (r *readFS) OpenFile(path string, flag int, perm fs.FileMode) (fs.File, sys
|
||||
default: // os.O_RDONLY so we are ok!
|
||||
}
|
||||
|
||||
f, errno := r.fs.OpenFile(path, flag, perm)
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
f, err := r.fs.OpenFile(path, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return maskForReads(f), 0
|
||||
return maskForReads(f), nil
|
||||
}
|
||||
|
||||
// maskForReads masks the file with read-only interfaces used by wazero.
|
||||
@@ -141,71 +141,71 @@ func maskForReads(f fs.File) fs.File {
|
||||
}
|
||||
|
||||
// Lstat implements FS.Lstat
|
||||
func (r *readFS) Lstat(path string) (platform.Stat_t, syscall.Errno) {
|
||||
func (r *readFS) Lstat(path string) (platform.Stat_t, error) {
|
||||
return r.fs.Lstat(path)
|
||||
}
|
||||
|
||||
// Stat implements FS.Stat
|
||||
func (r *readFS) Stat(path string) (platform.Stat_t, syscall.Errno) {
|
||||
func (r *readFS) Stat(path string) (platform.Stat_t, error) {
|
||||
return r.fs.Stat(path)
|
||||
}
|
||||
|
||||
// Readlink implements FS.Readlink
|
||||
func (r *readFS) Readlink(path string) (dst string, err syscall.Errno) {
|
||||
func (r *readFS) Readlink(path string) (dst string, err error) {
|
||||
return r.fs.Readlink(path)
|
||||
}
|
||||
|
||||
// Mkdir implements FS.Mkdir
|
||||
func (r *readFS) Mkdir(path string, perm fs.FileMode) syscall.Errno {
|
||||
func (r *readFS) Mkdir(path string, perm fs.FileMode) error {
|
||||
return syscall.EROFS
|
||||
}
|
||||
|
||||
// Chmod implements FS.Chmod
|
||||
func (r *readFS) Chmod(path string, perm fs.FileMode) syscall.Errno {
|
||||
func (r *readFS) Chmod(path string, perm fs.FileMode) error {
|
||||
return syscall.EROFS
|
||||
}
|
||||
|
||||
// Chown implements FS.Chown
|
||||
func (r *readFS) Chown(path string, uid, gid int) syscall.Errno {
|
||||
func (r *readFS) Chown(path string, uid, gid int) error {
|
||||
return syscall.EROFS
|
||||
}
|
||||
|
||||
// Lchown implements FS.Lchown
|
||||
func (r *readFS) Lchown(path string, uid, gid int) syscall.Errno {
|
||||
func (r *readFS) Lchown(path string, uid, gid int) error {
|
||||
return syscall.EROFS
|
||||
}
|
||||
|
||||
// Rename implements FS.Rename
|
||||
func (r *readFS) Rename(from, to string) syscall.Errno {
|
||||
func (r *readFS) Rename(from, to string) error {
|
||||
return syscall.EROFS
|
||||
}
|
||||
|
||||
// Rmdir implements FS.Rmdir
|
||||
func (r *readFS) Rmdir(path string) syscall.Errno {
|
||||
func (r *readFS) Rmdir(path string) error {
|
||||
return syscall.EROFS
|
||||
}
|
||||
|
||||
// Link implements FS.Link
|
||||
func (r *readFS) Link(_, _ string) syscall.Errno {
|
||||
func (r *readFS) Link(_, _ string) error {
|
||||
return syscall.EROFS
|
||||
}
|
||||
|
||||
// Symlink implements FS.Symlink
|
||||
func (r *readFS) Symlink(_, _ string) syscall.Errno {
|
||||
func (r *readFS) Symlink(_, _ string) error {
|
||||
return syscall.EROFS
|
||||
}
|
||||
|
||||
// Unlink implements FS.Unlink
|
||||
func (r *readFS) Unlink(path string) syscall.Errno {
|
||||
func (r *readFS) Unlink(path string) error {
|
||||
return syscall.EROFS
|
||||
}
|
||||
|
||||
// Utimens implements FS.Utimens
|
||||
func (r *readFS) Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) syscall.Errno {
|
||||
func (r *readFS) Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) error {
|
||||
return syscall.EROFS
|
||||
}
|
||||
|
||||
// Truncate implements FS.Truncate
|
||||
func (r *readFS) Truncate(string, int64) syscall.Errno {
|
||||
func (r *readFS) Truncate(string, int64) error {
|
||||
return syscall.EROFS
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func TestReadFS_Lstat(t *testing.T) {
|
||||
|
||||
writeable := NewDirFS(tmpDir)
|
||||
for _, path := range []string{"animals.txt", "sub", "sub-link"} {
|
||||
require.Zero(t, writeable.Symlink(path, path+"-link"))
|
||||
require.NoError(t, writeable.Symlink(path, path+"-link"))
|
||||
}
|
||||
|
||||
testFS := NewReadFS(writeable)
|
||||
|
||||
@@ -123,11 +123,11 @@ func (c *CompositeFS) Open(name string) (fs.File, error) {
|
||||
}
|
||||
|
||||
// OpenFile implements FS.OpenFile
|
||||
func (c *CompositeFS) OpenFile(path string, flag int, perm fs.FileMode) (f fs.File, err syscall.Errno) {
|
||||
func (c *CompositeFS) OpenFile(path string, flag int, perm fs.FileMode) (f fs.File, err error) {
|
||||
matchIndex, relativePath := c.chooseFS(path)
|
||||
|
||||
f, err = c.fs[matchIndex].OpenFile(relativePath, flag, perm)
|
||||
if err != 0 {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ func (d *openRootDir) readDir() (err error) {
|
||||
}
|
||||
|
||||
func (d *openRootDir) rootEntry(name string, fsI int) (fs.DirEntry, error) {
|
||||
if st, err := d.c.fs[fsI].Stat("."); err != 0 {
|
||||
if st, err := d.c.fs[fsI].Stat("."); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return &dirInfo{name, st}, nil
|
||||
@@ -246,43 +246,43 @@ func (d *openRootDir) ReadDir(count int) ([]fs.DirEntry, error) {
|
||||
}
|
||||
|
||||
// Lstat implements FS.Lstat
|
||||
func (c *CompositeFS) Lstat(path string) (platform.Stat_t, syscall.Errno) {
|
||||
func (c *CompositeFS) Lstat(path string) (platform.Stat_t, error) {
|
||||
matchIndex, relativePath := c.chooseFS(path)
|
||||
return c.fs[matchIndex].Lstat(relativePath)
|
||||
}
|
||||
|
||||
// Stat implements FS.Stat
|
||||
func (c *CompositeFS) Stat(path string) (platform.Stat_t, syscall.Errno) {
|
||||
func (c *CompositeFS) Stat(path string) (platform.Stat_t, error) {
|
||||
matchIndex, relativePath := c.chooseFS(path)
|
||||
return c.fs[matchIndex].Stat(relativePath)
|
||||
}
|
||||
|
||||
// Mkdir implements FS.Mkdir
|
||||
func (c *CompositeFS) Mkdir(path string, perm fs.FileMode) syscall.Errno {
|
||||
func (c *CompositeFS) Mkdir(path string, perm fs.FileMode) error {
|
||||
matchIndex, relativePath := c.chooseFS(path)
|
||||
return c.fs[matchIndex].Mkdir(relativePath, perm)
|
||||
}
|
||||
|
||||
// Chmod implements FS.Chmod
|
||||
func (c *CompositeFS) Chmod(path string, perm fs.FileMode) syscall.Errno {
|
||||
func (c *CompositeFS) Chmod(path string, perm fs.FileMode) error {
|
||||
matchIndex, relativePath := c.chooseFS(path)
|
||||
return c.fs[matchIndex].Chmod(relativePath, perm)
|
||||
}
|
||||
|
||||
// Chown implements FS.Chown
|
||||
func (c *CompositeFS) Chown(path string, uid, gid int) syscall.Errno {
|
||||
func (c *CompositeFS) Chown(path string, uid, gid int) error {
|
||||
matchIndex, relativePath := c.chooseFS(path)
|
||||
return c.fs[matchIndex].Chown(relativePath, uid, gid)
|
||||
}
|
||||
|
||||
// Lchown implements FS.Lchown
|
||||
func (c *CompositeFS) Lchown(path string, uid, gid int) syscall.Errno {
|
||||
func (c *CompositeFS) Lchown(path string, uid, gid int) error {
|
||||
matchIndex, relativePath := c.chooseFS(path)
|
||||
return c.fs[matchIndex].Lchown(relativePath, uid, gid)
|
||||
}
|
||||
|
||||
// Rename implements FS.Rename
|
||||
func (c *CompositeFS) Rename(from, to string) syscall.Errno {
|
||||
func (c *CompositeFS) Rename(from, to string) error {
|
||||
fromFS, fromPath := c.chooseFS(from)
|
||||
toFS, toPath := c.chooseFS(to)
|
||||
if fromFS != toFS {
|
||||
@@ -292,13 +292,13 @@ func (c *CompositeFS) Rename(from, to string) syscall.Errno {
|
||||
}
|
||||
|
||||
// Readlink implements FS.Readlink
|
||||
func (c *CompositeFS) Readlink(path string) (string, syscall.Errno) {
|
||||
func (c *CompositeFS) Readlink(path string) (string, error) {
|
||||
matchIndex, relativePath := c.chooseFS(path)
|
||||
return c.fs[matchIndex].Readlink(relativePath)
|
||||
}
|
||||
|
||||
// Link implements FS.Link.
|
||||
func (c *CompositeFS) Link(oldName, newName string) syscall.Errno {
|
||||
func (c *CompositeFS) Link(oldName, newName string) error {
|
||||
fromFS, oldNamePath := c.chooseFS(oldName)
|
||||
toFS, newNamePath := c.chooseFS(newName)
|
||||
if fromFS != toFS {
|
||||
@@ -308,13 +308,13 @@ func (c *CompositeFS) Link(oldName, newName string) syscall.Errno {
|
||||
}
|
||||
|
||||
// Utimens implements FS.Utimens
|
||||
func (c *CompositeFS) Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) syscall.Errno {
|
||||
func (c *CompositeFS) Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) error {
|
||||
matchIndex, relativePath := c.chooseFS(path)
|
||||
return c.fs[matchIndex].Utimens(relativePath, times, symlinkFollow)
|
||||
}
|
||||
|
||||
// Symlink implements FS.Symlink
|
||||
func (c *CompositeFS) Symlink(oldName, link string) (err syscall.Errno) {
|
||||
func (c *CompositeFS) Symlink(oldName, link string) (err error) {
|
||||
fromFS, oldNamePath := c.chooseFS(oldName)
|
||||
toFS, linkPath := c.chooseFS(link)
|
||||
if fromFS != toFS {
|
||||
@@ -324,19 +324,19 @@ func (c *CompositeFS) Symlink(oldName, link string) (err syscall.Errno) {
|
||||
}
|
||||
|
||||
// Truncate implements FS.Truncate
|
||||
func (c *CompositeFS) Truncate(path string, size int64) syscall.Errno {
|
||||
func (c *CompositeFS) Truncate(path string, size int64) error {
|
||||
matchIndex, relativePath := c.chooseFS(path)
|
||||
return c.fs[matchIndex].Truncate(relativePath, size)
|
||||
}
|
||||
|
||||
// Rmdir implements FS.Rmdir
|
||||
func (c *CompositeFS) Rmdir(path string) syscall.Errno {
|
||||
func (c *CompositeFS) Rmdir(path string) error {
|
||||
matchIndex, relativePath := c.chooseFS(path)
|
||||
return c.fs[matchIndex].Rmdir(relativePath)
|
||||
}
|
||||
|
||||
// Unlink implements FS.Unlink
|
||||
func (c *CompositeFS) Unlink(path string) syscall.Errno {
|
||||
func (c *CompositeFS) Unlink(path string) error {
|
||||
matchIndex, relativePath := c.chooseFS(path)
|
||||
return c.fs[matchIndex].Unlink(relativePath)
|
||||
}
|
||||
@@ -479,10 +479,10 @@ loop:
|
||||
type fakeRootFS struct{ UnimplementedFS }
|
||||
|
||||
// OpenFile implements FS.OpenFile
|
||||
func (*fakeRootFS) OpenFile(path string, flag int, perm fs.FileMode) (fs.File, syscall.Errno) {
|
||||
func (*fakeRootFS) OpenFile(path string, flag int, perm fs.FileMode) (fs.File, error) {
|
||||
switch path {
|
||||
case ".", "/", "":
|
||||
return fakeRootDir{}, 0
|
||||
return fakeRootDir{}, nil
|
||||
}
|
||||
return nil, syscall.ENOENT
|
||||
}
|
||||
|
||||
@@ -48,14 +48,13 @@ func TestNewRootFS(t *testing.T) {
|
||||
require.Equal(t, "[.:/tmp]", rootFS.String())
|
||||
|
||||
// Guest can look up /tmp
|
||||
f, errno := rootFS.OpenFile("/tmp", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
f, err := rootFS.OpenFile("/tmp", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.Close())
|
||||
|
||||
// Guest can look up / and see "/tmp" in it
|
||||
f, errno = rootFS.OpenFile("/", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
|
||||
f, err = rootFS.OpenFile("/", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
dirents, err := f.(fs.ReadDirFile).ReadDir(-1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(dirents))
|
||||
@@ -96,10 +95,9 @@ func TestNewRootFS(t *testing.T) {
|
||||
require.NotEqual(t, testFS2, rootFS)
|
||||
|
||||
t.Run("last wins", func(t *testing.T) {
|
||||
f, errno := rootFS.OpenFile("/tmp/a", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
f, err := rootFS.OpenFile("/tmp/a", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
b, err := io.ReadAll(f)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []byte{2}, b)
|
||||
@@ -107,8 +105,8 @@ func TestNewRootFS(t *testing.T) {
|
||||
|
||||
// This test is covered by fstest.TestFS, but doing again here
|
||||
t.Run("root includes prefix mount", func(t *testing.T) {
|
||||
f, errno := rootFS.OpenFile(".", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
f, err := rootFS.OpenFile(".", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
require.Equal(t, []string{"a", "tmp"}, readDirNames(t, f))
|
||||
@@ -117,8 +115,8 @@ func TestNewRootFS(t *testing.T) {
|
||||
}
|
||||
|
||||
func readDirNames(t *testing.T, f fs.File) []string {
|
||||
names, errno := platform.Readdirnames(f, -1)
|
||||
require.Zero(t, errno)
|
||||
names, err := platform.Readdirnames(f, -1)
|
||||
require.NoError(t, err)
|
||||
sort.Strings(names)
|
||||
return names
|
||||
}
|
||||
@@ -281,8 +279,8 @@ func TestRootFS_examples(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, p := range tc.expected {
|
||||
f, errno := root.OpenFile(p, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno, p)
|
||||
f, err := root.OpenFile(p, os.O_RDONLY, 0)
|
||||
require.NoError(t, err, p)
|
||||
require.NoError(t, f.Close(), p)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,20 +19,7 @@ import (
|
||||
// Implementations should embed UnimplementedFS for forward compatability. Any
|
||||
// unsupported method or parameter should return syscall.ENOSYS.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// All methods that can return an error return a syscall.Errno, which is zero
|
||||
// on success.
|
||||
//
|
||||
// Restricting to syscall.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.
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// A writable filesystem abstraction is not yet implemented as of Go 1.20. See
|
||||
// https://github.com/golang/go/issues/45757
|
||||
// See https://github.com/golang/go/issues/45757
|
||||
type FS interface {
|
||||
// String should return a human-readable format of the filesystem
|
||||
//
|
||||
@@ -44,8 +31,7 @@ type FS interface {
|
||||
String() string
|
||||
|
||||
// OpenFile is similar to os.OpenFile, except the path is relative to this
|
||||
// file system, and syscall.Errno are returned instead of an os.PathError.
|
||||
// A zero syscall.Errno is success.
|
||||
// file system, and syscall.Errno are returned instead of a os.PathError.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
@@ -71,7 +57,7 @@ type FS interface {
|
||||
// - flag are the same as OpenFile, for example, os.O_CREATE.
|
||||
// - Implications of permissions when os.O_CREATE are described in Chmod
|
||||
// notes.
|
||||
OpenFile(path string, flag int, perm fs.FileMode) (fs.File, syscall.Errno)
|
||||
OpenFile(path string, flag int, perm fs.FileMode) (fs.File, error)
|
||||
// ^^ TODO: Consider syscall.Open, though this implies defining and
|
||||
// coercing flags and perms similar to what is done in os.OpenFile.
|
||||
|
||||
@@ -89,7 +75,7 @@ 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) (platform.Stat_t, syscall.Errno)
|
||||
Lstat(path string) (platform.Stat_t, error)
|
||||
|
||||
// Stat is similar to syscall.Stat, except the path is relative to this
|
||||
// file system.
|
||||
@@ -105,11 +91,10 @@ 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) (platform.Stat_t, syscall.Errno)
|
||||
Stat(path string) (platform.Stat_t, error)
|
||||
|
||||
// Mkdir is similar to os.Mkdir, except the path is relative to this file
|
||||
// system, and syscall.Errno are returned instead of a os.PathError. A zero
|
||||
// syscall.Errno is success.
|
||||
// system, and syscall.Errno are returned instead of a os.PathError.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
@@ -121,13 +106,12 @@ type FS interface {
|
||||
// # Notes
|
||||
//
|
||||
// - Implications of permissions are described in Chmod notes.
|
||||
Mkdir(path string, perm fs.FileMode) syscall.Errno
|
||||
Mkdir(path string, perm fs.FileMode) error
|
||||
// ^^ TODO: Consider syscall.Mkdir, though this implies defining and
|
||||
// coercing flags and perms similar to what is done in os.Mkdir.
|
||||
|
||||
// Chmod is similar to os.Chmod, except the path is relative to this file
|
||||
// system, and syscall.Errno are returned instead of a os.PathError. A zero
|
||||
// syscall.Errno is success.
|
||||
// system, and syscall.Errno are returned instead of a os.PathError.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
@@ -140,13 +124,12 @@ 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) error
|
||||
// ^^ TODO: Consider syscall.Chmod, though this implies defining and
|
||||
// coercing flags and perms similar to what is done in os.Chmod.
|
||||
|
||||
// Chown is like os.Chown except the path is relative to this file
|
||||
// system, and syscall.Errno are returned instead of an os.PathError.
|
||||
// A zero syscall.Errno is success.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
@@ -158,11 +141,11 @@ type FS interface {
|
||||
//
|
||||
// - Windows will always return syscall.ENOSYS
|
||||
// - This is similar to https://linux.die.net/man/3/chown
|
||||
Chown(path string, uid, gid int) syscall.Errno
|
||||
Chown(path string, uid, gid int) error
|
||||
|
||||
// Lchown is like os.Lchown except the path is relative to this file
|
||||
// system, and syscall.Errno are returned instead of an os.PathError. A
|
||||
// zero syscall.Errno is success.
|
||||
// system, and syscall.Errno are returned instead of a os.PathError.
|
||||
// See https://linux.die.net/man/3/lchown
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
@@ -174,7 +157,7 @@ type FS interface {
|
||||
//
|
||||
// - Windows will always return syscall.ENOSYS
|
||||
// - This is similar to https://linux.die.net/man/3/lchown
|
||||
Lchown(path string, uid, gid int) syscall.Errno
|
||||
Lchown(path string, uid, gid int) error
|
||||
|
||||
// Rename is similar to syscall.Rename, except the path is relative to this
|
||||
// file system.
|
||||
@@ -192,7 +175,7 @@ type FS interface {
|
||||
// # Notes
|
||||
//
|
||||
// - Windows doesn't let you overwrite an existing directory.
|
||||
Rename(from, to string) syscall.Errno
|
||||
Rename(from, to string) error
|
||||
|
||||
// Rmdir is similar to syscall.Rmdir, except the path is relative to this
|
||||
// file system.
|
||||
@@ -208,7 +191,7 @@ type FS interface {
|
||||
// # Notes
|
||||
//
|
||||
// - As of Go 1.19, Windows maps syscall.ENOTDIR to syscall.ENOENT.
|
||||
Rmdir(path string) syscall.Errno
|
||||
Rmdir(path string) error
|
||||
|
||||
// Unlink is similar to syscall.Unlink, except the path is relative to this
|
||||
// file system.
|
||||
@@ -225,7 +208,7 @@ 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) error
|
||||
|
||||
// Link is similar to syscall.Link, except the path is relative to this
|
||||
// file system. This creates "hard" link from oldPath to newPath, in
|
||||
@@ -237,7 +220,7 @@ type FS interface {
|
||||
// - syscall.EPERM: `oldPath` is invalid.
|
||||
// - syscall.ENOENT: `oldPath` doesn't exist.
|
||||
// - syscall.EISDIR: `newPath` exists, but is a directory.
|
||||
Link(oldPath, newPath string) syscall.Errno
|
||||
Link(oldPath, newPath string) error
|
||||
|
||||
// Symlink is similar to syscall.Symlink, except the `oldPath` is relative
|
||||
// to this file system. This creates "soft" link from oldPath to newPath,
|
||||
@@ -259,7 +242,7 @@ type FS interface {
|
||||
// - Symlinks in Windows requires `SeCreateSymbolicLinkPrivilege`.
|
||||
// Otherwise, syscall.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) error
|
||||
|
||||
// Readlink is similar to syscall.Readlink, except the path is relative to
|
||||
// this file system.
|
||||
@@ -273,7 +256,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, error)
|
||||
|
||||
// Truncate is similar to syscall.Truncate, except the path is relative to
|
||||
// this file system.
|
||||
@@ -284,7 +267,7 @@ type FS interface {
|
||||
// - syscall.EINVAL: `path` is invalid or size is negative.
|
||||
// - syscall.ENOENT: `path` doesn't exist
|
||||
// - syscall.EACCES: `path` doesn't have write access.
|
||||
Truncate(path string, size int64) syscall.Errno
|
||||
Truncate(path string, size int64) error
|
||||
|
||||
// Utimens set file access and modification times on a path relative to
|
||||
// this file system, at nanosecond precision.
|
||||
@@ -313,7 +296,7 @@ type FS interface {
|
||||
// values UTIME_NOW or UTIME_NOW.
|
||||
// - This is like `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) error
|
||||
}
|
||||
|
||||
// ReaderAtOffset gets an io.Reader from a fs.File that reads from an offset,
|
||||
@@ -334,7 +317,7 @@ func ReaderAtOffset(f fs.File, offset int64) io.Reader {
|
||||
}
|
||||
|
||||
// FileDatasync is like syscall.Fdatasync except that's only defined in linux.
|
||||
func FileDatasync(f fs.File) (err syscall.Errno) {
|
||||
func FileDatasync(f fs.File) (err error) {
|
||||
return platform.Fdatasync(f)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ func testOpen_O_RDWR(t *testing.T, tmpDir string, testFS FS) {
|
||||
err := os.WriteFile(realPath, []byte{}, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
f, errno := testFS.OpenFile(file, os.O_RDWR, 0)
|
||||
require.Zero(t, errno)
|
||||
f, err := testFS.OpenFile(file, os.O_RDWR, 0)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
w, ok := f.(io.Writer)
|
||||
@@ -46,8 +46,8 @@ func testOpen_O_RDWR(t *testing.T, tmpDir string, testFS FS) {
|
||||
|
||||
// re-create as read-only, using 0444 to allow read-back on windows.
|
||||
require.NoError(t, os.Remove(realPath))
|
||||
f, errno = testFS.OpenFile(file, os.O_RDONLY|os.O_CREATE, 0o444)
|
||||
require.Zero(t, errno)
|
||||
f, err = testFS.OpenFile(file, os.O_RDONLY|os.O_CREATE, 0o444)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
w, ok = f.(io.Writer)
|
||||
@@ -67,27 +67,27 @@ func testOpen_O_RDWR(t *testing.T, tmpDir string, testFS FS) {
|
||||
// from os.TestDirFSPathsValid
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Run("strange name", func(t *testing.T) {
|
||||
f, errno = testFS.OpenFile(`e:xperi\ment.txt`, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
|
||||
require.Zero(t, errno)
|
||||
f, err := testFS.OpenFile(`e:xperi\ment.txt`, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
_, errno = platform.StatFile(f)
|
||||
require.Zero(t, errno)
|
||||
_, err = platform.StatFile(f)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testOpen_Read(t *testing.T, testFS FS, expectIno bool) {
|
||||
t.Run("doesn't exist", func(t *testing.T) {
|
||||
_, errno := testFS.OpenFile("nope", os.O_RDONLY, 0)
|
||||
_, err := 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, syscall.ENOENT, err)
|
||||
})
|
||||
|
||||
t.Run("readdir . opens root", func(t *testing.T) {
|
||||
f, errno := testFS.OpenFile(".", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
f, err := testFS.OpenFile(".", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
dirents := requireReaddir(t, f, -1, expectIno)
|
||||
@@ -102,8 +102,8 @@ func testOpen_Read(t *testing.T, testFS FS, expectIno bool) {
|
||||
})
|
||||
|
||||
t.Run("readdirnames . opens root", func(t *testing.T) {
|
||||
f, errno := testFS.OpenFile(".", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
f, err := testFS.OpenFile(".", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
names := requireReaddirnames(t, f, -1)
|
||||
@@ -111,8 +111,8 @@ func testOpen_Read(t *testing.T, testFS FS, expectIno bool) {
|
||||
})
|
||||
|
||||
t.Run("readdir empty", func(t *testing.T) {
|
||||
f, errno := testFS.OpenFile("emptydir", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
f, err := testFS.OpenFile("emptydir", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
entries := requireReaddir(t, f, -1, expectIno)
|
||||
@@ -120,8 +120,8 @@ func testOpen_Read(t *testing.T, testFS FS, expectIno bool) {
|
||||
})
|
||||
|
||||
t.Run("readdirnames empty", func(t *testing.T) {
|
||||
f, errno := testFS.OpenFile("emptydir", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
f, err := testFS.OpenFile("emptydir", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
names := requireReaddirnames(t, f, -1)
|
||||
@@ -129,21 +129,21 @@ func testOpen_Read(t *testing.T, testFS FS, expectIno bool) {
|
||||
})
|
||||
|
||||
t.Run("readdir partial", func(t *testing.T) {
|
||||
dirF, errno := testFS.OpenFile("dir", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
dirF, err := testFS.OpenFile("dir", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer dirF.Close()
|
||||
|
||||
dirents1, errno := platform.Readdir(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
dirents1, err := platform.Readdir(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(dirents1))
|
||||
|
||||
dirents2, errno := platform.Readdir(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
dirents2, err := platform.Readdir(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(dirents2))
|
||||
|
||||
// read exactly the last entry
|
||||
dirents3, errno := platform.Readdir(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
dirents3, err := platform.Readdir(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(dirents3))
|
||||
|
||||
dirents := []*platform.Dirent{dirents1[0], dirents2[0], dirents3[0]}
|
||||
@@ -158,28 +158,28 @@ func testOpen_Read(t *testing.T, testFS FS, expectIno bool) {
|
||||
}, dirents)
|
||||
|
||||
// no error reading an exhausted directory
|
||||
_, errno = platform.Readdir(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
_, err = platform.Readdir(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
// TODO: consolidate duplicated tests from platform once we have our own
|
||||
// file type
|
||||
t.Run("readdirnames partial", func(t *testing.T) {
|
||||
dirF, errno := testFS.OpenFile("dir", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
dirF, err := testFS.OpenFile("dir", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer dirF.Close()
|
||||
|
||||
names1, errno := platform.Readdirnames(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
names1, err := platform.Readdirnames(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(names1))
|
||||
|
||||
names2, errno := platform.Readdirnames(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
names2, err := platform.Readdirnames(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(names2))
|
||||
|
||||
// read exactly the last entry
|
||||
names3, errno := platform.Readdirnames(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
names3, err := platform.Readdirnames(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(names3))
|
||||
|
||||
names := []string{names1[0], names2[0], names3[0]}
|
||||
@@ -188,13 +188,13 @@ func testOpen_Read(t *testing.T, testFS FS, expectIno bool) {
|
||||
require.Equal(t, []string{"-", "a-", "ab-"}, names)
|
||||
|
||||
// no error reading an exhausted directory
|
||||
_, errno = platform.Readdirnames(dirF, 1)
|
||||
require.Zero(t, errno)
|
||||
_, err = platform.Readdirnames(dirF, 1)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("file exists", func(t *testing.T) {
|
||||
f, errno := testFS.OpenFile("animals.txt", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
f, err := testFS.OpenFile("animals.txt", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
fileContents := []byte(`bear
|
||||
@@ -230,18 +230,18 @@ human
|
||||
// currently supported in WASI or GOOS=js
|
||||
const O_NOATIME = 0x40000
|
||||
|
||||
f, errno := testFS.OpenFile("animals.txt", os.O_RDONLY|O_NOATIME, 0)
|
||||
require.Zero(t, errno)
|
||||
f, err := testFS.OpenFile("animals.txt", os.O_RDONLY|O_NOATIME, 0)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
})
|
||||
|
||||
t.Run("writing to a read-only file is EBADF", func(t *testing.T) {
|
||||
f, errno := testFS.OpenFile("animals.txt", os.O_RDONLY, 0)
|
||||
f, err := testFS.OpenFile("animals.txt", os.O_RDONLY, 0)
|
||||
defer require.NoError(t, f.Close())
|
||||
require.Zero(t, errno)
|
||||
require.NoError(t, err)
|
||||
|
||||
if w, ok := f.(io.Writer); ok {
|
||||
_, err := w.Write([]byte{1, 2, 3, 4})
|
||||
_, err = w.Write([]byte{1, 2, 3, 4})
|
||||
require.EqualErrno(t, syscall.EBADF, platform.UnwrapOSError(err))
|
||||
} else {
|
||||
t.Skip("not an io.Writer")
|
||||
@@ -249,12 +249,12 @@ human
|
||||
})
|
||||
|
||||
t.Run("writing to a directory is EBADF", func(t *testing.T) {
|
||||
f, errno := testFS.OpenFile("sub", os.O_RDONLY, 0)
|
||||
f, err := testFS.OpenFile("sub", os.O_RDONLY, 0)
|
||||
defer require.NoError(t, f.Close())
|
||||
require.Zero(t, errno)
|
||||
require.NoError(t, err)
|
||||
|
||||
if w, ok := f.(io.Writer); ok {
|
||||
_, err := w.Write([]byte{1, 2, 3, 4})
|
||||
_, err = w.Write([]byte{1, 2, 3, 4})
|
||||
require.EqualErrno(t, syscall.EBADF, platform.UnwrapOSError(err))
|
||||
} else {
|
||||
t.Skip("not an io.Writer")
|
||||
@@ -263,16 +263,16 @@ human
|
||||
}
|
||||
|
||||
func testLstat(t *testing.T, testFS FS) {
|
||||
_, errno := testFS.Lstat("cat")
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
_, errno = testFS.Lstat("sub/cat")
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
_, err := testFS.Lstat("cat")
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
_, err = testFS.Lstat("sub/cat")
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
|
||||
var st platform.Stat_t
|
||||
|
||||
t.Run("dir", func(t *testing.T) {
|
||||
st, errno = testFS.Lstat(".")
|
||||
require.Zero(t, errno)
|
||||
st, err = testFS.Lstat(".")
|
||||
require.NoError(t, err)
|
||||
require.True(t, st.Mode.IsDir())
|
||||
require.NotEqual(t, uint64(0), st.Ino)
|
||||
})
|
||||
@@ -280,9 +280,8 @@ func testLstat(t *testing.T, testFS FS) {
|
||||
var stFile platform.Stat_t
|
||||
|
||||
t.Run("file", func(t *testing.T) {
|
||||
stFile, errno = testFS.Lstat("animals.txt")
|
||||
require.Zero(t, errno)
|
||||
|
||||
stFile, err = testFS.Lstat("animals.txt")
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, stFile.Mode.Type())
|
||||
require.Equal(t, int64(30), stFile.Size)
|
||||
require.NotEqual(t, uint64(0), st.Ino)
|
||||
@@ -294,9 +293,8 @@ func testLstat(t *testing.T, testFS FS) {
|
||||
|
||||
var stSubdir platform.Stat_t
|
||||
t.Run("subdir", func(t *testing.T) {
|
||||
stSubdir, errno = testFS.Lstat("sub")
|
||||
require.Zero(t, errno)
|
||||
|
||||
stSubdir, err = testFS.Lstat("sub")
|
||||
require.NoError(t, err)
|
||||
require.True(t, stSubdir.Mode.IsDir())
|
||||
require.NotEqual(t, uint64(0), st.Ino)
|
||||
})
|
||||
@@ -307,8 +305,8 @@ func testLstat(t *testing.T, testFS FS) {
|
||||
|
||||
t.Run("link to dir link", func(t *testing.T) {
|
||||
pathLink := "sub-link"
|
||||
stLink, errno := testFS.Lstat(pathLink)
|
||||
require.Zero(t, errno)
|
||||
stLink, err := testFS.Lstat(pathLink)
|
||||
require.NoError(t, err)
|
||||
|
||||
requireLinkStat(t, testFS, pathLink, stLink)
|
||||
})
|
||||
@@ -316,9 +314,8 @@ func testLstat(t *testing.T, testFS FS) {
|
||||
|
||||
func requireLinkStat(t *testing.T, testFS FS, path string, stat platform.Stat_t) {
|
||||
link := path + "-link"
|
||||
stLink, errno := testFS.Lstat(link)
|
||||
require.Zero(t, errno)
|
||||
|
||||
stLink, err := testFS.Lstat(link)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, stat.Ino, stLink.Ino) // inodes are not equal
|
||||
require.Equal(t, fs.ModeSymlink, stLink.Mode.Type())
|
||||
// From https://linux.die.net/man/2/lstat:
|
||||
@@ -332,21 +329,19 @@ func requireLinkStat(t *testing.T, testFS FS, path string, stat platform.Stat_t)
|
||||
}
|
||||
|
||||
func testStat(t *testing.T, testFS FS) {
|
||||
_, errno := testFS.Stat("cat")
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
_, errno = testFS.Stat("sub/cat")
|
||||
require.EqualErrno(t, syscall.ENOENT, errno)
|
||||
|
||||
st, errno := testFS.Stat("sub/test.txt")
|
||||
require.Zero(t, errno)
|
||||
_, err := testFS.Stat("cat")
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
_, err = testFS.Stat("sub/cat")
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
|
||||
st, err := testFS.Stat("sub/test.txt")
|
||||
require.NoError(t, err)
|
||||
require.False(t, st.Mode.IsDir())
|
||||
require.NotEqual(t, uint64(0), st.Dev)
|
||||
require.NotEqual(t, uint64(0), st.Ino)
|
||||
|
||||
st, errno = testFS.Stat("sub")
|
||||
require.Zero(t, errno)
|
||||
|
||||
st, err = testFS.Stat("sub")
|
||||
require.NoError(t, err)
|
||||
require.True(t, st.Mode.IsDir())
|
||||
// windows before go 1.20 has trouble reading the inode information on directories.
|
||||
if runtime.GOOS != "windows" || platform.IsGo120 {
|
||||
@@ -358,9 +353,8 @@ func testStat(t *testing.T, testFS FS) {
|
||||
// requireReaddir ensures the input file is a directory, and returns its
|
||||
// entries.
|
||||
func requireReaddir(t *testing.T, f fs.File, n int, expectIno bool) []*platform.Dirent {
|
||||
entries, errno := platform.Readdir(f, n)
|
||||
require.Zero(t, errno)
|
||||
|
||||
entries, err := platform.Readdir(f, n)
|
||||
require.NoError(t, err)
|
||||
sort.Slice(entries, func(i, j int) bool { return entries[i].Name < entries[j].Name })
|
||||
if _, ok := f.(*openRootDir); ok {
|
||||
// TODO: get inodes to work on the root directory of a composite FS
|
||||
@@ -374,8 +368,8 @@ func requireReaddir(t *testing.T, f fs.File, n int, expectIno bool) []*platform.
|
||||
// requireReaddirnames ensures the input file is a directory, and returns its
|
||||
// entries.
|
||||
func requireReaddirnames(t *testing.T, f fs.File, n int) []string {
|
||||
names, errno := platform.Readdirnames(f, n)
|
||||
require.Zero(t, errno)
|
||||
names, err := platform.Readdirnames(f, n)
|
||||
require.NoError(t, err)
|
||||
sort.Strings(names)
|
||||
return names
|
||||
}
|
||||
@@ -394,11 +388,11 @@ func testReadlink(t *testing.T, readFS, writeFS FS) {
|
||||
}
|
||||
|
||||
for _, tl := range testLinks {
|
||||
errno := writeFS.Symlink(tl.old, tl.dst) // not os.Symlink for windows compat
|
||||
require.Zero(t, errno, "%v", tl)
|
||||
err := writeFS.Symlink(tl.old, tl.dst) // not os.Symlink for windows compat
|
||||
require.NoError(t, err, "%v", tl)
|
||||
|
||||
dst, errno := readFS.Readlink(tl.dst)
|
||||
require.Zero(t, errno)
|
||||
dst, err := readFS.Readlink(tl.dst)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tl.old, dst)
|
||||
}
|
||||
|
||||
@@ -580,8 +574,8 @@ func TestWriterAtOffset(t *testing.T) {
|
||||
tc := tc
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
f, errno := tc.fs.OpenFile(readerAtFile, os.O_RDWR|os.O_CREATE, 0o600)
|
||||
require.Zero(t, errno)
|
||||
f, err := tc.fs.OpenFile(readerAtFile, os.O_RDWR|os.O_CREATE, 0o600)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
w := f.(io.Writer)
|
||||
@@ -646,8 +640,8 @@ func TestWriterAtOffset_empty(t *testing.T) {
|
||||
tc := tc
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
f, errno := tc.fs.OpenFile(emptyFile, os.O_RDWR|os.O_CREATE, 0o600)
|
||||
require.Zero(t, errno)
|
||||
f, err := tc.fs.OpenFile(emptyFile, os.O_RDWR|os.O_CREATE, 0o600)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
r := f.(io.Writer)
|
||||
@@ -674,15 +668,15 @@ func TestWriterAtOffset_Unsupported(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
dirFS := NewDirFS(tmpDir)
|
||||
|
||||
f, errno := dirFS.OpenFile(readerAtFile, os.O_RDWR|os.O_CREATE, 0o600)
|
||||
require.Zero(t, errno)
|
||||
f, err := dirFS.OpenFile(readerAtFile, os.O_RDWR|os.O_CREATE, 0o600)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
// mask both io.WriterAt and io.Seeker
|
||||
ra := WriterAtOffset(struct{ fs.File }{f}, 0)
|
||||
|
||||
buf := make([]byte, 3)
|
||||
_, err := ra.Write(buf)
|
||||
_, err = ra.Write(buf)
|
||||
require.Equal(t, syscall.ENOSYS, err)
|
||||
}
|
||||
|
||||
@@ -690,8 +684,8 @@ func TestWriterAtOffset_Unsupported(t *testing.T) {
|
||||
// sync anyway. There is no test in Go for os.File Sync, but closest is similar
|
||||
// to below. Effectively, this only tests that things don't error.
|
||||
func Test_FileSync(t *testing.T) {
|
||||
testSync(t, func(f fs.File) syscall.Errno {
|
||||
return platform.UnwrapOSError(f.(interface{ Sync() error }).Sync())
|
||||
testSync(t, func(f fs.File) error {
|
||||
return f.(interface{ Sync() error }).Sync()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -700,7 +694,7 @@ func Test_FileDatasync(t *testing.T) {
|
||||
testSync(t, FileDatasync)
|
||||
}
|
||||
|
||||
func testSync(t *testing.T, sync func(fs.File) syscall.Errno) {
|
||||
func testSync(t *testing.T, sync func(fs.File) error) {
|
||||
f, err := os.CreateTemp("", t.Name())
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
@@ -712,7 +706,7 @@ func testSync(t *testing.T, sync func(fs.File) syscall.Errno) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Sync the data.
|
||||
require.Zero(t, sync(f))
|
||||
require.NoError(t, sync(f))
|
||||
|
||||
// Rewind while the file is still open.
|
||||
_, err = f.Seek(0, io.SeekStart)
|
||||
|
||||
@@ -22,76 +22,76 @@ func (UnimplementedFS) Open(name string) (fs.File, error) {
|
||||
}
|
||||
|
||||
// OpenFile implements FS.OpenFile
|
||||
func (UnimplementedFS) OpenFile(path string, flag int, perm fs.FileMode) (fs.File, syscall.Errno) {
|
||||
func (UnimplementedFS) OpenFile(path string, flag int, perm fs.FileMode) (fs.File, error) {
|
||||
return nil, syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Lstat implements FS.Lstat
|
||||
func (UnimplementedFS) Lstat(path string) (platform.Stat_t, syscall.Errno) {
|
||||
func (UnimplementedFS) Lstat(path string) (platform.Stat_t, error) {
|
||||
return platform.Stat_t{}, syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Stat implements FS.Stat
|
||||
func (UnimplementedFS) Stat(path string) (platform.Stat_t, syscall.Errno) {
|
||||
func (UnimplementedFS) Stat(path string) (platform.Stat_t, error) {
|
||||
return platform.Stat_t{}, syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Readlink implements FS.Readlink
|
||||
func (UnimplementedFS) Readlink(path string) (string, syscall.Errno) {
|
||||
func (UnimplementedFS) Readlink(path string) (string, error) {
|
||||
return "", syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Mkdir implements FS.Mkdir
|
||||
func (UnimplementedFS) Mkdir(path string, perm fs.FileMode) syscall.Errno {
|
||||
func (UnimplementedFS) Mkdir(path string, perm fs.FileMode) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Chmod implements FS.Chmod
|
||||
func (UnimplementedFS) Chmod(path string, perm fs.FileMode) syscall.Errno {
|
||||
func (UnimplementedFS) Chmod(path string, perm fs.FileMode) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Chown implements FS.Chown
|
||||
func (UnimplementedFS) Chown(path string, uid, gid int) syscall.Errno {
|
||||
func (UnimplementedFS) Chown(path string, uid, gid int) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Lchown implements FS.Lchown
|
||||
func (UnimplementedFS) Lchown(path string, uid, gid int) syscall.Errno {
|
||||
func (UnimplementedFS) Lchown(path string, uid, gid int) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Rename implements FS.Rename
|
||||
func (UnimplementedFS) Rename(from, to string) syscall.Errno {
|
||||
func (UnimplementedFS) Rename(from, to string) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Rmdir implements FS.Rmdir
|
||||
func (UnimplementedFS) Rmdir(path string) syscall.Errno {
|
||||
func (UnimplementedFS) Rmdir(path string) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Link implements FS.Link
|
||||
func (UnimplementedFS) Link(_, _ string) syscall.Errno {
|
||||
func (UnimplementedFS) Link(_, _ string) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Symlink implements FS.Symlink
|
||||
func (UnimplementedFS) Symlink(_, _ string) syscall.Errno {
|
||||
func (UnimplementedFS) Symlink(_, _ string) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Unlink implements FS.Unlink
|
||||
func (UnimplementedFS) Unlink(path string) syscall.Errno {
|
||||
func (UnimplementedFS) Unlink(path string) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Utimens implements FS.Utimens
|
||||
func (UnimplementedFS) Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) syscall.Errno {
|
||||
func (UnimplementedFS) Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
// Truncate implements FS.Truncate
|
||||
func (UnimplementedFS) Truncate(string, int64) syscall.Errno {
|
||||
func (UnimplementedFS) Truncate(string, int64) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
)
|
||||
|
||||
// Errno is neither uint16 nor an alias for parity with wasm.ValueType.
|
||||
@@ -263,10 +266,13 @@ 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(err error) Errno {
|
||||
if err == nil || err == io.EOF {
|
||||
return ErrnoSuccess // io.EOF has no value in WASI, and isn't an error.
|
||||
}
|
||||
errno := platform.UnwrapOSError(err)
|
||||
|
||||
switch errno {
|
||||
case 0:
|
||||
return ErrnoSuccess
|
||||
case syscall.EACCES:
|
||||
return ErrnoAcces
|
||||
case syscall.EAGAIN:
|
||||
@@ -275,8 +281,6 @@ func ToErrno(errno syscall.Errno) Errno {
|
||||
return ErrnoBadf
|
||||
case syscall.EEXIST:
|
||||
return ErrnoExist
|
||||
case syscall.EFAULT:
|
||||
return ErrnoFault
|
||||
case syscall.EINTR:
|
||||
return ErrnoIntr
|
||||
case syscall.EINVAL:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
@@ -8,11 +9,16 @@ import (
|
||||
func TestToErrno(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input syscall.Errno
|
||||
input error
|
||||
expected Errno
|
||||
}{
|
||||
{
|
||||
name: "zero is not an error",
|
||||
name: "nil is not an error",
|
||||
expected: ErrnoSuccess,
|
||||
},
|
||||
{
|
||||
name: "io.EOF is not an error",
|
||||
input: io.EOF,
|
||||
expected: ErrnoSuccess,
|
||||
},
|
||||
{
|
||||
@@ -35,11 +41,6 @@ func TestToErrno(t *testing.T) {
|
||||
input: syscall.EEXIST,
|
||||
expected: ErrnoExist,
|
||||
},
|
||||
{
|
||||
name: "syscall.EFAULT",
|
||||
input: syscall.EFAULT,
|
||||
expected: ErrnoFault,
|
||||
},
|
||||
{
|
||||
name: "syscall.EINTR",
|
||||
input: syscall.EINTR,
|
||||
|
||||
@@ -109,8 +109,8 @@ func TestCallContext_Close(t *testing.T) {
|
||||
sysCtx := internalsys.DefaultContext(testFS)
|
||||
fsCtx := sysCtx.FS()
|
||||
|
||||
_, errno := fsCtx.OpenFile(testFS, "/foo", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
_, err := fsCtx.OpenFile(testFS, "/foo", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
m, err := s.Instantiate(testCtx, &Module{}, t.Name(), sysCtx, nil)
|
||||
require.NoError(t, err)
|
||||
@@ -144,8 +144,8 @@ func TestCallContext_Close(t *testing.T) {
|
||||
sysCtx := internalsys.DefaultContext(testFS)
|
||||
fsCtx := sysCtx.FS()
|
||||
|
||||
_, errno := fsCtx.OpenFile(testFS, "/foo", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
_, err := fsCtx.OpenFile(testFS, "/foo", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
m, err := s.Instantiate(testCtx, &Module{}, t.Name(), sysCtx, nil)
|
||||
require.NoError(t, err)
|
||||
@@ -213,8 +213,8 @@ func TestCallContext_CallDynamic(t *testing.T) {
|
||||
sysCtx := internalsys.DefaultContext(testFS)
|
||||
fsCtx := sysCtx.FS()
|
||||
|
||||
_, errno := fsCtx.OpenFile(testFS, "/foo", os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
_, err := fsCtx.OpenFile(testFS, "/foo", os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
m, err := s.Instantiate(testCtx, &Module{}, t.Name(), sysCtx, nil)
|
||||
require.NoError(t, err)
|
||||
@@ -242,8 +242,8 @@ func TestCallContext_CallDynamic(t *testing.T) {
|
||||
fsCtx := sysCtx.FS()
|
||||
|
||||
path := "/foo"
|
||||
_, errno := fsCtx.OpenFile(testFS, path, os.O_RDONLY, 0)
|
||||
require.Zero(t, errno)
|
||||
_, err := fsCtx.OpenFile(testFS, path, os.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
m, err := s.Instantiate(testCtx, &Module{}, t.Name(), sysCtx, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
Reference in New Issue
Block a user