forked from karelbilek/wazero-fs-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dirfs.go
130 lines (110 loc) · 4.05 KB
/
dirfs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package sysfs
import (
"io/fs"
"os"
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
"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
}
// Chmod implements the same method as documented on sys.FS
func (d *dirFS) Chmod(path string, perm fs.FileMode) experimentalsys.Errno {
err := os.Chmod(d.join(path), perm)
return experimentalsys.UnwrapOSError(err)
}
// Rename implements the same method as documented on sys.FS
func (d *dirFS) Rename(from, to string) experimentalsys.Errno {
from, to = d.join(from), d.join(to)
return rename(from, to)
}
// 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 toPosixPath(dst), 0
}
// Link implements the same method as documented on sys.FS
func (d *dirFS) Link(oldName, newName string) experimentalsys.Errno {
err := os.Link(d.join(oldName), d.join(newName))
return experimentalsys.UnwrapOSError(err)
}
// Rmdir implements the same method as documented on sys.FS
func (d *dirFS) Rmdir(path string) experimentalsys.Errno {
return rmdir(d.join(path))
}
// Unlink implements the same method as documented on sys.FS
func (d *dirFS) Unlink(path string) (err experimentalsys.Errno) {
return unlink(d.join(path))
}
// Symlink implements the same method as documented on sys.FS
func (d *dirFS) Symlink(oldName, link string) experimentalsys.Errno {
// Note: do not resolve `oldName` relative to this dirFS. The link result is always resolved
// when dereference the `link` on its usage (e.g. readlink, read, etc).
// https://github.com/bytecodealliance/cap-std/blob/v1.0.4/cap-std/src/fs/dir.rs#L404-L409
err := os.Symlink(oldName, d.join(link))
return experimentalsys.UnwrapOSError(err)
}
// 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
}