sysfs: Makes ReadFS and AdaptFS embeddable (#1607)

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2023-08-02 08:27:50 +08:00
committed by GitHub
parent 1f8c908f1c
commit 2f2b6a9d2c
21 changed files with 249 additions and 271 deletions
+2 -2
View File
@@ -419,9 +419,9 @@ func validateMounts(mounts sliceFlag, stdErr logging.Writer) (rc int, rootPath s
fmt.Fprintf(stdErr, "invalid mount: path %q is not a directory\n", dir)
}
root := sysfs.NewDirFS(dir)
root := sysfs.DirFS(dir)
if readOnly {
root = sysfs.NewReadFS(root)
root = &sysfs.ReadFS{FS: root}
}
config = config.(sysfs.FSConfig).WithSysFSMount(root, guestPath)
+4 -3
View File
@@ -8,6 +8,7 @@ import (
"time"
"github.com/tetratelabs/wazero/api"
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
"github.com/tetratelabs/wazero/internal/fstest"
"github.com/tetratelabs/wazero/internal/platform"
internalsys "github.com/tetratelabs/wazero/internal/sys"
@@ -325,7 +326,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
config := base.WithFS(testFS)
return config, func(t *testing.T, sys *internalsys.Context) {
rootfs := sys.FS().RootFS()
require.Equal(t, sysfs.Adapt(testFS), rootfs)
require.Equal(t, &sysfs.AdaptFS{FS: testFS}, rootfs)
}
},
},
@@ -336,7 +337,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
config := base.WithFS(testFS).WithFS(testFS2)
return config, func(t *testing.T, sys *internalsys.Context) {
rootfs := sys.FS().RootFS()
require.Equal(t, sysfs.Adapt(testFS2), rootfs)
require.Equal(t, &sysfs.AdaptFS{FS: testFS2}, rootfs)
}
},
},
@@ -346,7 +347,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
config := base.WithFS(nil)
return config, func(t *testing.T, sys *internalsys.Context) {
rootfs := sys.FS().RootFS()
require.Equal(t, sysfs.Adapt(nil), rootfs)
require.Equal(t, experimentalsys.UnimplementedFS{}, rootfs)
}
},
},
-15
View File
@@ -10,16 +10,6 @@ import (
// This should be embedded to have forward compatible implementations.
type UnimplementedFS struct{}
// String implements fmt.Stringer
func (UnimplementedFS) String() string {
return "Unimplemented:/"
}
// Open implements the same method as documented on fs.FS
func (UnimplementedFS) Open(name string) (fs.File, error) {
return nil, &fs.PathError{Op: "open", Path: name, Err: ENOSYS}
}
// OpenFile implements FS.OpenFile
func (UnimplementedFS) OpenFile(path string, flag Oflag, perm fs.FileMode) (File, Errno) {
return nil, ENOSYS
@@ -80,11 +70,6 @@ func (UnimplementedFS) Utimens(path string, atim, mtim int64) Errno {
return ENOSYS
}
// Truncate implements FS.Truncate
func (UnimplementedFS) Truncate(string, int64) Errno {
return ENOSYS
}
// UnimplementedFile is a File that returns ENOSYS for all functions,
// except where no-op are otherwise documented.
//
+20 -20
View File
@@ -10,31 +10,31 @@ import (
var moduleConfig wazero.ModuleConfig
// This example shows how to configure a sysfs.NewDirFS
func ExampleNewDirFS() {
root := sysfs.NewDirFS(".")
moduleConfig = wazero.NewModuleConfig().
WithFSConfig(wazero.NewFSConfig().(sysfs.FSConfig).WithSysFSMount(root, "/"))
}
// This example shows how to configure a sysfs.NewReadFS
func ExampleNewReadFS() {
root := sysfs.NewDirFS(".")
readOnly := sysfs.NewReadFS(root)
moduleConfig = wazero.NewModuleConfig().
WithFSConfig(wazero.NewFSConfig().(sysfs.FSConfig).WithSysFSMount(readOnly, "/"))
}
// This example shows how to adapt a fs.FS as a sys.FS
func ExampleAdapt() {
// This example shows how to adapt a fs.FS to a sys.FS
func ExampleAdaptFS() {
m := fstest.MapFS{
"a/b.txt": &fstest.MapFile{Mode: 0o666},
".": &fstest.MapFile{Mode: 0o777 | fs.ModeDir},
}
root := sysfs.Adapt(m)
root := &sysfs.AdaptFS{FS: m}
moduleConfig = wazero.NewModuleConfig().
WithFSConfig(wazero.NewFSConfig().(sysfs.FSConfig).WithSysFSMount(root, "/"))
}
// This example shows how to configure a sysfs.DirFS
func ExampleDirFS() {
root := sysfs.DirFS(".")
moduleConfig = wazero.NewModuleConfig().
WithFSConfig(wazero.NewFSConfig().(sysfs.FSConfig).WithSysFSMount(root, "/"))
}
// This example shows how to configure a sysfs.ReadFS
func ExampleReadFS() {
root := sysfs.DirFS(".")
readOnly := &sysfs.ReadFS{FS: root}
moduleConfig = wazero.NewModuleConfig().
WithFSConfig(wazero.NewFSConfig().(sysfs.FSConfig).WithSysFSMount(readOnly, "/"))
}
+14 -17
View File
@@ -8,32 +8,29 @@
package sysfs
import (
"io/fs"
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
"github.com/tetratelabs/wazero/internal/sysfs"
)
// Adapt adapts the input to sys.FS unless it is already one. Use NewDirFS
// instead of os.DirFS as it handles interop issues such as windows support.
// AdaptFS adapts the input to sys.FS. Use DirFS instead of adapting an
// os.DirFS as it handles interop issues such as windows support.
//
// Note: This performs no flag verification on OpenFile. fs.FS cannot read
// flags as there is no parameter to pass them through with. Moreover, fs.FS
// Note: This performs no flag verification on OpenFile. sys.FS cannot read
// flags as there is no parameter to pass them through with. Moreover, sys.FS
// documentation does not require the file to be present. In summary, we can't
// enforce flag behavior.
func Adapt(fs fs.FS) experimentalsys.FS {
return sysfs.Adapt(fs)
type AdaptFS = sysfs.AdaptFS
// DirFS is like os.DirFS except it returns sys.FS, which has more features.
func DirFS(dir string) experimentalsys.FS {
return sysfs.DirFS(dir)
}
// NewReadFS is used to mask an existing sys.FS for reads. Notably, this allows
// ReadFS is used to mask an existing sys.FS for reads. Notably, this allows
// the CLI to do read-only mounts of directories the host user can write, but
// doesn't want the guest wasm to. For example, Python libraries shouldn't be
// written to at runtime by the python wasm file.
func NewReadFS(fs experimentalsys.FS) experimentalsys.FS {
return sysfs.NewReadFS(fs)
}
// NewDirFS is like os.DirFS except it returns sys.FS, which has more features.
func NewDirFS(dir string) experimentalsys.FS {
return sysfs.NewDirFS(dir)
}
//
// Note: This implements read-only by returning sys.EROFS or sys.EBADF,
// depending on the operation that require write access.
type ReadFS = sysfs.ReadFS
+8 -4
View File
@@ -165,17 +165,21 @@ func (c *fsConfig) clone() *fsConfig {
// WithDirMount implements FSConfig.WithDirMount
func (c *fsConfig) WithDirMount(dir, guestPath string) FSConfig {
return c.WithSysFSMount(sysfs.NewDirFS(dir), guestPath)
return c.WithSysFSMount(sysfs.DirFS(dir), guestPath)
}
// WithReadOnlyDirMount implements FSConfig.WithReadOnlyDirMount
func (c *fsConfig) WithReadOnlyDirMount(dir, guestPath string) FSConfig {
return c.WithSysFSMount(sysfs.NewReadFS(sysfs.NewDirFS(dir)), guestPath)
return c.WithSysFSMount(&sysfs.ReadFS{FS: sysfs.DirFS(dir)}, guestPath)
}
// WithFSMount implements FSConfig.WithFSMount
func (c *fsConfig) WithFSMount(fs fs.FS, guestPath string) FSConfig {
return c.WithSysFSMount(sysfs.Adapt(fs), guestPath)
var adapted experimentalsys.FS
if fs != nil {
adapted = &sysfs.AdaptFS{FS: fs}
}
return c.WithSysFSMount(adapted, guestPath)
}
// WithSysFSMount implements sysfs.FSConfig
@@ -188,7 +192,7 @@ func (c *fsConfig) WithSysFSMount(fs experimentalsys.FS, guestPath string) FSCon
if i, ok := ret.guestPathToFS[cleaned]; ok {
ret.fs[i] = fs
ret.guestPaths[i] = guestPath
} else {
} else if fs != nil {
ret.guestPathToFS[cleaned] = len(ret.fs)
ret.fs = append(ret.fs, fs)
ret.guestPaths = append(ret.guestPaths, guestPath)
+4 -4
View File
@@ -29,13 +29,13 @@ func TestFSConfig(t *testing.T) {
{
name: "WithFSMount",
input: base.WithFSMount(testFS, "/"),
expectedFS: []sys.FS{sysfs.Adapt(testFS)},
expectedFS: []sys.FS{&sysfs.AdaptFS{FS: testFS}},
expectedGuestPaths: []string{"/"},
},
{
name: "WithFSMount overwrites",
input: base.WithFSMount(testFS, "/").WithFSMount(testFS2, "/"),
expectedFS: []sys.FS{sysfs.Adapt(testFS2)},
expectedFS: []sys.FS{&sysfs.AdaptFS{FS: testFS2}},
expectedGuestPaths: []string{"/"},
},
{
@@ -45,13 +45,13 @@ func TestFSConfig(t *testing.T) {
{
name: "WithDirMount overwrites",
input: base.WithFSMount(testFS, "/").WithDirMount(".", "/"),
expectedFS: []sys.FS{sysfs.NewDirFS(".")},
expectedFS: []sys.FS{sysfs.DirFS(".")},
expectedGuestPaths: []string{"/"},
},
{
name: "multiple",
input: base.WithReadOnlyDirMount(".", "/").WithDirMount("/tmp", "/tmp"),
expectedFS: []sys.FS{sysfs.NewReadFS(sysfs.NewDirFS(".")), sysfs.NewDirFS("/tmp")},
expectedFS: []sys.FS{&sysfs.ReadFS{FS: sysfs.DirFS(".")}, sysfs.DirFS("/tmp")},
expectedGuestPaths: []string{"/", "/tmp"},
},
}
+4 -4
View File
@@ -242,9 +242,9 @@ func Test_fdFdstatGet(t *testing.T) {
// replace stdin with a fake TTY file.
// TODO: Make this easier once we have in-memory sys.File
stdin, _ := fsc.LookupFile(sys.FdStdin)
stdinFile, errno := sysfs.Adapt(&gofstest.MapFS{"stdin": &gofstest.MapFile{
stdinFile, errno := (&sysfs.AdaptFS{FS: &gofstest.MapFS{"stdin": &gofstest.MapFile{
Mode: fs.ModeDevice | fs.ModeCharDevice | 0o600,
}}).OpenFile("stdin", 0, 0)
}}}).OpenFile("stdin", 0, 0)
require.EqualErrno(t, 0, errno)
stdin.File = stdinFile
@@ -3648,8 +3648,8 @@ func Test_pathLink(t *testing.T) {
func Test_pathOpen(t *testing.T) {
dir := t.TempDir() // open before loop to ensure no locking problems.
writeFS := sysfs.NewDirFS(dir)
readFS := sysfs.NewReadFS(writeFS)
writeFS := sysfs.DirFS(dir)
readFS := &sysfs.ReadFS{FS: writeFS}
fileName := "file"
fileContents := []byte("012")
+12 -12
View File
@@ -24,7 +24,7 @@ func TestNewFSContext(t *testing.T) {
embedFS, err := fs.Sub(testdata, "testdata")
require.NoError(t, err)
dirfs := sysfs.NewDirFS(".")
dirfs := sysfs.DirFS(".")
// Test various usual configuration for the file system.
tests := []struct {
@@ -33,21 +33,21 @@ func TestNewFSContext(t *testing.T) {
}{
{
name: "embed.FS",
fs: sysfs.Adapt(embedFS),
fs: &sysfs.AdaptFS{FS: embedFS},
},
{
name: "NewDirFS",
name: "DirFS",
// Don't use "testdata" because it may not be present in
// cross-architecture (a.k.a. scratch) build containers.
fs: dirfs,
},
{
name: "NewReadFS",
fs: sysfs.NewReadFS(dirfs),
name: "ReadFS",
fs: &sysfs.ReadFS{FS: dirfs},
},
{
name: "fstest.MapFS",
fs: sysfs.Adapt(gofstest.MapFS{}),
fs: &sysfs.AdaptFS{FS: gofstest.MapFS{}},
},
}
@@ -96,7 +96,7 @@ func TestNewFSContext(t *testing.T) {
func TestFSContext_CloseFile(t *testing.T) {
embedFS, err := fs.Sub(testdata, "testdata")
require.NoError(t, err)
testFS := sysfs.Adapt(embedFS)
testFS := &sysfs.AdaptFS{FS: embedFS}
c := Context{}
err = c.InitFSContext(nil, nil, nil, []sys.FS{testFS}, []string{"/"}, nil)
@@ -154,7 +154,7 @@ func TestFSContext_noPreopens(t *testing.T) {
}
func TestContext_Close(t *testing.T) {
testFS := sysfs.Adapt(testfs.FS{"foo": &testfs.File{}})
testFS := &sysfs.AdaptFS{FS: testfs.FS{"foo": &testfs.File{}}}
c := Context{}
err := c.InitFSContext(nil, nil, nil, []sys.FS{testFS}, []string{"/"}, nil)
@@ -181,7 +181,7 @@ func TestContext_Close(t *testing.T) {
func TestContext_Close_Error(t *testing.T) {
file := &testfs.File{CloseErr: errors.New("error closing")}
testFS := sysfs.Adapt(testfs.FS{"foo": file})
testFS := &sysfs.AdaptFS{FS: testfs.FS{"foo": file}}
c := Context{}
err := c.InitFSContext(nil, nil, nil, []sys.FS{testFS}, []string{"/"}, nil)
@@ -201,7 +201,7 @@ func TestContext_Close_Error(t *testing.T) {
func TestFSContext_Renumber(t *testing.T) {
tmpDir := t.TempDir()
dirFS := sysfs.NewDirFS(tmpDir)
dirFS := sysfs.DirFS(tmpDir)
const dirName = "dir"
errno := dirFS.Mkdir(dirName, 0o700)
@@ -252,7 +252,7 @@ func TestFSContext_Renumber(t *testing.T) {
func TestDirentCache_Read(t *testing.T) {
c := Context{}
err := c.InitFSContext(nil, nil, nil, []sys.FS{sysfs.Adapt(fstest.FS)}, []string{"/"}, nil)
err := c.InitFSContext(nil, nil, nil, []sys.FS{&sysfs.AdaptFS{FS: fstest.FS}}, []string{"/"}, nil)
require.NoError(t, err)
fsc := c.fsc
defer fsc.Close()
@@ -430,7 +430,7 @@ func TestDirentCache_ReadNewFile(t *testing.T) {
tmpDir := t.TempDir()
c := Context{}
err := c.InitFSContext(nil, nil, nil, []sys.FS{sysfs.NewDirFS(tmpDir)}, []string{"/"}, nil)
err := c.InitFSContext(nil, nil, nil, []sys.FS{sysfs.DirFS(tmpDir)}, []string{"/"}, nil)
require.NoError(t, err)
fsc := c.fsc
defer fsc.Close()
+1 -1
View File
@@ -20,7 +20,7 @@ func TestContext_WalltimeNanos(t *testing.T) {
}
func TestDefaultSysContext(t *testing.T) {
testFS := sysfs.Adapt(fstest.FS)
testFS := &sysfs.AdaptFS{FS: fstest.FS}
sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, nil, nil, []experimentalsys.FS{testFS}, []string{"/"}, nil)
require.NoError(t, err)
+63 -36
View File
@@ -9,40 +9,35 @@ import (
"github.com/tetratelabs/wazero/sys"
)
// Adapt adapts the input to sys.FS unless it is already one. Use NewDirFS instead
// of os.DirFS as it handles interop issues such as windows support.
//
// Note: This performs no flag verification on OpenFile. sys.FS cannot read
// flags as there is no parameter to pass them through with. Moreover, sys.FS
// documentation does not require the file to be present. In summary, we can't
// enforce flag behavior.
func Adapt(fs fs.FS) experimentalsys.FS {
if fs == nil {
return experimentalsys.UnimplementedFS{}
}
if sys, ok := fs.(experimentalsys.FS); ok {
return sys
}
return &adapter{fs: fs}
}
type adapter struct {
experimentalsys.UnimplementedFS
fs fs.FS
type AdaptFS struct {
FS fs.FS
}
// String implements fmt.Stringer
func (a *adapter) String() string {
return fmt.Sprintf("%v", a.fs)
func (a *AdaptFS) String() string {
return fmt.Sprintf("%v", a.FS)
}
// OpenFile implements the same method as documented on sys.FS
func (a *adapter) OpenFile(path string, flag experimentalsys.Oflag, perm fs.FileMode) (experimentalsys.File, experimentalsys.Errno) {
return OpenFSFile(a.fs, cleanPath(path), flag, perm)
func (a *AdaptFS) OpenFile(path string, flag experimentalsys.Oflag, perm fs.FileMode) (experimentalsys.File, experimentalsys.Errno) {
return OpenFSFile(a.FS, cleanPath(path), flag, perm)
}
// Lstat implements the same method as documented on sys.FS
func (a *AdaptFS) Lstat(path string) (sys.Stat_t, experimentalsys.Errno) {
// At this time, we make the assumption sys.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 are better off not making a decision that would be difficult to
// revert later on.
//
// For further discussions on the topic, see:
// https://github.com/golang/go/issues/49580
return a.Stat(path)
}
// Stat implements the same method as documented on sys.FS
func (a *adapter) Stat(path string) (sys.Stat_t, experimentalsys.Errno) {
func (a *AdaptFS) Stat(path string) (sys.Stat_t, experimentalsys.Errno) {
f, errno := a.OpenFile(path, experimentalsys.O_RDONLY, 0)
if errno != 0 {
return sys.Stat_t{}, errno
@@ -51,17 +46,49 @@ func (a *adapter) Stat(path string) (sys.Stat_t, experimentalsys.Errno) {
return f.Stat()
}
// Lstat implements the same method as documented on sys.FS
func (a *adapter) Lstat(path string) (sys.Stat_t, experimentalsys.Errno) {
// At this time, we make the assumption that sys.FS instances do not support
// symbolic links, therefore Lstat is the same as Stat. This is obviously
// not true but until sys.FS has a solid story for how to handle symlinks we
// are better off not making a decision that would be difficult to revert
// later on.
//
// For further discussions on the topic, see:
// https://github.com/golang/go/issues/49580
return a.Stat(path)
// Readlink implements the same method as documented on sys.FS
func (a *AdaptFS) Readlink(string) (string, experimentalsys.Errno) {
return "", experimentalsys.ENOSYS
}
// Mkdir implements the same method as documented on sys.FS
func (a *AdaptFS) Mkdir(string, fs.FileMode) experimentalsys.Errno {
return experimentalsys.ENOSYS
}
// Chmod implements the same method as documented on sys.FS
func (a *AdaptFS) Chmod(string, fs.FileMode) experimentalsys.Errno {
return experimentalsys.ENOSYS
}
// Rename implements the same method as documented on sys.FS
func (a *AdaptFS) Rename(string, string) experimentalsys.Errno {
return experimentalsys.ENOSYS
}
// Rmdir implements the same method as documented on sys.FS
func (a *AdaptFS) Rmdir(string) experimentalsys.Errno {
return experimentalsys.ENOSYS
}
// Link implements the same method as documented on sys.FS
func (a *AdaptFS) Link(string, string) experimentalsys.Errno {
return experimentalsys.ENOSYS
}
// Symlink implements the same method as documented on sys.FS
func (a *AdaptFS) Symlink(string, string) experimentalsys.Errno {
return experimentalsys.ENOSYS
}
// Unlink implements the same method as documented on sys.FS
func (a *AdaptFS) Unlink(string) experimentalsys.Errno {
return experimentalsys.ENOSYS
}
// Utimens implements the same method as documented on sys.FS
func (a *AdaptFS) Utimens(string, int64, int64) experimentalsys.Errno {
return experimentalsys.ENOSYS
}
func cleanPath(name string) string {
+24 -30
View File
@@ -17,29 +17,23 @@ import (
"github.com/tetratelabs/wazero/sys"
)
func TestAdapt_nil(t *testing.T) {
testFS := Adapt(nil)
_, ok := testFS.(experimentalsys.UnimplementedFS)
require.True(t, ok)
}
func TestAdapt_MkDir(t *testing.T) {
testFS := Adapt(os.DirFS(t.TempDir()))
func TestAdaptFS_MkDir(t *testing.T) {
testFS := &AdaptFS{FS: os.DirFS(t.TempDir())}
err := testFS.Mkdir("mkdir", fs.ModeDir)
require.EqualErrno(t, experimentalsys.ENOSYS, err)
}
func TestAdapt_Chmod(t *testing.T) {
testFS := Adapt(os.DirFS(t.TempDir()))
func TestAdaptFS_Chmod(t *testing.T) {
testFS := &AdaptFS{FS: os.DirFS(t.TempDir())}
err := testFS.Chmod("chmod", fs.ModeDir)
require.EqualErrno(t, experimentalsys.ENOSYS, err)
}
func TestAdapt_Rename(t *testing.T) {
func TestAdaptFS_Rename(t *testing.T) {
tmpDir := t.TempDir()
testFS := Adapt(os.DirFS(tmpDir))
testFS := &AdaptFS{FS: os.DirFS(tmpDir)}
file1 := "file1"
file1Path := joinPath(tmpDir, file1)
@@ -57,9 +51,9 @@ func TestAdapt_Rename(t *testing.T) {
require.EqualErrno(t, experimentalsys.ENOSYS, err)
}
func TestAdapt_Rmdir(t *testing.T) {
func TestAdaptFS_Rmdir(t *testing.T) {
tmpDir := t.TempDir()
testFS := Adapt(os.DirFS(tmpDir))
testFS := &AdaptFS{FS: os.DirFS(tmpDir)}
path := "rmdir"
realPath := joinPath(tmpDir, path)
@@ -69,9 +63,9 @@ func TestAdapt_Rmdir(t *testing.T) {
require.EqualErrno(t, experimentalsys.ENOSYS, err)
}
func TestAdapt_Unlink(t *testing.T) {
func TestAdaptFS_Unlink(t *testing.T) {
tmpDir := t.TempDir()
testFS := Adapt(os.DirFS(tmpDir))
testFS := &AdaptFS{FS: os.DirFS(tmpDir)}
path := "unlink"
realPath := joinPath(tmpDir, path)
@@ -81,9 +75,9 @@ func TestAdapt_Unlink(t *testing.T) {
require.EqualErrno(t, experimentalsys.ENOSYS, err)
}
func TestAdapt_UtimesNano(t *testing.T) {
func TestAdaptFS_UtimesNano(t *testing.T) {
tmpDir := t.TempDir()
testFS := Adapt(os.DirFS(tmpDir))
testFS := &AdaptFS{FS: os.DirFS(tmpDir)}
path := "utimes"
realPath := joinPath(tmpDir, path)
@@ -93,13 +87,13 @@ func TestAdapt_UtimesNano(t *testing.T) {
require.EqualErrno(t, experimentalsys.ENOSYS, err)
}
func TestAdapt_Open_Read(t *testing.T) {
// Create a subdirectory, so we can test reads outside the sys.FS root.
func TestAdaptFS_Open_Read(t *testing.T) {
tmpDir := t.TempDir()
// Create a subdirectory, so we can test reads outside the sys.FS root.
tmpDir = joinPath(tmpDir, t.Name())
require.NoError(t, os.Mkdir(tmpDir, 0o700))
require.NoError(t, fstest.WriteTestFiles(tmpDir))
testFS := Adapt(os.DirFS(tmpDir))
testFS := &AdaptFS{FS: os.DirFS(tmpDir)}
// We can't correct operating system portability issues with os.DirFS on
// windows. Use syscall.DirFS instead!
@@ -113,10 +107,10 @@ func TestAdapt_Open_Read(t *testing.T) {
})
}
func TestAdapt_Lstat(t *testing.T) {
func TestAdaptFS_Lstat(t *testing.T) {
tmpDir := t.TempDir()
testFS := &AdaptFS{FS: os.DirFS(tmpDir)}
require.NoError(t, fstest.WriteTestFiles(tmpDir))
testFS := Adapt(os.DirFS(tmpDir))
for _, path := range []string{"animals.txt", "sub", "sub-link"} {
fullPath := joinPath(tmpDir, path)
@@ -128,15 +122,15 @@ func TestAdapt_Lstat(t *testing.T) {
}
}
func TestAdapt_Stat(t *testing.T) {
func TestAdaptFS_Stat(t *testing.T) {
tmpDir := t.TempDir()
testFS := &AdaptFS{FS: os.DirFS(tmpDir)}
require.NoError(t, fstest.WriteTestFiles(tmpDir))
testFS := Adapt(os.DirFS(tmpDir))
testStat(t, testFS)
}
// hackFS cheats the api.FS contract by opening for write (sys.O_RDWR).
// hackFS cheats the fs.FS contract by opening for write (sys.O_RDWR).
//
// Until we have an alternate public interface for filesystems, some users will
// rely on this. Via testing, we ensure we don't accidentally break them.
@@ -156,11 +150,11 @@ func (dir hackFS) Open(name string) (fs.File, error) {
}
}
// TestAdapt_HackedWrites ensures we allow writes even if they violate the
// TestAdaptFS_HackedWrites ensures we allow writes even if they violate the
// api.FS contract.
func TestAdapt_HackedWrites(t *testing.T) {
func TestAdaptFS_HackedWrites(t *testing.T) {
tmpDir := t.TempDir()
testFS := Adapt(hackFS(tmpDir))
testFS := &AdaptFS{FS: hackFS(tmpDir)}
testOpen_O_RDWR(t, tmpDir, testFS)
}
@@ -237,7 +231,7 @@ func (i *sysFileInfo) Sys() any {
// to zero).
//
// A fs.File implementing this should be functionally equivalent to an os.File,
// even if both are less ideal than using NewDirFS directly, especially on
// even if both are less ideal than using DirFS directly, especially on
// Windows.
//
// For example, on Windows, we cannot reliably read the inode for a
+4 -1
View File
@@ -9,7 +9,7 @@ import (
"github.com/tetratelabs/wazero/sys"
)
func NewDirFS(dir string) experimentalsys.FS {
func DirFS(dir string) experimentalsys.FS {
return &dirFS{
dir: dir,
cleanedDir: ensureTrailingPathSeparator(dir),
@@ -23,8 +23,11 @@ func ensureTrailingPathSeparator(dir string) string {
return dir
}
// dirFS is not exported because the input fields must be maintained together.
// This is likely why os.DirFS doesn't, either!
type dirFS struct {
experimentalsys.UnimplementedFS
dir string
// cleanedDir is for easier OS-specific concatenation, as it always has
// a trailing path separator.
+37 -37
View File
@@ -16,8 +16,8 @@ import (
"github.com/tetratelabs/wazero/internal/testing/require"
)
func TestNewDirFS(t *testing.T) {
testFS := NewDirFS(".")
func TestDirFS(t *testing.T) {
testFS := DirFS(".")
// Guest can look up /
f, errno := testFS.OpenFile("/", sys.O_RDONLY, 0)
@@ -25,14 +25,14 @@ func TestNewDirFS(t *testing.T) {
require.EqualErrno(t, 0, f.Close())
t.Run("host path not found", func(t *testing.T) {
testFS := NewDirFS("a")
testFS := DirFS("a")
_, errno = testFS.OpenFile(".", sys.O_RDONLY, 0)
require.EqualErrno(t, sys.ENOENT, errno)
})
t.Run("host path not a directory", func(t *testing.T) {
arg0 := os.Args[0] // should be safe in scratch tests which don't have the source mounted.
testFS := NewDirFS(arg0)
testFS := DirFS(arg0)
d, errno := testFS.OpenFile(".", sys.O_RDONLY, 0)
require.EqualErrno(t, 0, errno)
_, errno = d.Readdir(-1)
@@ -41,13 +41,13 @@ func TestNewDirFS(t *testing.T) {
}
func TestDirFS_join(t *testing.T) {
testFS := NewDirFS("/").(*dirFS)
testFS := DirFS("/").(*dirFS)
require.Equal(t, "/", testFS.join(""))
require.Equal(t, "/", testFS.join("."))
require.Equal(t, "/", testFS.join("/"))
require.Equal(t, "/tmp", testFS.join("tmp"))
testFS = NewDirFS(".").(*dirFS)
testFS = DirFS(".").(*dirFS)
require.Equal(t, ".", testFS.join(""))
require.Equal(t, ".", testFS.join("."))
require.Equal(t, ".", testFS.join("/"))
@@ -55,7 +55,7 @@ func TestDirFS_join(t *testing.T) {
}
func TestDirFS_String(t *testing.T) {
testFS := NewDirFS(".")
testFS := DirFS(".")
// String has the name of the path entered
require.Equal(t, ".", testFS.(fmt.Stringer).String())
@@ -65,7 +65,7 @@ func TestDirFS_Lstat(t *testing.T) {
tmpDir := t.TempDir()
require.NoError(t, fstest.WriteTestFiles(tmpDir))
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
for _, path := range []string{"animals.txt", "sub", "sub-link"} {
require.EqualErrno(t, 0, testFS.Symlink(path, path+"-link"))
}
@@ -75,7 +75,7 @@ func TestDirFS_Lstat(t *testing.T) {
func TestDirFS_MkDir(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
name := "mkdir"
realPath := path.Join(tmpDir, name)
@@ -152,7 +152,7 @@ func requireMode(t *testing.T, testFS sys.FS, path string, mode fs.FileMode) {
func TestDirFS_Rename(t *testing.T) {
t.Run("from doesn't exist", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
file1 := "file1"
file1Path := path.Join(tmpDir, file1)
@@ -164,7 +164,7 @@ func TestDirFS_Rename(t *testing.T) {
})
t.Run("file to non-exist", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
file1 := "file1"
file1Path := path.Join(tmpDir, file1)
@@ -187,7 +187,7 @@ func TestDirFS_Rename(t *testing.T) {
})
t.Run("dir to non-exist", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
dir1 := "dir1"
dir1Path := path.Join(tmpDir, dir1)
@@ -208,7 +208,7 @@ func TestDirFS_Rename(t *testing.T) {
})
t.Run("dir to file", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
dir1 := "dir1"
dir1Path := path.Join(tmpDir, dir1)
@@ -227,7 +227,7 @@ func TestDirFS_Rename(t *testing.T) {
})
t.Run("file to dir", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
file1 := "file1"
file1Path := path.Join(tmpDir, file1)
@@ -246,7 +246,7 @@ func TestDirFS_Rename(t *testing.T) {
// Similar to https://github.com/ziglang/zig/blob/0.10.1/lib/std/fs/test.zig#L567-L582
t.Run("dir to empty dir should be fine", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
dir1 := "dir1"
dir1Path := path.Join(tmpDir, dir1)
@@ -279,7 +279,7 @@ func TestDirFS_Rename(t *testing.T) {
// Similar to https://github.com/ziglang/zig/blob/0.10.1/lib/std/fs/test.zig#L584-L604
t.Run("dir to non empty dir should be EXIST", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
dir1 := "dir1"
dir1Path := path.Join(tmpDir, dir1)
@@ -306,7 +306,7 @@ func TestDirFS_Rename(t *testing.T) {
t.Run("file to file", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
file1 := "file1"
file1Path := path.Join(tmpDir, file1)
@@ -334,7 +334,7 @@ func TestDirFS_Rename(t *testing.T) {
})
t.Run("dir to itself", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
dir1 := "dir1"
dir1Path := path.Join(tmpDir, dir1)
@@ -349,7 +349,7 @@ func TestDirFS_Rename(t *testing.T) {
})
t.Run("file to itself", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
file1 := "file1"
file1Path := path.Join(tmpDir, file1)
@@ -369,7 +369,7 @@ func TestDirFS_Rename(t *testing.T) {
func TestDirFS_Rmdir(t *testing.T) {
t.Run("doesn't exist", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
name := "rmdir"
@@ -379,7 +379,7 @@ func TestDirFS_Rmdir(t *testing.T) {
t.Run("dir not empty", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
name := "rmdir"
realPath := path.Join(tmpDir, name)
@@ -396,7 +396,7 @@ func TestDirFS_Rmdir(t *testing.T) {
t.Run("dir previously not empty", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
name := "rmdir"
realPath := path.Join(tmpDir, name)
@@ -414,7 +414,7 @@ func TestDirFS_Rmdir(t *testing.T) {
t.Run("dir empty", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
name := "rmdir"
realPath := path.Join(tmpDir, name)
@@ -426,7 +426,7 @@ func TestDirFS_Rmdir(t *testing.T) {
t.Run("dir empty while opening", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
name := "rmdir"
realPath := path.Join(tmpDir, name)
@@ -443,7 +443,7 @@ func TestDirFS_Rmdir(t *testing.T) {
t.Run("not directory", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
name := "rmdir"
realPath := path.Join(tmpDir, name)
@@ -460,7 +460,7 @@ func TestDirFS_Rmdir(t *testing.T) {
func TestDirFS_Unlink(t *testing.T) {
t.Run("doesn't exist", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
name := "unlink"
err := testFS.Unlink(name)
@@ -469,7 +469,7 @@ func TestDirFS_Unlink(t *testing.T) {
t.Run("target: dir", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
dir := "dir"
realPath := path.Join(tmpDir, dir)
@@ -484,7 +484,7 @@ func TestDirFS_Unlink(t *testing.T) {
t.Run("target: symlink to dir", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
// Create link target dir.
subDirName := "subdir"
@@ -502,7 +502,7 @@ func TestDirFS_Unlink(t *testing.T) {
t.Run("file exists", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
name := "unlink"
realPath := path.Join(tmpDir, name)
@@ -518,7 +518,7 @@ func TestDirFS_Unlink(t *testing.T) {
func TestDirFS_Utimesns(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
file := "file"
err := os.WriteFile(path.Join(tmpDir, file), []byte{}, 0o700)
@@ -574,7 +574,7 @@ func TestDirFS_Utimesns(t *testing.T) {
t.Run(name, func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
file := path.Join(tmpDir, "file")
errno := os.WriteFile(file, []byte{}, 0o700)
@@ -638,7 +638,7 @@ func TestDirFS_OpenFile(t *testing.T) {
require.NoError(t, os.Mkdir(tmpDir, 0o700))
require.NoError(t, fstest.WriteTestFiles(tmpDir))
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
testOpen_Read(t, testFS, statSetsIno(), true)
@@ -656,7 +656,7 @@ func TestDirFS_Stat(t *testing.T) {
tmpDir := t.TempDir()
require.NoError(t, fstest.WriteTestFiles(tmpDir))
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
testStat(t, testFS)
// from os.TestDirFSPathsValid
@@ -673,7 +673,7 @@ func TestDirFS_Stat(t *testing.T) {
func TestDirFS_Readdir(t *testing.T) {
root := t.TempDir()
testFS := NewDirFS(root)
testFS := DirFS(root)
const readDirTarget = "dir"
errno := testFS.Mkdir(readDirTarget, 0o700)
@@ -728,7 +728,7 @@ func TestDirFS_Link(t *testing.T) {
tmpDir := t.TempDir()
require.NoError(t, fstest.WriteTestFiles(tmpDir))
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
require.EqualErrno(t, testFS.Link("cat", ""), sys.ENOENT)
require.EqualErrno(t, testFS.Link("sub/test.txt", "sub/test.txt"), sys.EEXIST)
@@ -745,7 +745,7 @@ func TestDirFS_Symlink(t *testing.T) {
tmpDir := t.TempDir()
require.NoError(t, fstest.WriteTestFiles(tmpDir))
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
require.EqualErrno(t, sys.EEXIST, testFS.Symlink("sub/test.txt", "sub/test.txt"))
// Non-existing old name is allowed.
@@ -767,6 +767,6 @@ func TestDirFS_Readlink(t *testing.T) {
tmpDir := t.TempDir()
require.NoError(t, fstest.WriteTestFiles(tmpDir))
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
testReadlink(t, testFS, testFS)
}
+4 -4
View File
@@ -60,7 +60,7 @@ func OpenFSFile(fs fs.FS, path string, flag experimentalsys.Oflag, perm fs.FileM
return nil, errno
}
// Don't return an os.File because the path is not absolute. osFile needs
// the path to be real and certain fs.File impls are subrooted.
// the path to be real and certain FS.File impls are subrooted.
return &fsFile{fs: fs, name: path, file: f}, 0
}
@@ -261,7 +261,7 @@ func (f *fsFile) Seek(offset int64, whence int) (newOffset int64, errno experime
// Notably, this uses readdirFile or fs.ReadDirFile if available. This does not
// return inodes on windows.
func (f *fsFile) Readdir(n int) (dirents []experimentalsys.Dirent, errno experimentalsys.Errno) {
// Windows lets you Readdir after close, fs.File also may not implement
// Windows lets you Readdir after close, FS.File also may not implement
// close in a meaningful way. read our closed field to return consistent
// results.
if f.closed {
@@ -286,8 +286,8 @@ func (f *fsFile) Readdir(n int) (dirents []experimentalsys.Dirent, errno experim
return
}
// Try with fs.ReadDirFile which is available on api.FS implementations
// like embed:fs.
// Try with FS.ReadDirFile which is available on api.FS implementations
// like embed:FS.
if rdf, ok := f.file.(fs.ReadDirFile); ok {
entries, e := rdf.ReadDir(n)
if errno = adjustReaddirErr(f, f.closed, e); errno != 0 {
+1 -1
View File
@@ -832,7 +832,7 @@ func testSync_NoError(t *testing.T, sync func(experimentalsys.File) experimental
f experimentalsys.File
}{
{name: "UnimplementedFile", f: experimentalsys.UnimplementedFile{}},
{name: "File of read-only fs.File", f: ro},
{name: "File of read-only FS.File", f: ro},
{name: "File of os.File", f: rw},
}
+1 -1
View File
@@ -14,7 +14,7 @@ func inoFromFileInfo(dirPath string, info fs.FileInfo) (ino sys.Inode, errno exp
return v.Ino, 0
}
if dirPath == "" {
// This is a fs.File backed implementation which doesn't have access to
// This is a FS.File backed implementation which doesn't have access to
// the original file path.
return
}
+13 -43
View File
@@ -6,51 +6,21 @@ import (
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
)
// NewReadFS is used to mask an existing sys.FS for reads. Notably, this allows
// the CLI to do read-only mounts of directories the host user can write, but
// doesn't want the guest wasm to. For example, Python libraries shouldn't be
// written to at runtime by the python wasm file.
func NewReadFS(fs experimentalsys.FS) experimentalsys.FS {
if _, ok := fs.(*readFS); ok {
return fs
} else if _, ok = fs.(experimentalsys.UnimplementedFS); ok {
return fs // unimplemented is read-only
}
return &readFS{fs}
}
type readFS struct {
type ReadFS struct {
experimentalsys.FS
}
// OpenFile implements the same method as documented on sys.FS
func (r *readFS) OpenFile(path string, flag experimentalsys.Oflag, perm fs.FileMode) (experimentalsys.File, experimentalsys.Errno) {
// TODO: Once the real implementation is complete, move the below to
// /RATIONALE.md. Doing this while the type is unstable creates
// documentation drift as we expect a lot of reshaping meanwhile.
//
// Callers of this function expect to either open a valid file handle, or
// get an error, if they can't. We want to return ENOSYS if opened for
// anything except reads.
//
// Instead, we could return a fake no-op file on O_WRONLY. However, this
// hurts observability because a later write error to that file will be on
// a different source code line than the root cause which is opening with
// an unsupported flag.
//
// The tricky part is os.RD_ONLY is typically defined as zero, so while the
// parameter is named flag, the part about opening read vs write isn't a
// typical bitflag. We can't compare against zero anyway, because even if
// there isn't a current flag to OR in with that, there may be in the
// future. What we do instead is mask the flags about read/write mode and
// check if they are the opposite of read or not.
func (r *ReadFS) OpenFile(path string, flag experimentalsys.Oflag, perm fs.FileMode) (experimentalsys.File, experimentalsys.Errno) {
// Mask the mutually exclusive bits as they determine write mode.
switch flag & (experimentalsys.O_RDONLY | experimentalsys.O_WRONLY | experimentalsys.O_RDWR) {
case experimentalsys.O_WRONLY, experimentalsys.O_RDWR:
// Return the correct error if a directory was opened for write.
if flag&experimentalsys.O_DIRECTORY != 0 {
return nil, experimentalsys.EISDIR
}
return nil, experimentalsys.ENOSYS
default: // sys.O_RDONLY (or no flag) so we are ok!
default: // sys.O_RDONLY (integer zero) so we are ok!
}
f, errno := r.FS.OpenFile(path, flag, perm)
@@ -61,42 +31,42 @@ func (r *readFS) OpenFile(path string, flag experimentalsys.Oflag, perm fs.FileM
}
// Mkdir implements the same method as documented on sys.FS
func (r *readFS) Mkdir(path string, perm fs.FileMode) experimentalsys.Errno {
func (r *ReadFS) Mkdir(path string, perm fs.FileMode) experimentalsys.Errno {
return experimentalsys.EROFS
}
// Chmod implements the same method as documented on sys.FS
func (r *readFS) Chmod(path string, perm fs.FileMode) experimentalsys.Errno {
func (r *ReadFS) Chmod(path string, perm fs.FileMode) experimentalsys.Errno {
return experimentalsys.EROFS
}
// Rename implements the same method as documented on sys.FS
func (r *readFS) Rename(from, to string) experimentalsys.Errno {
func (r *ReadFS) Rename(from, to string) experimentalsys.Errno {
return experimentalsys.EROFS
}
// Rmdir implements the same method as documented on sys.FS
func (r *readFS) Rmdir(path string) experimentalsys.Errno {
func (r *ReadFS) Rmdir(path string) experimentalsys.Errno {
return experimentalsys.EROFS
}
// Link implements the same method as documented on sys.FS
func (r *readFS) Link(_, _ string) experimentalsys.Errno {
func (r *ReadFS) Link(_, _ string) experimentalsys.Errno {
return experimentalsys.EROFS
}
// Symlink implements the same method as documented on sys.FS
func (r *readFS) Symlink(_, _ string) experimentalsys.Errno {
func (r *ReadFS) Symlink(_, _ string) experimentalsys.Errno {
return experimentalsys.EROFS
}
// Unlink implements the same method as documented on sys.FS
func (r *readFS) Unlink(path string) experimentalsys.Errno {
func (r *ReadFS) Unlink(path string) experimentalsys.Errno {
return experimentalsys.EROFS
}
// Utimens implements the same method as documented on sys.FS
func (r *readFS) Utimens(path string, atim, mtim int64) experimentalsys.Errno {
func (r *ReadFS) Utimens(path string, atim, mtim int64) experimentalsys.Errno {
return experimentalsys.EROFS
}
+28 -31
View File
@@ -14,16 +14,13 @@ import (
func TestNewReadFS(t *testing.T) {
tmpDir := t.TempDir()
// Doesn't double-wrap file systems that are already read-only
require.Equal(t, sys.UnimplementedFS{}, NewReadFS(sys.UnimplementedFS{}))
// Wraps a sys.FS because it allows access to Write
adapted := Adapt(os.DirFS(tmpDir))
require.NotEqual(t, adapted, NewReadFS(adapted))
adapted := &AdaptFS{FS: os.DirFS(tmpDir)}
require.NotEqual(t, adapted, &ReadFS{FS: adapted})
// Wraps a writeable file system
writeable := NewDirFS(tmpDir)
readFS := NewReadFS(writeable)
writeable := DirFS(tmpDir)
readFS := &ReadFS{FS: writeable}
require.NotEqual(t, writeable, readFS)
}
@@ -31,27 +28,27 @@ func TestReadFS_Lstat(t *testing.T) {
tmpDir := t.TempDir()
require.NoError(t, fstest.WriteTestFiles(tmpDir))
writeable := NewDirFS(tmpDir)
writeable := DirFS(tmpDir)
for _, path := range []string{"animals.txt", "sub", "sub-link"} {
require.EqualErrno(t, 0, writeable.Symlink(path, path+"-link"))
}
testFS := NewReadFS(writeable)
testFS := &ReadFS{FS: writeable}
testLstat(t, testFS)
}
func TestReadFS_MkDir(t *testing.T) {
writeable := NewDirFS(t.TempDir())
testFS := NewReadFS(writeable)
writeable := DirFS(t.TempDir())
testFS := &ReadFS{FS: writeable}
err := testFS.Mkdir("mkdir", fs.ModeDir)
require.EqualErrno(t, sys.EROFS, err)
}
func TestReadFS_Chmod(t *testing.T) {
writeable := NewDirFS(t.TempDir())
testFS := NewReadFS(writeable)
writeable := DirFS(t.TempDir())
testFS := &ReadFS{FS: writeable}
err := testFS.Chmod("chmod", fs.ModeDir)
require.EqualErrno(t, sys.EROFS, err)
@@ -59,8 +56,8 @@ func TestReadFS_Chmod(t *testing.T) {
func TestReadFS_Rename(t *testing.T) {
tmpDir := t.TempDir()
writeable := NewDirFS(tmpDir)
testFS := NewReadFS(writeable)
writeable := DirFS(tmpDir)
testFS := &ReadFS{FS: writeable}
file1 := "file1"
file1Path := joinPath(tmpDir, file1)
@@ -80,8 +77,8 @@ func TestReadFS_Rename(t *testing.T) {
func TestReadFS_Rmdir(t *testing.T) {
tmpDir := t.TempDir()
writeable := NewDirFS(tmpDir)
testFS := NewReadFS(writeable)
writeable := DirFS(tmpDir)
testFS := &ReadFS{FS: writeable}
path := "rmdir"
realPath := joinPath(tmpDir, path)
@@ -93,8 +90,8 @@ func TestReadFS_Rmdir(t *testing.T) {
func TestReadFS_Unlink(t *testing.T) {
tmpDir := t.TempDir()
writeable := NewDirFS(tmpDir)
testFS := NewReadFS(writeable)
writeable := DirFS(tmpDir)
testFS := &ReadFS{FS: writeable}
path := "unlink"
realPath := joinPath(tmpDir, path)
@@ -106,8 +103,8 @@ func TestReadFS_Unlink(t *testing.T) {
func TestReadFS_UtimesNano(t *testing.T) {
tmpDir := t.TempDir()
writeable := NewDirFS(tmpDir)
testFS := NewReadFS(writeable)
writeable := DirFS(tmpDir)
testFS := &ReadFS{FS: writeable}
path := "utimes"
realPath := joinPath(tmpDir, path)
@@ -129,7 +126,7 @@ func TestReadFS_Open_Read(t *testing.T) {
{
name: "DirFS",
fs: func(tmpDir string) sys.FS {
return NewDirFS(tmpDir)
return DirFS(tmpDir)
},
expectFileIno: true,
expectDirIno: true,
@@ -137,7 +134,7 @@ func TestReadFS_Open_Read(t *testing.T) {
{
name: "fstest.MapFS",
fs: func(tmpDir string) sys.FS {
return Adapt(fstest.FS)
return &AdaptFS{FS: fstest.FS}
},
expectFileIno: false,
expectDirIno: false,
@@ -145,7 +142,7 @@ func TestReadFS_Open_Read(t *testing.T) {
{
name: "os.DirFS",
fs: func(tmpDir string) sys.FS {
return Adapt(os.DirFS(tmpDir))
return &AdaptFS{FS: os.DirFS(tmpDir)}
},
expectFileIno: statSetsIno(),
expectDirIno: runtime.GOOS != "windows",
@@ -153,7 +150,7 @@ func TestReadFS_Open_Read(t *testing.T) {
{
name: "mask(os.DirFS)",
fs: func(tmpDir string) sys.FS {
return Adapt(&MaskOsFS{Fs: os.DirFS(tmpDir)})
return &AdaptFS{FS: &MaskOsFS{Fs: os.DirFS(tmpDir)}}
},
expectFileIno: statSetsIno(),
expectDirIno: runtime.GOOS != "windows",
@@ -161,7 +158,7 @@ func TestReadFS_Open_Read(t *testing.T) {
{
name: "mask(os.DirFS) ZeroIno",
fs: func(tmpDir string) sys.FS {
return Adapt(&MaskOsFS{Fs: os.DirFS(tmpDir), ZeroIno: true})
return &AdaptFS{FS: &MaskOsFS{Fs: os.DirFS(tmpDir), ZeroIno: true}}
},
expectFileIno: false,
expectDirIno: false,
@@ -178,7 +175,7 @@ func TestReadFS_Open_Read(t *testing.T) {
tmpDir := t.TempDir()
require.NoError(t, fstest.WriteTestFiles(tmpDir))
testOpen_Read(t, NewReadFS(tc.fs(tmpDir)), tc.expectFileIno, tc.expectDirIno)
testOpen_Read(t, &ReadFS{FS: tc.fs(tmpDir)}, tc.expectFileIno, tc.expectDirIno)
})
}
}
@@ -187,8 +184,8 @@ func TestReadFS_Stat(t *testing.T) {
tmpDir := t.TempDir()
require.NoError(t, fstest.WriteTestFiles(tmpDir))
writeable := NewDirFS(tmpDir)
testFS := NewReadFS(writeable)
writeable := DirFS(tmpDir)
testFS := &ReadFS{FS: writeable}
testStat(t, testFS)
}
@@ -196,7 +193,7 @@ func TestReadFS_Readlink(t *testing.T) {
tmpDir := t.TempDir()
require.NoError(t, fstest.WriteTestFiles(tmpDir))
writeable := NewDirFS(tmpDir)
testFS := NewReadFS(writeable)
writeable := DirFS(tmpDir)
testFS := &ReadFS{FS: writeable}
testReadlink(t, testFS, writeable)
}
+1 -1
View File
@@ -70,7 +70,7 @@ func testOpen_O_RDWR(t *testing.T, tmpDir string, testFS experimentalsys.FS) {
t.Run("O_TRUNC", func(t *testing.T) {
tmpDir := t.TempDir()
testFS := NewDirFS(tmpDir)
testFS := DirFS(tmpDir)
name := "truncate"
realPath := path.Join(tmpDir, name)
+4 -4
View File
@@ -112,7 +112,7 @@ func TestModuleInstance_Close(t *testing.T) {
}
t.Run("calls Context.Close()", func(t *testing.T) {
testFS := sysfs.Adapt(testfs.FS{"foo": &testfs.File{}})
testFS := &sysfs.AdaptFS{FS: testfs.FS{"foo": &testfs.File{}}}
sysCtx := internalsys.DefaultContext(testFS)
fsCtx := sysCtx.FS()
@@ -147,7 +147,7 @@ func TestModuleInstance_Close(t *testing.T) {
t.Run("error closing", func(t *testing.T) {
// Right now, the only way to err closing the sys context is if a File.Close erred.
testFS := sysfs.Adapt(testfs.FS{"foo": &testfs.File{CloseErr: errors.New("error closing")}})
testFS := &sysfs.AdaptFS{FS: testfs.FS{"foo": &testfs.File{CloseErr: errors.New("error closing")}}}
sysCtx := internalsys.DefaultContext(testFS)
fsCtx := sysCtx.FS()
@@ -217,7 +217,7 @@ func TestModuleInstance_CallDynamic(t *testing.T) {
}
t.Run("calls Context.Close()", func(t *testing.T) {
testFS := sysfs.Adapt(testfs.FS{"foo": &testfs.File{}})
testFS := &sysfs.AdaptFS{FS: testfs.FS{"foo": &testfs.File{}}}
sysCtx := internalsys.DefaultContext(testFS)
fsCtx := sysCtx.FS()
@@ -245,7 +245,7 @@ func TestModuleInstance_CallDynamic(t *testing.T) {
t.Run("error closing", func(t *testing.T) {
// Right now, the only way to err closing the sys context is if a File.Close erred.
testFS := sysfs.Adapt(testfs.FS{"foo": &testfs.File{CloseErr: errors.New("error closing")}})
testFS := &sysfs.AdaptFS{FS: testfs.FS{"foo": &testfs.File{CloseErr: errors.New("error closing")}}}
sysCtx := internalsys.DefaultContext(testFS)
fsCtx := sysCtx.FS()