1package sysfs
2
3import (
4 "fmt"
5 "io/fs"
6 "path"
7
8 experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
9 "github.com/tetratelabs/wazero/sys"
10)
11
12type AdaptFS struct {
13 FS fs.FS
14}
15
16// String implements fmt.Stringer
17func (a *AdaptFS) String() string {
18 return fmt.Sprintf("%v", a.FS)
19}
20
21// OpenFile implements the same method as documented on sys.FS
22func (a *AdaptFS) OpenFile(path string, flag experimentalsys.Oflag, perm fs.FileMode) (experimentalsys.File, experimentalsys.Errno) {
23 return OpenFSFile(a.FS, cleanPath(path), flag, perm)
24}
25
26// Lstat implements the same method as documented on sys.FS
27func (a *AdaptFS) Lstat(path string) (sys.Stat_t, experimentalsys.Errno) {
28 // At this time, we make the assumption sys.FS instances do not support
29 // symbolic links, therefore Lstat is the same as Stat. This is obviously
30 // not true, but until FS.FS has a solid story for how to handle symlinks,
31 // we are better off not making a decision that would be difficult to
32 // revert later on.
33 //
34 // For further discussions on the topic, see:
35 // https://github.com/golang/go/issues/49580
36 return a.Stat(path)
37}
38
39// Stat implements the same method as documented on sys.FS
40func (a *AdaptFS) Stat(path string) (sys.Stat_t, experimentalsys.Errno) {
41 f, errno := a.OpenFile(path, experimentalsys.O_RDONLY, 0)
42 if errno != 0 {
43 return sys.Stat_t{}, errno
44 }
45 defer f.Close()
46 return f.Stat()
47}
48
49// Readlink implements the same method as documented on sys.FS
50func (a *AdaptFS) Readlink(string) (string, experimentalsys.Errno) {
51 return "", experimentalsys.ENOSYS
52}
53
54// Mkdir implements the same method as documented on sys.FS
55func (a *AdaptFS) Mkdir(string, fs.FileMode) experimentalsys.Errno {
56 return experimentalsys.ENOSYS
57}
58
59// Chmod implements the same method as documented on sys.FS
60func (a *AdaptFS) Chmod(string, fs.FileMode) experimentalsys.Errno {
61 return experimentalsys.ENOSYS
62}
63
64// Rename implements the same method as documented on sys.FS
65func (a *AdaptFS) Rename(string, string) experimentalsys.Errno {
66 return experimentalsys.ENOSYS
67}
68
69// Rmdir implements the same method as documented on sys.FS
70func (a *AdaptFS) Rmdir(string) experimentalsys.Errno {
71 return experimentalsys.ENOSYS
72}
73
74// Link implements the same method as documented on sys.FS
75func (a *AdaptFS) Link(string, string) experimentalsys.Errno {
76 return experimentalsys.ENOSYS
77}
78
79// Symlink implements the same method as documented on sys.FS
80func (a *AdaptFS) Symlink(string, string) experimentalsys.Errno {
81 return experimentalsys.ENOSYS
82}
83
84// Unlink implements the same method as documented on sys.FS
85func (a *AdaptFS) Unlink(string) experimentalsys.Errno {
86 return experimentalsys.ENOSYS
87}
88
89// Utimens implements the same method as documented on sys.FS
90func (a *AdaptFS) Utimens(string, int64, int64) experimentalsys.Errno {
91 return experimentalsys.ENOSYS
92}
93
94func cleanPath(name string) string {
95 if len(name) == 0 {
96 return name
97 }
98 // fs.ValidFile cannot be rooted (start with '/')
99 cleaned := name
100 if name[0] == '/' {
101 cleaned = name[1:]
102 }
103 cleaned = path.Clean(cleaned) // e.g. "sub/." -> "sub"
104 return cleaned
105}