summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/sysfs/dirfs.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/sysfs/dirfs.go')
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/sysfs/dirfs.go99
1 files changed, 99 insertions, 0 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/dirfs.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/dirfs.go
new file mode 100644
index 000000000..04384038f
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/dirfs.go
@@ -0,0 +1,99 @@
+package sysfs
+
+import (
+ "io/fs"
+ "os"
+
+ experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
+ "github.com/tetratelabs/wazero/internal/platform"
+ "github.com/tetratelabs/wazero/sys"
+)
+
+func DirFS(dir string) experimentalsys.FS {
+ return &dirFS{
+ dir: dir,
+ cleanedDir: ensureTrailingPathSeparator(dir),
+ }
+}
+
+func ensureTrailingPathSeparator(dir string) string {
+ if !os.IsPathSeparator(dir[len(dir)-1]) {
+ return dir + string(os.PathSeparator)
+ }
+ 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.
+ cleanedDir string
+}
+
+// String implements fmt.Stringer
+func (d *dirFS) String() string {
+ return d.dir
+}
+
+// OpenFile implements the same method as documented on sys.FS
+func (d *dirFS) OpenFile(path string, flag experimentalsys.Oflag, perm fs.FileMode) (experimentalsys.File, experimentalsys.Errno) {
+ return OpenOSFile(d.join(path), flag, perm)
+}
+
+// Lstat implements the same method as documented on sys.FS
+func (d *dirFS) Lstat(path string) (sys.Stat_t, experimentalsys.Errno) {
+ return lstat(d.join(path))
+}
+
+// Stat implements the same method as documented on sys.FS
+func (d *dirFS) Stat(path string) (sys.Stat_t, experimentalsys.Errno) {
+ return stat(d.join(path))
+}
+
+// Mkdir implements the same method as documented on sys.FS
+func (d *dirFS) Mkdir(path string, perm fs.FileMode) (errno experimentalsys.Errno) {
+ err := os.Mkdir(d.join(path), perm)
+ if errno = experimentalsys.UnwrapOSError(err); errno == experimentalsys.ENOTDIR {
+ errno = experimentalsys.ENOENT
+ }
+ return
+}
+
+// Readlink implements the same method as documented on sys.FS
+func (d *dirFS) Readlink(path string) (string, experimentalsys.Errno) {
+ // Note: do not use syscall.Readlink as that causes race on Windows.
+ // In any case, syscall.Readlink does almost the same logic as os.Readlink.
+ dst, err := os.Readlink(d.join(path))
+ if err != nil {
+ return "", experimentalsys.UnwrapOSError(err)
+ }
+ return platform.ToPosixPath(dst), 0
+}
+
+// Rmdir implements the same method as documented on sys.FS
+func (d *dirFS) Rmdir(path string) experimentalsys.Errno {
+ return rmdir(d.join(path))
+}
+
+// Utimens implements the same method as documented on sys.FS
+func (d *dirFS) Utimens(path string, atim, mtim int64) experimentalsys.Errno {
+ return utimens(d.join(path), atim, mtim)
+}
+
+func (d *dirFS) join(path string) string {
+ switch path {
+ case "", ".", "/":
+ if d.cleanedDir == "/" {
+ return "/"
+ }
+ // cleanedDir includes an unnecessary delimiter for the root path.
+ return d.cleanedDir[:len(d.cleanedDir)-1]
+ }
+ // TODO: Enforce similar to safefilepath.FromFS(path), but be careful as
+ // relative path inputs are allowed. e.g. dir or path == ../
+ return d.cleanedDir + path
+}