wasi: implements path_filestat_set_times (#1220)
This implements `path_filestat_set_times` which is the last remaining filesystem function in wasi we formerly stubbed. Other minor changes: * this removes all places we import alias path as pathutil, introducing a utility function `joinPath` where that was used to reduce name conflicts. * this fixes places where we used different variable names for the same parameter between main and test source. Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
@@ -6,7 +6,7 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"math"
|
||||
pathutil "path"
|
||||
"path"
|
||||
"reflect"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
@@ -425,6 +425,8 @@ var fdFilestatSetTimes = newHostFunc(
|
||||
|
||||
func fdFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
fd := uint32(params[0])
|
||||
atim := int64(params[1])
|
||||
mtim := int64(params[2])
|
||||
fstFlags := uint16(params[3])
|
||||
|
||||
sys := mod.(*wasm.CallContext).Sys
|
||||
@@ -435,29 +437,9 @@ func fdFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) Er
|
||||
return ErrnoBadf
|
||||
}
|
||||
|
||||
// times[0] == atim, times[1] == mtim
|
||||
times := [2]syscall.Timespec{}
|
||||
|
||||
// coerce atim into a timespec
|
||||
if set, now := fstFlags&FileStatAdjustFlagsAtim != 0, fstFlags&FileStatAdjustFlagsAtimNow != 0; set && now {
|
||||
return ErrnoInval
|
||||
} else if set {
|
||||
times[0] = syscall.NsecToTimespec(int64(params[1]))
|
||||
} else if now {
|
||||
times[0].Nsec = platform.UTIME_NOW
|
||||
} else {
|
||||
times[0].Nsec = platform.UTIME_OMIT
|
||||
}
|
||||
|
||||
// coerce mtim into a timespec
|
||||
if set, now := fstFlags&FileStatAdjustFlagsMtim != 0, fstFlags&FileStatAdjustFlagsMtimNow != 0; set && now {
|
||||
return ErrnoInval
|
||||
} else if set {
|
||||
times[1] = syscall.NsecToTimespec(int64(params[2]))
|
||||
} else if now {
|
||||
times[1].Nsec = platform.UTIME_NOW
|
||||
} else {
|
||||
times[1].Nsec = platform.UTIME_OMIT
|
||||
times, errno := toTimes(atim, mtim, fstFlags)
|
||||
if errno != ErrnoSuccess {
|
||||
return errno
|
||||
}
|
||||
|
||||
// Try to update the file timestamps by file-descriptor.
|
||||
@@ -472,6 +454,35 @@ func fdFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) Er
|
||||
return ToErrno(err)
|
||||
}
|
||||
|
||||
func toTimes(atim, mtime int64, fstFlags uint16) (times [2]syscall.Timespec, errno Errno) {
|
||||
// times[0] == atim, times[1] == mtim
|
||||
|
||||
// coerce atim into a timespec
|
||||
if set, now := fstFlags&FstflagsAtim != 0, fstFlags&FstflagsAtimNow != 0; set && now {
|
||||
errno = ErrnoInval
|
||||
return
|
||||
} else if set {
|
||||
times[0] = syscall.NsecToTimespec(atim)
|
||||
} else if now {
|
||||
times[0].Nsec = platform.UTIME_NOW
|
||||
} else {
|
||||
times[0].Nsec = platform.UTIME_OMIT
|
||||
}
|
||||
|
||||
// coerce mtim into a timespec
|
||||
if set, now := fstFlags&FstflagsMtim != 0, fstFlags&FstflagsMtimNow != 0; set && now {
|
||||
errno = ErrnoInval
|
||||
return
|
||||
} else if set {
|
||||
times[1] = syscall.NsecToTimespec(mtime)
|
||||
} else if now {
|
||||
times[1].Nsec = platform.UTIME_NOW
|
||||
} else {
|
||||
times[1].Nsec = platform.UTIME_OMIT
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// fdPread is the WASI function named FdPreadName which reads from a file
|
||||
// descriptor, without using and updating the file descriptor's offset.
|
||||
//
|
||||
@@ -882,7 +893,7 @@ func dotDirents(f *sys.FileEntry) ([]*platform.Dirent, error) {
|
||||
dotDotIno := uint64(0)
|
||||
if !f.IsPreopen && f.Name != "." {
|
||||
var st platform.Stat_t
|
||||
if err = f.FS.Stat(pathutil.Dir(f.Name), &st); err != nil {
|
||||
if err = f.FS.Stat(path.Dir(f.Name), &st); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dotDotIno = st.Ino
|
||||
@@ -1349,11 +1360,11 @@ var pathCreateDirectory = newHostFunc(
|
||||
func pathCreateDirectoryFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
dirFD := uint32(params[0])
|
||||
fd := uint32(params[0])
|
||||
path := uint32(params[1])
|
||||
pathLen := uint32(params[2])
|
||||
|
||||
preopen, pathName, errno := atPath(fsc, mod.Memory(), dirFD, path, pathLen)
|
||||
preopen, pathName, errno := atPath(fsc, mod.Memory(), fd, path, pathLen)
|
||||
if errno != ErrnoSuccess {
|
||||
return errno
|
||||
}
|
||||
@@ -1402,7 +1413,7 @@ var pathFilestatGet = newHostFunc(
|
||||
func pathFilestatGetFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
dirFD := uint32(params[0])
|
||||
fd := uint32(params[0])
|
||||
|
||||
// TODO: flags is a lookupflags and it only has one bit: symlink_follow
|
||||
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#lookupflags
|
||||
@@ -1411,7 +1422,7 @@ func pathFilestatGetFn(_ context.Context, mod api.Module, params []uint64) Errno
|
||||
path := uint32(params[2])
|
||||
pathLen := uint32(params[3])
|
||||
|
||||
preopen, pathName, errno := atPath(fsc, mod.Memory(), dirFD, path, pathLen)
|
||||
preopen, pathName, errno := atPath(fsc, mod.Memory(), fd, path, pathLen)
|
||||
if errno != ErrnoSuccess {
|
||||
return errno
|
||||
}
|
||||
@@ -1439,12 +1450,39 @@ func pathFilestatGetFn(_ context.Context, mod api.Module, params []uint64) Errno
|
||||
// which adjusts the timestamps of a file or directory.
|
||||
//
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_filestat_set_timesfd-fd-flags-lookupflags-path-string-atim-timestamp-mtim-timestamp-fst_flags-fstflags---errno
|
||||
var pathFilestatSetTimes = stubFunction(
|
||||
PathFilestatSetTimesName,
|
||||
var pathFilestatSetTimes = newHostFunc(
|
||||
PathFilestatSetTimesName, pathFilestatSetTimesFn,
|
||||
[]wasm.ValueType{i32, i32, i32, i32, i64, i64, i32},
|
||||
"fd", "flags", "path", "path_len", "atim", "mtim", "fst_flags",
|
||||
)
|
||||
|
||||
func pathFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
fd := uint32(params[0])
|
||||
flags := uint16(params[1])
|
||||
path := uint32(params[2])
|
||||
pathLen := uint32(params[3])
|
||||
atim := int64(params[4])
|
||||
mtim := int64(params[5])
|
||||
fstFlags := uint16(params[6])
|
||||
|
||||
sys := mod.(*wasm.CallContext).Sys
|
||||
fsc := sys.FS()
|
||||
|
||||
times, errno := toTimes(atim, mtim, fstFlags)
|
||||
if errno != ErrnoSuccess {
|
||||
return errno
|
||||
}
|
||||
|
||||
preopen, pathName, errno := atPath(fsc, mod.Memory(), fd, path, pathLen)
|
||||
if errno != ErrnoSuccess {
|
||||
return errno
|
||||
}
|
||||
|
||||
symlinkFollow := flags&LOOKUP_SYMLINK_FOLLOW != 0
|
||||
err := preopen.Utimens(pathName, ×, symlinkFollow)
|
||||
return ToErrno(err)
|
||||
}
|
||||
|
||||
// pathLink is the WASI function named PathLinkName which adjusts the
|
||||
// timestamps of a file or directory.
|
||||
//
|
||||
@@ -1470,11 +1508,11 @@ func pathLinkFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
return errno
|
||||
}
|
||||
|
||||
newFd := uint32(params[4])
|
||||
newFD := uint32(params[4])
|
||||
newPath := uint32(params[5])
|
||||
newPathLen := uint32(params[6])
|
||||
|
||||
newFS, newName, errno := atPath(fsc, mem, newFd, newPath, newPathLen)
|
||||
newFS, newName, errno := atPath(fsc, mem, newFD, newPath, newPathLen)
|
||||
if errno != ErrnoSuccess {
|
||||
return errno
|
||||
}
|
||||
@@ -1611,24 +1649,24 @@ func pathOpenFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
//
|
||||
// Languages including Zig and Rust use only pre-opens for the FD because
|
||||
// wasi-libc `__wasilibc_find_relpath` will only return a preopen. That said,
|
||||
// our wasi.c example shows other languages act differently and can use dirFD
|
||||
// of a non-preopen.
|
||||
// our wasi.c example shows other languages act differently and can use a non
|
||||
// pre-opened file descriptor.
|
||||
//
|
||||
// We don't handle AT_FDCWD, as that's resolved in the compiler. There's no
|
||||
// We don't handle `AT_FDCWD`, as that's resolved in the compiler. There's no
|
||||
// working directory function in WASI, so most assume CWD is "/". Notably, Zig
|
||||
// has different behavior which assumes it is whatever the first pre-open name
|
||||
// is.
|
||||
//
|
||||
// See https://github.com/WebAssembly/wasi-libc/blob/659ff414560721b1660a19685110e484a081c3d4/libc-bottom-half/sources/at_fdcwd.c
|
||||
// See https://linux.die.net/man/2/openat
|
||||
func atPath(fsc *sys.FSContext, mem api.Memory, dirFD, path, pathLen uint32) (sysfs.FS, string, Errno) {
|
||||
func atPath(fsc *sys.FSContext, mem api.Memory, fd, path, pathLen uint32) (sysfs.FS, string, Errno) {
|
||||
b, ok := mem.Read(path, pathLen)
|
||||
if !ok {
|
||||
return nil, "", ErrnoFault
|
||||
}
|
||||
pathName := string(b)
|
||||
|
||||
if f, ok := fsc.LookupFile(dirFD); !ok {
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return nil, "", ErrnoBadf // closed
|
||||
} else if _, ft, err := f.CachedStat(); err != nil {
|
||||
return nil, "", ToErrno(err)
|
||||
@@ -1637,12 +1675,13 @@ func atPath(fsc *sys.FSContext, mem api.Memory, dirFD, path, pathLen uint32) (sy
|
||||
} else if f.IsPreopen { // don't append the pre-open name
|
||||
return f.FS, pathName, ErrnoSuccess
|
||||
} else {
|
||||
return f.FS, pathutil.Join(f.Name, pathName), ErrnoSuccess
|
||||
// Join via concat to avoid name conflict on path.Join
|
||||
return f.FS, f.Name + "/" + pathName, ErrnoSuccess
|
||||
}
|
||||
}
|
||||
|
||||
func preopenPath(fsc *sys.FSContext, dirFD uint32) (string, Errno) {
|
||||
if f, ok := fsc.LookupFile(dirFD); !ok {
|
||||
func preopenPath(fsc *sys.FSContext, fd uint32) (string, Errno) {
|
||||
if f, ok := fsc.LookupFile(fd); !ok {
|
||||
return "", ErrnoBadf // closed
|
||||
} else if !f.IsPreopen {
|
||||
return "", ErrnoBadf
|
||||
@@ -1692,9 +1731,9 @@ func pathReadlinkFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
fd := uint32(params[0])
|
||||
path := uint32(params[1])
|
||||
pathLen := uint32(params[2])
|
||||
bufPtr := uint32(params[3])
|
||||
buf := uint32(params[3])
|
||||
bufLen := uint32(params[4])
|
||||
resultBufUsedPtr := uint32(params[5])
|
||||
resultBufused := uint32(params[5])
|
||||
|
||||
if pathLen == 0 || bufLen == 0 {
|
||||
return ErrnoInval
|
||||
@@ -1711,11 +1750,11 @@ func pathReadlinkFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
return ToErrno(err)
|
||||
}
|
||||
|
||||
if ok := mem.WriteString(bufPtr, dst); !ok {
|
||||
if ok := mem.WriteString(buf, dst); !ok {
|
||||
return ErrnoFault
|
||||
}
|
||||
|
||||
if !mem.WriteUint32Le(resultBufUsedPtr, uint32(len(dst))) {
|
||||
if !mem.WriteUint32Le(resultBufused, uint32(len(dst))) {
|
||||
return ErrnoFault
|
||||
}
|
||||
return ErrnoSuccess
|
||||
@@ -1752,11 +1791,11 @@ var pathRemoveDirectory = newHostFunc(
|
||||
func pathRemoveDirectoryFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
dirFD := uint32(params[0])
|
||||
fd := uint32(params[0])
|
||||
path := uint32(params[1])
|
||||
pathLen := uint32(params[2])
|
||||
|
||||
preopen, pathName, errno := atPath(fsc, mod.Memory(), dirFD, path, pathLen)
|
||||
preopen, pathName, errno := atPath(fsc, mod.Memory(), fd, path, pathLen)
|
||||
if errno != ErrnoSuccess {
|
||||
return errno
|
||||
}
|
||||
@@ -1802,20 +1841,20 @@ var pathRename = newHostFunc(
|
||||
func pathRenameFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
olddirFD := uint32(params[0])
|
||||
fd := uint32(params[0])
|
||||
oldPath := uint32(params[1])
|
||||
oldPathLen := uint32(params[2])
|
||||
|
||||
newdirFD := uint32(params[3])
|
||||
newFD := uint32(params[3])
|
||||
newPath := uint32(params[4])
|
||||
newPathLen := uint32(params[5])
|
||||
|
||||
oldFS, oldPathName, errno := atPath(fsc, mod.Memory(), olddirFD, oldPath, oldPathLen)
|
||||
oldFS, oldPathName, errno := atPath(fsc, mod.Memory(), fd, oldPath, oldPathLen)
|
||||
if errno != ErrnoSuccess {
|
||||
return errno
|
||||
}
|
||||
|
||||
newFS, newPathName, errno := atPath(fsc, mod.Memory(), newdirFD, newPath, newPathLen)
|
||||
newFS, newPathName, errno := atPath(fsc, mod.Memory(), newFD, newPath, newPathLen)
|
||||
if errno != ErrnoSuccess {
|
||||
return errno
|
||||
}
|
||||
@@ -1846,13 +1885,13 @@ func pathSymlinkFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
|
||||
oldPath := uint32(params[0])
|
||||
oldPathLen := uint32(params[1])
|
||||
dirFD := uint32(params[2])
|
||||
fd := uint32(params[2])
|
||||
newPath := uint32(params[3])
|
||||
newPathLen := uint32(params[4])
|
||||
|
||||
mem := mod.Memory()
|
||||
|
||||
dir, ok := fsc.LookupFile(dirFD)
|
||||
dir, ok := fsc.LookupFile(fd)
|
||||
if !ok {
|
||||
return ErrnoBadf // closed
|
||||
} else if _, ft, err := dir.CachedStat(); err != nil {
|
||||
@@ -1879,7 +1918,7 @@ func pathSymlinkFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
// Do not join old path since it's only resolved when dereference the link created here.
|
||||
// And the dereference result depends on the opening directory's file descriptor at that point.
|
||||
bufToStr(oldPathBuf, int(oldPathLen)),
|
||||
pathutil.Join(dir.Name, bufToStr(newPathBuf, int(newPathLen))),
|
||||
path.Join(dir.Name, bufToStr(newPathBuf, int(newPathLen))),
|
||||
); err != nil {
|
||||
return ToErrno(err)
|
||||
}
|
||||
@@ -1925,11 +1964,11 @@ var pathUnlinkFile = newHostFunc(
|
||||
func pathUnlinkFileFn(_ context.Context, mod api.Module, params []uint64) Errno {
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
dirFD := uint32(params[0])
|
||||
fd := uint32(params[0])
|
||||
path := uint32(params[1])
|
||||
pathLen := uint32(params[2])
|
||||
|
||||
preopen, pathName, errno := atPath(fsc, mod.Memory(), dirFD, path, pathLen)
|
||||
preopen, pathName, errno := atPath(fsc, mod.Memory(), fd, path, pathLen)
|
||||
if errno != ErrnoSuccess {
|
||||
return errno
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -145,5 +145,5 @@ func requireErrnoResult(t *testing.T, expectedErrno Errno, mod api.Closer, funcN
|
||||
results, err := mod.(api.Module).ExportedFunction(funcName).Call(testCtx, params...)
|
||||
require.NoError(t, err)
|
||||
errno := Errno(results[0])
|
||||
require.Equal(t, expectedErrno, errno, "want %s but got %s", ErrnoName(expectedErrno), ErrnoName(errno))
|
||||
require.Equal(t, expectedErrno, errno, "want %s but have %s", ErrnoName(expectedErrno), ErrnoName(errno))
|
||||
}
|
||||
|
||||
@@ -79,6 +79,20 @@ func testFutimens(t *testing.T, usePath bool) {
|
||||
{Sec: 123, Nsec: UTIME_NOW},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "a=set,m=omit",
|
||||
times: &[2]syscall.Timespec{
|
||||
{Sec: 123, Nsec: 4 * 1e3},
|
||||
{Sec: 123, Nsec: UTIME_OMIT},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "a=omit,m=set",
|
||||
times: &[2]syscall.Timespec{
|
||||
{Sec: 123, Nsec: UTIME_OMIT},
|
||||
{Sec: 123, Nsec: 4 * 1e3},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "a=set,m=set",
|
||||
times: &[2]syscall.Timespec{
|
||||
|
||||
@@ -2,7 +2,7 @@ package platform
|
||||
|
||||
import (
|
||||
"os"
|
||||
pathutil "path/filepath"
|
||||
path "path/filepath"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
@@ -13,13 +13,13 @@ func TestOpenFile_Errors(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
t.Run("not found must be ENOENT", func(t *testing.T) {
|
||||
_, err := OpenFile(pathutil.Join(tmpDir, "not-really-exist.txt"), os.O_RDONLY, 0o600)
|
||||
_, 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 := pathutil.Join(tmpDir, "file.txt")
|
||||
filepath := path.Join(tmpDir, "file.txt")
|
||||
f, err := OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o666)
|
||||
defer require.NoError(t, f.Close())
|
||||
require.NoError(t, err)
|
||||
@@ -29,7 +29,7 @@ func TestOpenFile_Errors(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("writing to a read-only file is EBADF", func(t *testing.T) {
|
||||
path := pathutil.Join(tmpDir, "file")
|
||||
path := path.Join(tmpDir, "file")
|
||||
require.NoError(t, os.WriteFile(path, nil, 0o600))
|
||||
|
||||
f, err := OpenFile(path, os.O_RDONLY, 0)
|
||||
@@ -41,7 +41,7 @@ func TestOpenFile_Errors(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("writing to a directory is EBADF", func(t *testing.T) {
|
||||
path := pathutil.Join(tmpDir, "diragain")
|
||||
path := path.Join(tmpDir, "diragain")
|
||||
require.NoError(t, os.Mkdir(path, 0o755))
|
||||
|
||||
f, err := OpenFile(path, os.O_RDONLY, 0)
|
||||
@@ -54,8 +54,8 @@ func TestOpenFile_Errors(t *testing.T) {
|
||||
|
||||
// This is similar to https://github.com/WebAssembly/wasi-testsuite/blob/dc7f8d27be1030cd4788ebdf07d9b57e5d23441e/tests/rust/src/bin/dangling_symlink.rs
|
||||
t.Run("dangling symlinks", func(t *testing.T) {
|
||||
target := pathutil.Join(tmpDir, "target")
|
||||
symlink := pathutil.Join(tmpDir, "dangling_symlink_symlink.cleanup")
|
||||
target := path.Join(tmpDir, "target")
|
||||
symlink := path.Join(tmpDir, "dangling_symlink_symlink.cleanup")
|
||||
|
||||
err := os.Symlink(target, symlink)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -3,7 +3,7 @@ package platform
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
pathutil "path"
|
||||
"path"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
@@ -16,8 +16,8 @@ func TestLstat(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
var stat Stat_t
|
||||
require.EqualErrno(t, syscall.ENOENT, Lstat(pathutil.Join(tmpDir, "cat"), &stat))
|
||||
require.EqualErrno(t, syscall.ENOENT, Lstat(pathutil.Join(tmpDir, "sub/cat"), &stat))
|
||||
require.EqualErrno(t, syscall.ENOENT, Lstat(path.Join(tmpDir, "cat"), &stat))
|
||||
require.EqualErrno(t, syscall.ENOENT, Lstat(path.Join(tmpDir, "sub/cat"), &stat))
|
||||
|
||||
t.Run("dir", func(t *testing.T) {
|
||||
err := Lstat(tmpDir, &stat)
|
||||
@@ -26,7 +26,7 @@ func TestLstat(t *testing.T) {
|
||||
require.NotEqual(t, uint64(0), stat.Ino)
|
||||
})
|
||||
|
||||
file := pathutil.Join(tmpDir, "file")
|
||||
file := path.Join(tmpDir, "file")
|
||||
var statFile Stat_t
|
||||
|
||||
t.Run("file", func(t *testing.T) {
|
||||
@@ -41,7 +41,7 @@ func TestLstat(t *testing.T) {
|
||||
requireLinkStat(t, file, &statFile)
|
||||
})
|
||||
|
||||
subdir := pathutil.Join(tmpDir, "sub")
|
||||
subdir := path.Join(tmpDir, "sub")
|
||||
var statSubdir Stat_t
|
||||
t.Run("subdir", func(t *testing.T) {
|
||||
require.NoError(t, os.Mkdir(subdir, 0o500))
|
||||
@@ -87,8 +87,8 @@ func TestStat(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
var stat Stat_t
|
||||
require.EqualErrno(t, syscall.ENOENT, Stat(pathutil.Join(tmpDir, "cat"), &stat))
|
||||
require.EqualErrno(t, syscall.ENOENT, Stat(pathutil.Join(tmpDir, "sub/cat"), &stat))
|
||||
require.EqualErrno(t, syscall.ENOENT, Stat(path.Join(tmpDir, "cat"), &stat))
|
||||
require.EqualErrno(t, syscall.ENOENT, Stat(path.Join(tmpDir, "sub/cat"), &stat))
|
||||
|
||||
t.Run("dir", func(t *testing.T) {
|
||||
err := Stat(tmpDir, &stat)
|
||||
@@ -97,7 +97,7 @@ func TestStat(t *testing.T) {
|
||||
require.NotEqual(t, uint64(0), stat.Ino)
|
||||
})
|
||||
|
||||
file := pathutil.Join(tmpDir, "file")
|
||||
file := path.Join(tmpDir, "file")
|
||||
var statFile Stat_t
|
||||
|
||||
t.Run("file", func(t *testing.T) {
|
||||
@@ -108,14 +108,14 @@ func TestStat(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("link to file", func(t *testing.T) {
|
||||
link := pathutil.Join(tmpDir, "file-link")
|
||||
link := path.Join(tmpDir, "file-link")
|
||||
require.NoError(t, os.Symlink(file, link))
|
||||
|
||||
require.NoError(t, Stat(link, &stat))
|
||||
require.Equal(t, statFile, stat) // resolves to the file
|
||||
})
|
||||
|
||||
subdir := pathutil.Join(tmpDir, "sub")
|
||||
subdir := path.Join(tmpDir, "sub")
|
||||
var statSubdir Stat_t
|
||||
t.Run("subdir", func(t *testing.T) {
|
||||
require.NoError(t, os.Mkdir(subdir, 0o500))
|
||||
@@ -126,7 +126,7 @@ func TestStat(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("link to dir", func(t *testing.T) {
|
||||
link := pathutil.Join(tmpDir, "dir-link")
|
||||
link := path.Join(tmpDir, "dir-link")
|
||||
require.NoError(t, os.Symlink(subdir, link))
|
||||
|
||||
require.NoError(t, Stat(link, &stat))
|
||||
@@ -159,7 +159,7 @@ func TestStatFile(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
file := pathutil.Join(tmpDir, "file")
|
||||
file := path.Join(tmpDir, "file")
|
||||
require.NoError(t, os.WriteFile(file, nil, 0o400))
|
||||
fileF, err := OpenFile(file, syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
@@ -178,7 +178,7 @@ func TestStatFile(t *testing.T) {
|
||||
require.NotEqual(t, uint64(0), stat.Ino)
|
||||
})
|
||||
|
||||
subdir := pathutil.Join(tmpDir, "sub")
|
||||
subdir := path.Join(tmpDir, "sub")
|
||||
require.NoError(t, os.Mkdir(subdir, 0o500))
|
||||
subdirF, err := OpenFile(subdir, syscall.O_RDONLY, 0)
|
||||
require.NoError(t, err)
|
||||
@@ -202,7 +202,7 @@ func TestStatFile(t *testing.T) {
|
||||
func Test_StatFile_times(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
file := pathutil.Join(tmpDir, "file")
|
||||
file := path.Join(tmpDir, "file")
|
||||
err := os.WriteFile(file, []byte{}, 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -256,17 +256,17 @@ func TestStatFile_dev_inode(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer d.Close()
|
||||
|
||||
path1 := pathutil.Join(tmpDir, "1")
|
||||
path1 := path.Join(tmpDir, "1")
|
||||
f1, err := os.Create(path1)
|
||||
require.NoError(t, err)
|
||||
defer f1.Close()
|
||||
|
||||
path2 := pathutil.Join(tmpDir, "2")
|
||||
path2 := path.Join(tmpDir, "2")
|
||||
f2, err := os.Create(path2)
|
||||
require.NoError(t, err)
|
||||
defer f2.Close()
|
||||
|
||||
pathLink2 := pathutil.Join(tmpDir, "link2")
|
||||
pathLink2 := path.Join(tmpDir, "link2")
|
||||
err = os.Symlink(path2, pathLink2)
|
||||
require.NoError(t, err)
|
||||
l2, err := os.Open(pathLink2)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
pathutil "path"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
@@ -70,7 +70,7 @@ func cleanPath(name string) string {
|
||||
if name[0] == '/' {
|
||||
cleaned = name[1:]
|
||||
}
|
||||
cleaned = pathutil.Clean(cleaned) // e.g. "sub/." -> "sub"
|
||||
cleaned = path.Clean(cleaned) // e.g. "sub/." -> "sub"
|
||||
return cleaned
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
pathutil "path"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
@@ -44,13 +43,13 @@ func TestAdapt_Rename(t *testing.T) {
|
||||
testFS := Adapt(os.DirFS(tmpDir))
|
||||
|
||||
file1 := "file1"
|
||||
file1Path := pathutil.Join(tmpDir, file1)
|
||||
file1Path := joinPath(tmpDir, file1)
|
||||
file1Contents := []byte{1}
|
||||
err := os.WriteFile(file1Path, file1Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
file2 := "file2"
|
||||
file2Path := pathutil.Join(tmpDir, file2)
|
||||
file2Path := joinPath(tmpDir, file2)
|
||||
file2Contents := []byte{2}
|
||||
err = os.WriteFile(file2Path, file2Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
@@ -64,7 +63,7 @@ func TestAdapt_Rmdir(t *testing.T) {
|
||||
testFS := Adapt(os.DirFS(tmpDir))
|
||||
|
||||
path := "rmdir"
|
||||
realPath := pathutil.Join(tmpDir, path)
|
||||
realPath := joinPath(tmpDir, path)
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
|
||||
err := testFS.Rmdir(path)
|
||||
@@ -76,7 +75,7 @@ func TestAdapt_Unlink(t *testing.T) {
|
||||
testFS := Adapt(os.DirFS(tmpDir))
|
||||
|
||||
path := "unlink"
|
||||
realPath := pathutil.Join(tmpDir, path)
|
||||
realPath := joinPath(tmpDir, path)
|
||||
require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600))
|
||||
|
||||
err := testFS.Unlink(path)
|
||||
@@ -88,7 +87,7 @@ func TestAdapt_UtimesNano(t *testing.T) {
|
||||
testFS := Adapt(os.DirFS(tmpDir))
|
||||
|
||||
path := "utimes"
|
||||
realPath := pathutil.Join(tmpDir, path)
|
||||
realPath := joinPath(tmpDir, path)
|
||||
require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600))
|
||||
|
||||
err := testFS.Utimens(path, nil, true)
|
||||
@@ -98,7 +97,7 @@ func TestAdapt_UtimesNano(t *testing.T) {
|
||||
func TestAdapt_Open_Read(t *testing.T) {
|
||||
// Create a subdirectory, so we can test reads outside the FS root.
|
||||
tmpDir := t.TempDir()
|
||||
tmpDir = pathutil.Join(tmpDir, t.Name())
|
||||
tmpDir = joinPath(tmpDir, t.Name())
|
||||
require.NoError(t, os.Mkdir(tmpDir, 0o700))
|
||||
require.NoError(t, fstest.WriteTestFiles(tmpDir))
|
||||
testFS := Adapt(os.DirFS(tmpDir))
|
||||
@@ -125,8 +124,8 @@ func TestAdapt_Lstat(t *testing.T) {
|
||||
testFS := Adapt(os.DirFS(tmpDir))
|
||||
|
||||
for _, path := range []string{"animals.txt", "sub", "sub-link"} {
|
||||
fullPath := pathutil.Join(tmpDir, path)
|
||||
linkPath := pathutil.Join(tmpDir, path+"-link")
|
||||
fullPath := joinPath(tmpDir, path)
|
||||
linkPath := joinPath(tmpDir, path+"-link")
|
||||
require.NoError(t, os.Symlink(fullPath, linkPath))
|
||||
var stat platform.Stat_t
|
||||
require.EqualErrno(t, syscall.ENOSYS, testFS.Lstat(linkPath, &stat))
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
pathutil "path"
|
||||
"path"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
@@ -63,7 +63,7 @@ func TestDirFS_MkDir(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
name := "mkdir"
|
||||
realPath := pathutil.Join(tmpDir, name)
|
||||
realPath := path.Join(tmpDir, name)
|
||||
|
||||
t.Run("doesn't exist", func(t *testing.T) {
|
||||
require.NoError(t, testFS.Mkdir(name, fs.ModeDir))
|
||||
@@ -86,7 +86,7 @@ func TestDirFS_MkDir(t *testing.T) {
|
||||
require.EqualErrno(t, syscall.EEXIST, err)
|
||||
})
|
||||
t.Run("try creating on file", func(t *testing.T) {
|
||||
filePath := pathutil.Join("non-existing-dir", "foo.txt")
|
||||
filePath := path.Join("non-existing-dir", "foo.txt")
|
||||
err := testFS.Mkdir(filePath, fs.ModeDir)
|
||||
require.EqualErrno(t, syscall.ENOENT, err)
|
||||
})
|
||||
@@ -137,7 +137,7 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
file1 := "file1"
|
||||
file1Path := pathutil.Join(tmpDir, file1)
|
||||
file1Path := path.Join(tmpDir, file1)
|
||||
err := os.WriteFile(file1Path, []byte{1}, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -149,13 +149,13 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
file1 := "file1"
|
||||
file1Path := pathutil.Join(tmpDir, file1)
|
||||
file1Path := path.Join(tmpDir, file1)
|
||||
file1Contents := []byte{1}
|
||||
err := os.WriteFile(file1Path, file1Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
file2 := "file2"
|
||||
file2Path := pathutil.Join(tmpDir, file2)
|
||||
file2Path := path.Join(tmpDir, file2)
|
||||
err = testFS.Rename(file1, file2)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -172,11 +172,11 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
dir1 := "dir1"
|
||||
dir1Path := pathutil.Join(tmpDir, dir1)
|
||||
dir1Path := path.Join(tmpDir, dir1)
|
||||
require.NoError(t, os.Mkdir(dir1Path, 0o700))
|
||||
|
||||
dir2 := "dir2"
|
||||
dir2Path := pathutil.Join(tmpDir, dir2)
|
||||
dir2Path := path.Join(tmpDir, dir2)
|
||||
err := testFS.Rename(dir1, dir2)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -193,11 +193,11 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
dir1 := "dir1"
|
||||
dir1Path := pathutil.Join(tmpDir, dir1)
|
||||
dir1Path := path.Join(tmpDir, dir1)
|
||||
require.NoError(t, os.Mkdir(dir1Path, 0o700))
|
||||
|
||||
dir2 := "dir2"
|
||||
dir2Path := pathutil.Join(tmpDir, dir2)
|
||||
dir2Path := path.Join(tmpDir, dir2)
|
||||
|
||||
// write a file to that path
|
||||
f, err := os.OpenFile(dir2Path, os.O_RDWR|os.O_CREATE, 0o600)
|
||||
@@ -212,13 +212,13 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
file1 := "file1"
|
||||
file1Path := pathutil.Join(tmpDir, file1)
|
||||
file1Path := path.Join(tmpDir, file1)
|
||||
file1Contents := []byte{1}
|
||||
err := os.WriteFile(file1Path, file1Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
dir1 := "dir1"
|
||||
dir1Path := pathutil.Join(tmpDir, dir1)
|
||||
dir1Path := path.Join(tmpDir, dir1)
|
||||
require.NoError(t, os.Mkdir(dir1Path, 0o700))
|
||||
|
||||
err = testFS.Rename(file1, dir1)
|
||||
@@ -231,18 +231,18 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
dir1 := "dir1"
|
||||
dir1Path := pathutil.Join(tmpDir, dir1)
|
||||
dir1Path := path.Join(tmpDir, dir1)
|
||||
require.NoError(t, os.Mkdir(dir1Path, 0o700))
|
||||
|
||||
// add a file to that directory
|
||||
file1 := "file1"
|
||||
file1Path := pathutil.Join(dir1Path, file1)
|
||||
file1Path := path.Join(dir1Path, file1)
|
||||
file1Contents := []byte{1}
|
||||
err := os.WriteFile(file1Path, file1Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
dir2 := "dir2"
|
||||
dir2Path := pathutil.Join(tmpDir, dir2)
|
||||
dir2Path := path.Join(tmpDir, dir2)
|
||||
require.NoError(t, os.Mkdir(dir2Path, 0o700))
|
||||
|
||||
err = testFS.Rename(dir1, dir2)
|
||||
@@ -253,7 +253,7 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
require.EqualErrno(t, syscall.ENOENT, platform.UnwrapOSError(err))
|
||||
|
||||
// Show the file inside that directory moved
|
||||
s, err := os.Stat(pathutil.Join(dir2Path, file1))
|
||||
s, err := os.Stat(path.Join(dir2Path, file1))
|
||||
require.NoError(t, err)
|
||||
require.False(t, s.IsDir())
|
||||
})
|
||||
@@ -264,22 +264,22 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
dir1 := "dir1"
|
||||
dir1Path := pathutil.Join(tmpDir, dir1)
|
||||
dir1Path := path.Join(tmpDir, dir1)
|
||||
require.NoError(t, os.Mkdir(dir1Path, 0o700))
|
||||
|
||||
// add a file to that directory
|
||||
file1 := "file1"
|
||||
file1Path := pathutil.Join(dir1Path, file1)
|
||||
file1Path := path.Join(dir1Path, file1)
|
||||
file1Contents := []byte{1}
|
||||
err := os.WriteFile(file1Path, file1Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
dir2 := "dir2"
|
||||
dir2Path := pathutil.Join(tmpDir, dir2)
|
||||
dir2Path := path.Join(tmpDir, dir2)
|
||||
require.NoError(t, os.Mkdir(dir2Path, 0o700))
|
||||
|
||||
// Make the destination non-empty.
|
||||
err = os.WriteFile(pathutil.Join(dir2Path, "existing.txt"), []byte("any thing"), 0o600)
|
||||
err = os.WriteFile(path.Join(dir2Path, "existing.txt"), []byte("any thing"), 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testFS.Rename(dir1, dir2)
|
||||
@@ -291,13 +291,13 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
file1 := "file1"
|
||||
file1Path := pathutil.Join(tmpDir, file1)
|
||||
file1Path := path.Join(tmpDir, file1)
|
||||
file1Contents := []byte{1}
|
||||
err := os.WriteFile(file1Path, file1Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
file2 := "file2"
|
||||
file2Path := pathutil.Join(tmpDir, file2)
|
||||
file2Path := path.Join(tmpDir, file2)
|
||||
file2Contents := []byte{2}
|
||||
err = os.WriteFile(file2Path, file2Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
@@ -319,7 +319,7 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
dir1 := "dir1"
|
||||
dir1Path := pathutil.Join(tmpDir, dir1)
|
||||
dir1Path := path.Join(tmpDir, dir1)
|
||||
require.NoError(t, os.Mkdir(dir1Path, 0o700))
|
||||
|
||||
err := testFS.Rename(dir1, dir1)
|
||||
@@ -334,7 +334,7 @@ func TestDirFS_Rename(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
file1 := "file1"
|
||||
file1Path := pathutil.Join(tmpDir, file1)
|
||||
file1Path := path.Join(tmpDir, file1)
|
||||
file1Contents := []byte{1}
|
||||
err := os.WriteFile(file1Path, file1Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
@@ -364,10 +364,10 @@ func TestDirFS_Rmdir(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
name := "rmdir"
|
||||
realPath := pathutil.Join(tmpDir, name)
|
||||
realPath := path.Join(tmpDir, name)
|
||||
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
fileInDir := pathutil.Join(realPath, "file")
|
||||
fileInDir := path.Join(realPath, "file")
|
||||
require.NoError(t, os.WriteFile(fileInDir, []byte{}, 0o600))
|
||||
|
||||
err := testFS.Rmdir(name)
|
||||
@@ -381,11 +381,11 @@ func TestDirFS_Rmdir(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
name := "rmdir"
|
||||
realPath := pathutil.Join(tmpDir, name)
|
||||
realPath := path.Join(tmpDir, name)
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
|
||||
// Create a file and then delete it.
|
||||
fileInDir := pathutil.Join(realPath, "file")
|
||||
fileInDir := path.Join(realPath, "file")
|
||||
require.NoError(t, os.WriteFile(fileInDir, []byte{}, 0o600))
|
||||
require.NoError(t, os.Remove(fileInDir))
|
||||
|
||||
@@ -399,7 +399,7 @@ func TestDirFS_Rmdir(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
name := "rmdir"
|
||||
realPath := pathutil.Join(tmpDir, name)
|
||||
realPath := path.Join(tmpDir, name)
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
require.NoError(t, testFS.Rmdir(name))
|
||||
_, err := os.Stat(realPath)
|
||||
@@ -411,7 +411,7 @@ func TestDirFS_Rmdir(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
name := "rmdir"
|
||||
realPath := pathutil.Join(tmpDir, name)
|
||||
realPath := path.Join(tmpDir, name)
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
|
||||
f, err := testFS.OpenFile(name, platform.O_DIRECTORY, 0o700)
|
||||
@@ -430,7 +430,7 @@ func TestDirFS_Rmdir(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
name := "rmdir"
|
||||
realPath := pathutil.Join(tmpDir, name)
|
||||
realPath := path.Join(tmpDir, name)
|
||||
|
||||
require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600))
|
||||
|
||||
@@ -456,7 +456,7 @@ func TestDirFS_Unlink(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
dir := "dir"
|
||||
realPath := pathutil.Join(tmpDir, dir)
|
||||
realPath := path.Join(tmpDir, dir)
|
||||
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
|
||||
@@ -472,7 +472,7 @@ func TestDirFS_Unlink(t *testing.T) {
|
||||
|
||||
// Create link target dir.
|
||||
subDirName := "subdir"
|
||||
subDirRealPath := pathutil.Join(tmpDir, subDirName)
|
||||
subDirRealPath := path.Join(tmpDir, subDirName)
|
||||
require.NoError(t, os.Mkdir(subDirRealPath, 0o700))
|
||||
|
||||
// Create a symlink to the subdirectory.
|
||||
@@ -489,7 +489,7 @@ func TestDirFS_Unlink(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
name := "unlink"
|
||||
realPath := pathutil.Join(tmpDir, name)
|
||||
realPath := path.Join(tmpDir, name)
|
||||
|
||||
require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600))
|
||||
|
||||
@@ -504,11 +504,11 @@ func TestDirFS_Utimesns(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
file := "file"
|
||||
err := os.WriteFile(pathutil.Join(tmpDir, file), []byte{}, 0o700)
|
||||
err := os.WriteFile(path.Join(tmpDir, file), []byte{}, 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
dir := "dir"
|
||||
err = os.Mkdir(pathutil.Join(tmpDir, dir), 0o700)
|
||||
err = os.Mkdir(path.Join(tmpDir, dir), 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("doesn't exist", func(t *testing.T) {
|
||||
@@ -595,14 +595,14 @@ func TestDirFS_Utimesns(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
file := pathutil.Join(tmpDir, "file")
|
||||
file := path.Join(tmpDir, "file")
|
||||
err := os.WriteFile(file, []byte{}, 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
link := file + "-link"
|
||||
require.NoError(t, os.Symlink(file, link))
|
||||
|
||||
dir := pathutil.Join(tmpDir, "dir")
|
||||
dir := path.Join(tmpDir, "dir")
|
||||
err = os.Mkdir(dir, 0o700)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -666,7 +666,7 @@ func TestDirFS_OpenFile(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Create a subdirectory, so we can test reads outside the FS root.
|
||||
tmpDir = pathutil.Join(tmpDir, t.Name())
|
||||
tmpDir = path.Join(tmpDir, t.Name())
|
||||
require.NoError(t, os.Mkdir(tmpDir, 0o700))
|
||||
require.NoError(t, fstest.WriteTestFiles(tmpDir))
|
||||
|
||||
@@ -730,7 +730,7 @@ func TestDirFS_Truncate(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
name := "truncate"
|
||||
realPath := pathutil.Join(tmpDir, name)
|
||||
realPath := path.Join(tmpDir, name)
|
||||
require.NoError(t, os.WriteFile(realPath, content, 0o0600))
|
||||
|
||||
err := testFS.Truncate(name, tc.size)
|
||||
@@ -746,7 +746,7 @@ func TestDirFS_Truncate(t *testing.T) {
|
||||
testFS := NewDirFS(tmpDir)
|
||||
|
||||
name := "truncate"
|
||||
realPath := pathutil.Join(tmpDir, name)
|
||||
realPath := path.Join(tmpDir, name)
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
// TODO: os.Truncate on windows can create the file even when it
|
||||
@@ -805,7 +805,7 @@ func Test_fdReaddir_opened_file_written(t *testing.T) {
|
||||
defer dirFile.Close()
|
||||
|
||||
// Then write a file to the directory.
|
||||
f, err := os.Create(pathutil.Join(root, readDirTarget, "my-file"))
|
||||
f, err := os.Create(path.Join(root, readDirTarget, "my-file"))
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
@@ -850,12 +850,12 @@ func TestDirFS_Symlink(t *testing.T) {
|
||||
require.NoError(t, testFS.Symlink("non-existing", "aa"))
|
||||
require.NoError(t, testFS.Symlink("sub/", "symlinked-subdir"))
|
||||
|
||||
st, err := os.Lstat(pathutil.Join(tmpDir, "aa"))
|
||||
st, err := os.Lstat(path.Join(tmpDir, "aa"))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "aa", st.Name())
|
||||
require.True(t, st.Mode()&fs.ModeSymlink > 0 && !st.IsDir())
|
||||
|
||||
st, err = os.Lstat(pathutil.Join(tmpDir, "symlinked-subdir"))
|
||||
st, err = os.Lstat(path.Join(tmpDir, "symlinked-subdir"))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "symlinked-subdir", st.Name())
|
||||
require.True(t, st.Mode()&fs.ModeSymlink > 0)
|
||||
|
||||
@@ -3,7 +3,6 @@ package sysfs
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
pathutil "path"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
@@ -72,13 +71,13 @@ func TestReadFS_Rename(t *testing.T) {
|
||||
testFS := NewReadFS(writeable)
|
||||
|
||||
file1 := "file1"
|
||||
file1Path := pathutil.Join(tmpDir, file1)
|
||||
file1Path := joinPath(tmpDir, file1)
|
||||
file1Contents := []byte{1}
|
||||
err := os.WriteFile(file1Path, file1Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
file2 := "file2"
|
||||
file2Path := pathutil.Join(tmpDir, file2)
|
||||
file2Path := joinPath(tmpDir, file2)
|
||||
file2Contents := []byte{2}
|
||||
err = os.WriteFile(file2Path, file2Contents, 0o600)
|
||||
require.NoError(t, err)
|
||||
@@ -93,7 +92,7 @@ func TestReadFS_Rmdir(t *testing.T) {
|
||||
testFS := NewReadFS(writeable)
|
||||
|
||||
path := "rmdir"
|
||||
realPath := pathutil.Join(tmpDir, path)
|
||||
realPath := joinPath(tmpDir, path)
|
||||
require.NoError(t, os.Mkdir(realPath, 0o700))
|
||||
|
||||
err := testFS.Rmdir(path)
|
||||
@@ -106,7 +105,7 @@ func TestReadFS_Unlink(t *testing.T) {
|
||||
testFS := NewReadFS(writeable)
|
||||
|
||||
path := "unlink"
|
||||
realPath := pathutil.Join(tmpDir, path)
|
||||
realPath := joinPath(tmpDir, path)
|
||||
require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600))
|
||||
|
||||
err := testFS.Unlink(path)
|
||||
@@ -119,7 +118,7 @@ func TestReadFS_UtimesNano(t *testing.T) {
|
||||
testFS := NewReadFS(writeable)
|
||||
|
||||
path := "utimes"
|
||||
realPath := pathutil.Join(tmpDir, path)
|
||||
realPath := joinPath(tmpDir, path)
|
||||
require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600))
|
||||
|
||||
err := testFS.Utimens(path, nil, true)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
pathutil "path"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
@@ -76,12 +76,12 @@ func TestNewRootFS(t *testing.T) {
|
||||
t.Run("multiple matches", func(t *testing.T) {
|
||||
tmpDir1 := t.TempDir()
|
||||
testFS1 := NewDirFS(tmpDir1)
|
||||
require.NoError(t, os.Mkdir(pathutil.Join(tmpDir1, "tmp"), 0o700))
|
||||
require.NoError(t, os.WriteFile(pathutil.Join(tmpDir1, "a"), []byte{1}, 0o600))
|
||||
require.NoError(t, os.Mkdir(path.Join(tmpDir1, "tmp"), 0o700))
|
||||
require.NoError(t, os.WriteFile(path.Join(tmpDir1, "a"), []byte{1}, 0o600))
|
||||
|
||||
tmpDir2 := t.TempDir()
|
||||
testFS2 := NewDirFS(tmpDir2)
|
||||
require.NoError(t, os.WriteFile(pathutil.Join(tmpDir2, "a"), []byte{2}, 0o600))
|
||||
require.NoError(t, os.WriteFile(path.Join(tmpDir2, "a"), []byte{2}, 0o600))
|
||||
|
||||
rootFS, err := NewRootFS([]FS{testFS2, testFS1}, []string{"/tmp", "/"})
|
||||
require.NoError(t, err)
|
||||
@@ -135,7 +135,7 @@ func TestRootFS_Open(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Create a subdirectory, so we can test reads outside the FS root.
|
||||
tmpDir = pathutil.Join(tmpDir, t.Name())
|
||||
tmpDir = path.Join(tmpDir, t.Name())
|
||||
require.NoError(t, os.Mkdir(tmpDir, 0o700))
|
||||
require.NoError(t, fstest.WriteTestFiles(tmpDir))
|
||||
|
||||
@@ -175,13 +175,13 @@ func TestRootFS_TestFS(t *testing.T) {
|
||||
|
||||
// move one directory outside the other
|
||||
tmpDir2 := t.TempDir()
|
||||
require.NoError(t, os.Rename(pathutil.Join(tmpDir1, "dir"), pathutil.Join(tmpDir2, "dir")))
|
||||
require.NoError(t, os.Rename(path.Join(tmpDir1, "dir"), path.Join(tmpDir2, "dir")))
|
||||
|
||||
// Create a root mount
|
||||
testFS1 := NewDirFS(tmpDir1)
|
||||
|
||||
// Create a dir mount
|
||||
testFS2 := NewDirFS(pathutil.Join(tmpDir2, "dir"))
|
||||
testFS2 := NewDirFS(path.Join(tmpDir2, "dir"))
|
||||
|
||||
testFS, err := NewRootFS([]FS{testFS1, testFS2}, []string{"/", "/dir"})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -713,3 +713,9 @@ func requireIno(t *testing.T, dirents []*platform.Dirent, expectIno bool) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// joinPath avoids us having to rename fields just to avoid conflict with the
|
||||
// path package.
|
||||
func joinPath(dirName, baseName string) string {
|
||||
return path.Join(dirName, baseName)
|
||||
}
|
||||
|
||||
@@ -136,12 +136,23 @@ var filetypeToString = [...]string{
|
||||
|
||||
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fstflags
|
||||
const (
|
||||
FileStatAdjustFlagsAtim uint16 = 1 << iota
|
||||
FileStatAdjustFlagsAtimNow
|
||||
FileStatAdjustFlagsMtim
|
||||
FileStatAdjustFlagsMtimNow
|
||||
FstflagsAtim uint16 = 1 << iota
|
||||
FstflagsAtimNow
|
||||
FstflagsMtim
|
||||
FstflagsMtimNow
|
||||
)
|
||||
|
||||
var fstflagNames = [...]string{
|
||||
"ATIM",
|
||||
"ATIM_NOW",
|
||||
"MTIM",
|
||||
"MTIM_NOW",
|
||||
}
|
||||
|
||||
func FstflagsString(fdflags int) string {
|
||||
return flagsString(fstflagNames[:], fdflags)
|
||||
}
|
||||
|
||||
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-advice-enumu8
|
||||
const (
|
||||
FdAdviceNormal byte = iota
|
||||
|
||||
@@ -96,7 +96,8 @@ func Config(fnd api.FunctionDefinition) (pSampler logging.ParamSampler, pLoggers
|
||||
var logger logging.ParamLogger
|
||||
|
||||
if isLookupFlags(fnd, name) {
|
||||
logger = (&logLookupflags{name, idx}).Log
|
||||
lf := &logLookupflags{name, idx}
|
||||
logger = lf.Log
|
||||
pLoggers = append(pLoggers, logger)
|
||||
continue
|
||||
}
|
||||
@@ -139,6 +140,8 @@ func Config(fnd api.FunctionDefinition) (pSampler logging.ParamSampler, pLoggers
|
||||
switch name {
|
||||
case "fdflags":
|
||||
logger = logFdflags(idx).Log
|
||||
case "fst_flags":
|
||||
logger = logFstflags(idx).Log
|
||||
case "oflags":
|
||||
logger = logOflags(idx).Log
|
||||
case "fs_rights_base":
|
||||
@@ -333,6 +336,13 @@ func (i logOflags) Log(_ context.Context, _ api.Module, w logging.Writer, params
|
||||
w.WriteString(OflagsString(int(params[i]))) //nolint
|
||||
}
|
||||
|
||||
type logFstflags int
|
||||
|
||||
func (i logFstflags) Log(_ context.Context, _ api.Module, w logging.Writer, params []uint64) {
|
||||
w.WriteString("fst_flags=") //nolint
|
||||
w.WriteString(FstflagsString(int(params[i]))) //nolint
|
||||
}
|
||||
|
||||
func resultParamName(name string) string {
|
||||
return name[7:] // without "result."
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ brevity.
|
||||
|
||||
When Rust compiles a `%.rs` file with a `wasm32-*` target, the output `%.wasm`
|
||||
depends on a subset of features in the [WebAssembly 1.0 Core specification]
|
||||
({{< ref "/specs#core" >}}). The `wasm32-wasi` target depends on [WASI]
|
||||
({{< ref "/specs#core" >}}). The [wasm32-wasi][15] target depends on [WASI]
|
||||
({{< ref "/specs#wasi" >}}) host functions as well.
|
||||
|
||||
Unlike some compilers, Rust also supports importing custom host functions and
|
||||
@@ -227,3 +227,4 @@ source code may reduce binary size further.
|
||||
[12]: https://github.com/rustwasm/wee_alloc
|
||||
[13]: https://doc.rust-lang.org/cargo/reference/profiles.html#profile-settings
|
||||
[14]: https://github.com/bytecodealliance/cargo-wasi
|
||||
[15]: https://github.com/rust-lang/rust/tree/1.68.0/library/std/src/sys/wasi
|
||||
|
||||
@@ -76,8 +76,9 @@ complete the below chart. If you desire something not yet implemented, please
|
||||
your use case (ex which language you are using to compile, a.k.a. target Wasm).
|
||||
|
||||
Notes:
|
||||
* C (via clang) supports the maximum WASI functions due to [wasi-libc][16]
|
||||
* AssemblyScript has its own ABI which can optionally use [wasi-shim][17]
|
||||
* C (via clang) supports the maximum WASI functions due to [wasi-libc][16]
|
||||
* Rust supports WASI via its [wasm32-wasi][18] target.
|
||||
|
||||
<details><summary>Click to see the full list of supported WASI functions</summary>
|
||||
<p>
|
||||
@@ -113,7 +114,7 @@ Notes:
|
||||
| fd_write | ✅ | Rust,TinyGo,Zig |
|
||||
| path_create_directory | ✅ | Rust,TinyGo,Zig |
|
||||
| path_filestat_get | ✅ | Rust,TinyGo,Zig |
|
||||
| path_filestat_set_times | ❌ | |
|
||||
| path_filestat_set_times | ✅ | Rust,libc |
|
||||
| path_link | ✅ | Rust,Zig |
|
||||
| path_open | ✅ | Rust,TinyGo,Zig |
|
||||
| path_readlink | ✅ | Rust,Zig |
|
||||
@@ -152,3 +153,4 @@ Note: 💀 means the function was later removed from WASI.
|
||||
[15]: https://github.com/WebAssembly/WASI/pull/458
|
||||
[16]: https://github.com/WebAssembly/wasi-libc
|
||||
[17]: https://github.com/AssemblyScript/wasi-shim
|
||||
[18]: https://github.com/rust-lang/rust/tree/1.68.0/library/std/src/sys/wasi
|
||||
|
||||
Reference in New Issue
Block a user