1package sys
2
3import (
4 "io/fs"
5
6 "github.com/tetratelabs/wazero/sys"
7)
8
9// FS is a writeable fs.FS bridge backed by syscall functions needed for ABI
10// including WASI.
11//
12// Implementations should embed UnimplementedFS for forward compatibility. Any
13// unsupported method or parameter should return ENO
14//
15// # Errors
16//
17// All methods that can return an error return a Errno, which is zero
18// on success.
19//
20// Restricting to Errno matches current WebAssembly host functions,
21// which are constrained to well-known error codes. For example, WASI maps syscall
22// errors to u32 numeric values.
23//
24// # Notes
25//
26// A writable filesystem abstraction is not yet implemented as of Go 1.20. See
27// https://github.com/golang/go/issues/45757
28type FS interface {
29 // OpenFile opens a file. It should be closed via Close on File.
30 //
31 // # Errors
32 //
33 // A zero Errno is success. The below are expected otherwise:
34 // - ENOSYS: the implementation does not support this function.
35 // - EINVAL: `path` or `flag` is invalid.
36 // - EISDIR: the path was a directory, but flag included O_RDWR or
37 // O_WRONLY
38 // - ENOENT: `path` doesn't exist and `flag` doesn't contain O_CREAT.
39 //
40 // # Constraints on the returned file
41 //
42 // Implementations that can read flags should enforce them regardless of
43 // the type returned. For example, while os.File implements io.Writer,
44 // attempts to write to a directory or a file opened with O_RDONLY fail
45 // with a EBADF.
46 //
47 // Some implementations choose whether to enforce read-only opens, namely
48 // fs.FS. While fs.FS is supported (Adapt), wazero cannot runtime enforce
49 // open flags. Instead, we encourage good behavior and test our built-in
50 // implementations.
51 //
52 // # Notes
53 //
54 // - This is like os.OpenFile, except the path is relative to this file
55 // system, and Errno is returned instead of os.PathError.
56 // - Implications of permissions when O_CREAT are described in Chmod notes.
57 // - This is like `open` in POSIX. See
58 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html
59 OpenFile(path string, flag Oflag, perm fs.FileMode) (File, Errno)
60
61 // Lstat gets file status without following symbolic links.
62 //
63 // # Errors
64 //
65 // A zero Errno is success. The below are expected otherwise:
66 // - ENOSYS: the implementation does not support this function.
67 // - ENOENT: `path` doesn't exist.
68 //
69 // # Notes
70 //
71 // - This is like syscall.Lstat, except the `path` is relative to this
72 // file system.
73 // - This is like `lstat` in POSIX. See
74 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat.html
75 // - An fs.FileInfo backed implementation sets atim, mtim and ctim to the
76 // same value.
77 // - When the path is a symbolic link, the stat returned is for the link,
78 // not the file it refers to.
79 Lstat(path string) (sys.Stat_t, Errno)
80
81 // Stat gets file status.
82 //
83 // # Errors
84 //
85 // A zero Errno is success. The below are expected otherwise:
86 // - ENOSYS: the implementation does not support this function.
87 // - ENOENT: `path` doesn't exist.
88 //
89 // # Notes
90 //
91 // - This is like syscall.Stat, except the `path` is relative to this
92 // file system.
93 // - This is like `stat` in POSIX. See
94 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html
95 // - An fs.FileInfo backed implementation sets atim, mtim and ctim to the
96 // same value.
97 // - When the path is a symbolic link, the stat returned is for the file
98 // it refers to.
99 Stat(path string) (sys.Stat_t, Errno)
100
101 // Mkdir makes a directory.
102 //
103 // # Errors
104 //
105 // A zero Errno is success. The below are expected otherwise:
106 // - ENOSYS: the implementation does not support this function.
107 // - EINVAL: `path` is invalid.
108 // - EEXIST: `path` exists and is a directory.
109 // - ENOTDIR: `path` exists and is a file.
110 //
111 // # Notes
112 //
113 // - This is like syscall.Mkdir, except the `path` is relative to this
114 // file system.
115 // - This is like `mkdir` in POSIX. See
116 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html
117 // - Implications of permissions are described in Chmod notes.
118 Mkdir(path string, perm fs.FileMode) Errno
119
120 // Chmod changes the mode of the file.
121 //
122 // # Errors
123 //
124 // A zero Errno is success. The below are expected otherwise:
125 // - ENOSYS: the implementation does not support this function.
126 // - EINVAL: `path` is invalid.
127 // - ENOENT: `path` does not exist.
128 //
129 // # Notes
130 //
131 // - This is like syscall.Chmod, except the `path` is relative to this
132 // file system.
133 // - This is like `chmod` in POSIX. See
134 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/chmod.html
135 // - Windows ignores the execute bit, and any permissions come back as
136 // group and world. For example, chmod of 0400 reads back as 0444, and
137 // 0700 0666. Also, permissions on directories aren't supported at all.
138 Chmod(path string, perm fs.FileMode) Errno
139
140 // Rename renames file or directory.
141 //
142 // # Errors
143 //
144 // A zero Errno is success. The below are expected otherwise:
145 // - ENOSYS: the implementation does not support this function.
146 // - EINVAL: `from` or `to` is invalid.
147 // - ENOENT: `from` or `to` don't exist.
148 // - ENOTDIR: `from` is a directory and `to` exists as a file.
149 // - EISDIR: `from` is a file and `to` exists as a directory.
150 // - ENOTEMPTY: `both from` and `to` are existing directory, but
151 // `to` is not empty.
152 //
153 // # Notes
154 //
155 // - This is like syscall.Rename, except the paths are relative to this
156 // file system.
157 // - This is like `rename` in POSIX. See
158 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html
159 // - Windows doesn't let you overwrite an existing directory.
160 Rename(from, to string) Errno
161
162 // Rmdir removes a directory.
163 //
164 // # Errors
165 //
166 // A zero Errno is success. The below are expected otherwise:
167 // - ENOSYS: the implementation does not support this function.
168 // - EINVAL: `path` is invalid.
169 // - ENOENT: `path` doesn't exist.
170 // - ENOTDIR: `path` exists, but isn't a directory.
171 // - ENOTEMPTY: `path` exists, but isn't empty.
172 //
173 // # Notes
174 //
175 // - This is like syscall.Rmdir, except the `path` is relative to this
176 // file system.
177 // - This is like `rmdir` in POSIX. See
178 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html
179 // - As of Go 1.19, Windows maps ENOTDIR to ENOENT.
180 Rmdir(path string) Errno
181
182 // Unlink removes a directory entry.
183 //
184 // # Errors
185 //
186 // A zero Errno is success. The below are expected otherwise:
187 // - ENOSYS: the implementation does not support this function.
188 // - EINVAL: `path` is invalid.
189 // - ENOENT: `path` doesn't exist.
190 // - EISDIR: `path` exists, but is a directory.
191 //
192 // # Notes
193 //
194 // - This is like syscall.Unlink, except the `path` is relative to this
195 // file system.
196 // - This is like `unlink` in POSIX. See
197 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html
198 // - On Windows, syscall.Unlink doesn't delete symlink to directory unlike other platforms. Implementations might
199 // want to combine syscall.RemoveDirectory with syscall.Unlink in order to delete such links on Windows.
200 // See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya
201 Unlink(path string) Errno
202
203 // Link creates a "hard" link from oldPath to newPath, in contrast to a
204 // soft link (via Symlink).
205 //
206 // # Errors
207 //
208 // A zero Errno is success. The below are expected otherwise:
209 // - ENOSYS: the implementation does not support this function.
210 // - EPERM: `oldPath` is invalid.
211 // - ENOENT: `oldPath` doesn't exist.
212 // - EISDIR: `newPath` exists, but is a directory.
213 //
214 // # Notes
215 //
216 // - This is like syscall.Link, except the `oldPath` is relative to this
217 // file system.
218 // - This is like `link` in POSIX. See
219 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/link.html
220 Link(oldPath, newPath string) Errno
221
222 // Symlink creates a "soft" link from oldPath to newPath, in contrast to a
223 // hard link (via Link).
224 //
225 // # Errors
226 //
227 // A zero Errno is success. The below are expected otherwise:
228 // - ENOSYS: the implementation does not support this function.
229 // - EPERM: `oldPath` or `newPath` is invalid.
230 // - EEXIST: `newPath` exists.
231 //
232 // # Notes
233 //
234 // - This is like syscall.Symlink, except the `oldPath` is relative to
235 // this file system.
236 // - This is like `symlink` in POSIX. See
237 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlink.html
238 // - Only `newPath` is relative to this file system and `oldPath` is kept
239 // as-is. That is because the link is only resolved relative to the
240 // directory when dereferencing it (e.g. ReadLink).
241 // See https://github.com/bytecodealliance/cap-std/blob/v1.0.4/cap-std/src/fs/dir.rs#L404-L409
242 // for how others implement this.
243 // - Symlinks in Windows requires `SeCreateSymbolicLinkPrivilege`.
244 // Otherwise, EPERM results.
245 // See https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
246 Symlink(oldPath, linkName string) Errno
247
248 // Readlink reads the contents of a symbolic link.
249 //
250 // # Errors
251 //
252 // A zero Errno is success. The below are expected otherwise:
253 // - ENOSYS: the implementation does not support this function.
254 // - EINVAL: `path` is invalid.
255 //
256 // # Notes
257 //
258 // - This is like syscall.Readlink, except the path is relative to this
259 // filesystem.
260 // - This is like `readlink` in POSIX. See
261 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html
262 // - On Windows, the path separator is different from other platforms,
263 // but to provide consistent results to Wasm, this normalizes to a "/"
264 // separator.
265 Readlink(path string) (string, Errno)
266
267 // Utimens set file access and modification times on a path relative to
268 // this file system, at nanosecond precision.
269 //
270 // # Parameters
271 //
272 // If the path is a symbolic link, the target of expanding that link is
273 // updated.
274 //
275 // The `atim` and `mtim` parameters refer to access and modification time
276 // stamps as defined in sys.Stat_t. To retain one or the other, substitute
277 // it with the pseudo-timestamp UTIME_OMIT.
278 //
279 // # Errors
280 //
281 // A zero Errno is success. The below are expected otherwise:
282 // - ENOSYS: the implementation does not support this function.
283 // - EINVAL: `path` is invalid.
284 // - EEXIST: `path` exists and is a directory.
285 // - ENOTDIR: `path` exists and is a file.
286 //
287 // # Notes
288 //
289 // - This is like syscall.UtimesNano and `utimensat` with `AT_FDCWD` in
290 // POSIX. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html
291 Utimens(path string, atim, mtim int64) Errno
292}