summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/fsconfig.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/fsconfig.go')
-rw-r--r--vendor/github.com/tetratelabs/wazero/fsconfig.go213
1 files changed, 213 insertions, 0 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/fsconfig.go b/vendor/github.com/tetratelabs/wazero/fsconfig.go
new file mode 100644
index 000000000..c21b6e80b
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/fsconfig.go
@@ -0,0 +1,213 @@
+package wazero
+
+import (
+ "io/fs"
+
+ experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
+ "github.com/tetratelabs/wazero/internal/sys"
+ "github.com/tetratelabs/wazero/internal/sysfs"
+)
+
+// FSConfig configures filesystem paths the embedding host allows the wasm
+// guest to access. Unconfigured paths are not allowed, so functions like
+// `path_open` result in unsupported errors (e.g. syscall.ENOSYS).
+//
+// # Guest Path
+//
+// `guestPath` is the name of the path the guest should use a filesystem for, or
+// empty for any files.
+//
+// All `guestPath` paths are normalized, specifically removing any leading or
+// trailing slashes. This means "/", "./" or "." all coerce to empty "".
+//
+// Multiple `guestPath` values can be configured, but the last longest match
+// wins. For example, if "tmp", then "" were added, a request to open
+// "tmp/foo.txt" use the filesystem associated with "tmp" even though a wider
+// path, "" (all files), was added later.
+//
+// A `guestPath` of "." coerces to the empty string "" because the current
+// directory is handled by the guest. In other words, the guest resolves ites
+// current directory prior to requesting files.
+//
+// More notes on `guestPath`
+// - Working directories are typically tracked in wasm, though possible some
+// relative paths are requested. For example, TinyGo may attempt to resolve
+// a path "../.." in unit tests.
+// - Zig uses the first path name it sees as the initial working directory of
+// the process.
+//
+// # Scope
+//
+// Configuration here is module instance scoped. This means you can use the
+// same configuration for multiple calls to Runtime.InstantiateModule. Each
+// module will have a different file descriptor table. Any errors accessing
+// resources allowed here are deferred to instantiation time of each module.
+//
+// Any host resources present at the time of configuration, but deleted before
+// Runtime.InstantiateModule will trap/panic when the guest wasm initializes or
+// calls functions like `fd_read`.
+//
+// # Windows
+//
+// While wazero supports Windows as a platform, all known compilers use POSIX
+// conventions at runtime. For example, even when running on Windows, paths
+// used by wasm are separated by forward slash (/), not backslash (\).
+//
+// # Notes
+//
+// - This is an interface for decoupling, not third-party implementations.
+// All implementations are in wazero.
+// - FSConfig is immutable. Each WithXXX function returns a new instance
+// including the corresponding change.
+// - RATIONALE.md includes design background and relationship to WebAssembly
+// System Interfaces (WASI).
+type FSConfig interface {
+ // WithDirMount assigns a directory at `dir` to any paths beginning at
+ // `guestPath`.
+ //
+ // For example, `dirPath` as / (or c:\ in Windows), makes the entire host
+ // volume writeable to the path on the guest. The `guestPath` is always a
+ // POSIX style path, slash (/) delimited, even if run on Windows.
+ //
+ // If the same `guestPath` was assigned before, this overrides its value,
+ // retaining the original precedence. See the documentation of FSConfig for
+ // more details on `guestPath`.
+ //
+ // # Isolation
+ //
+ // The guest will have full access to this directory including escaping it
+ // via relative path lookups like "../../". Full access includes operations
+ // such as creating or deleting files, limited to any host level access
+ // controls.
+ //
+ // # os.DirFS
+ //
+ // This configuration optimizes for WASI compatibility which is sometimes
+ // at odds with the behavior of os.DirFS. Hence, this will not behave
+ // exactly the same as os.DirFS. See /RATIONALE.md for more.
+ WithDirMount(dir, guestPath string) FSConfig
+
+ // WithReadOnlyDirMount assigns a directory at `dir` to any paths
+ // beginning at `guestPath`.
+ //
+ // This is the same as WithDirMount except only read operations are
+ // permitted. However, escaping the directory via relative path lookups
+ // like "../../" is still allowed.
+ WithReadOnlyDirMount(dir, guestPath string) FSConfig
+
+ // WithFSMount assigns a fs.FS file system for any paths beginning at
+ // `guestPath`.
+ //
+ // If the same `guestPath` was assigned before, this overrides its value,
+ // retaining the original precedence. See the documentation of FSConfig for
+ // more details on `guestPath`.
+ //
+ // # Isolation
+ //
+ // fs.FS does not restrict the ability to overwrite returned files via
+ // io.Writer. Moreover, os.DirFS documentation includes important notes
+ // about isolation, which also applies to fs.Sub. As of Go 1.19, the
+ // built-in file-systems are not jailed (chroot). See
+ // https://github.com/golang/go/issues/42322
+ //
+ // # os.DirFS
+ //
+ // Due to limited control and functionality available in os.DirFS, we
+ // advise using WithDirMount instead. There will be behavior differences
+ // between os.DirFS and WithDirMount, as the latter biases towards what's
+ // expected from WASI implementations.
+ //
+ // # Custom fs.FileInfo
+ //
+ // The underlying implementation supports data not usually in fs.FileInfo
+ // when `info.Sys` returns *sys.Stat_t. For example, a custom fs.FS can use
+ // this approach to generate or mask sys.Inode data. Such a filesystem
+ // needs to decorate any functions that can return fs.FileInfo:
+ //
+ // - `Stat` as defined on `fs.File` (always)
+ // - `Readdir` as defined on `os.File` (if defined)
+ //
+ // See sys.NewStat_t for examples.
+ WithFSMount(fs fs.FS, guestPath string) FSConfig
+}
+
+type fsConfig struct {
+ // fs are the currently configured filesystems.
+ fs []experimentalsys.FS
+ // guestPaths are the user-supplied names of the filesystems, retained for
+ // error messages and fmt.Stringer.
+ guestPaths []string
+ // guestPathToFS are the normalized paths to the currently configured
+ // filesystems, used for de-duplicating.
+ guestPathToFS map[string]int
+}
+
+// NewFSConfig returns a FSConfig that can be used for configuring module instantiation.
+func NewFSConfig() FSConfig {
+ return &fsConfig{guestPathToFS: map[string]int{}}
+}
+
+// clone makes a deep copy of this module config.
+func (c *fsConfig) clone() *fsConfig {
+ ret := *c // copy except slice and maps which share a ref
+ ret.fs = make([]experimentalsys.FS, 0, len(c.fs))
+ ret.fs = append(ret.fs, c.fs...)
+ ret.guestPaths = make([]string, 0, len(c.guestPaths))
+ ret.guestPaths = append(ret.guestPaths, c.guestPaths...)
+ ret.guestPathToFS = make(map[string]int, len(c.guestPathToFS))
+ for key, value := range c.guestPathToFS {
+ ret.guestPathToFS[key] = value
+ }
+ return &ret
+}
+
+// WithDirMount implements FSConfig.WithDirMount
+func (c *fsConfig) WithDirMount(dir, guestPath string) FSConfig {
+ return c.WithSysFSMount(sysfs.DirFS(dir), guestPath)
+}
+
+// WithReadOnlyDirMount implements FSConfig.WithReadOnlyDirMount
+func (c *fsConfig) WithReadOnlyDirMount(dir, guestPath string) FSConfig {
+ return c.WithSysFSMount(&sysfs.ReadFS{FS: sysfs.DirFS(dir)}, guestPath)
+}
+
+// WithFSMount implements FSConfig.WithFSMount
+func (c *fsConfig) WithFSMount(fs fs.FS, guestPath string) FSConfig {
+ var adapted experimentalsys.FS
+ if fs != nil {
+ adapted = &sysfs.AdaptFS{FS: fs}
+ }
+ return c.WithSysFSMount(adapted, guestPath)
+}
+
+// WithSysFSMount implements sysfs.FSConfig
+func (c *fsConfig) WithSysFSMount(fs experimentalsys.FS, guestPath string) FSConfig {
+ if _, ok := fs.(experimentalsys.UnimplementedFS); ok {
+ return c // don't add fake paths.
+ }
+ cleaned := sys.StripPrefixesAndTrailingSlash(guestPath)
+ ret := c.clone()
+ if i, ok := ret.guestPathToFS[cleaned]; ok {
+ ret.fs[i] = fs
+ ret.guestPaths[i] = guestPath
+ } else if fs != nil {
+ ret.guestPathToFS[cleaned] = len(ret.fs)
+ ret.fs = append(ret.fs, fs)
+ ret.guestPaths = append(ret.guestPaths, guestPath)
+ }
+ return ret
+}
+
+// preopens returns the possible nil index-correlated preopened filesystems
+// with guest paths.
+func (c *fsConfig) preopens() ([]experimentalsys.FS, []string) {
+ preopenCount := len(c.fs)
+ if preopenCount == 0 {
+ return nil, nil
+ }
+ fs := make([]experimentalsys.FS, len(c.fs))
+ copy(fs, c.fs)
+ guestPaths := make([]string, len(c.guestPaths))
+ copy(guestPaths, c.guestPaths)
+ return fs, guestPaths
+}