github.com/tetratelabs/wazero@v1.2.1/internal/fsapi/fs.go (about) 1 package fsapi 2 3 import ( 4 "io/fs" 5 "syscall" 6 ) 7 8 // FS is a writeable fs.FS bridge backed by syscall functions needed for ABI 9 // including WASI and runtime.GOOS=js. 10 // 11 // Implementations should embed UnimplementedFS for forward compatability. Any 12 // unsupported method or parameter should return syscall.ENO 13 // 14 // # Errors 15 // 16 // All methods that can return an error return a syscall.Errno, which is zero 17 // on success. 18 // 19 // Restricting to syscall.Errno matches current WebAssembly host functions, 20 // which are constrained to well-known error codes. For example, `GOOS=js` maps 21 // hard coded values and panics otherwise. More commonly, 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 28 type FS interface { 29 // String should return a human-readable format of the filesystem 30 // 31 // For example, if this filesystem is backed by the real directory 32 // "/tmp/wasm", the expected value is "/tmp/wasm". 33 // 34 // When the host filesystem isn't a real filesystem, substitute a symbolic, 35 // human-readable name. e.g. "virtual" 36 String() string 37 38 // OpenFile opens a file. It should be closed via Close on File. 39 // 40 // # Errors 41 // 42 // A zero syscall.Errno is success. The below are expected otherwise: 43 // - syscall.ENOSYS: the implementation does not support this function. 44 // - syscall.EINVAL: `path` or `flag` is invalid. 45 // - syscall.EISDIR: the path was a directory, but flag included 46 // syscall.O_RDWR or syscall.O_WRONLY 47 // - syscall.ENOENT: `path` doesn't exist and `flag` doesn't contain 48 // os.O_CREATE. 49 // 50 // # Constraints on the returned file 51 // 52 // Implementations that can read flags should enforce them regardless of 53 // the type returned. For example, while os.File implements io.Writer, 54 // attempts to write to a directory or a file opened with os.O_RDONLY fail 55 // with a syscall.EBADF. 56 // 57 // Some implementations choose whether to enforce read-only opens, namely 58 // fs.FS. While fs.FS is supported (Adapt), wazero cannot runtime enforce 59 // open flags. Instead, we encourage good behavior and test our built-in 60 // implementations. 61 // 62 // # Notes 63 // 64 // - This is like os.OpenFile, except the path is relative to this file 65 // system, and syscall.Errno is returned instead of os.PathError. 66 // - flag are the same as os.OpenFile, for example, os.O_CREATE. 67 // - Implications of permissions when os.O_CREATE are described in Chmod 68 // notes. 69 // - This is like `open` in POSIX. See 70 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html 71 OpenFile(path string, flag int, perm fs.FileMode) (File, syscall.Errno) 72 // ^^ TODO: Consider syscall.Open, though this implies defining and 73 // coercing flags and perms similar to what is done in os.OpenFile. 74 75 // Lstat gets file status without following symbolic links. 76 // 77 // # Errors 78 // 79 // A zero syscall.Errno is success. The below are expected otherwise: 80 // - syscall.ENOSYS: the implementation does not support this function. 81 // - syscall.ENOENT: `path` doesn't exist. 82 // 83 // # Notes 84 // 85 // - This is like syscall.Lstat, except the `path` is relative to this 86 // file system. 87 // - This is like `lstat` in POSIX. See 88 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat.html 89 // - An fs.FileInfo backed implementation sets atim, mtim and ctim to the 90 // same value. 91 // - When the path is a symbolic link, the stat returned is for the link, 92 // not the file it refers to. 93 Lstat(path string) (Stat_t, syscall.Errno) 94 95 // Stat gets file status. 96 // 97 // # Errors 98 // 99 // A zero syscall.Errno is success. The below are expected otherwise: 100 // - syscall.ENOSYS: the implementation does not support this function. 101 // - syscall.ENOENT: `path` doesn't exist. 102 // 103 // # Notes 104 // 105 // - This is like syscall.Stat, except the `path` is relative to this 106 // file system. 107 // - This is like `stat` in POSIX. See 108 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html 109 // - An fs.FileInfo backed implementation sets atim, mtim and ctim to the 110 // same value. 111 // - When the path is a symbolic link, the stat returned is for the file 112 // it refers to. 113 Stat(path string) (Stat_t, syscall.Errno) 114 115 // Mkdir makes a directory. 116 // 117 // # Errors 118 // 119 // A zero syscall.Errno is success. The below are expected otherwise: 120 // - syscall.ENOSYS: the implementation does not support this function. 121 // - syscall.EINVAL: `path` is invalid. 122 // - syscall.EEXIST: `path` exists and is a directory. 123 // - syscall.ENOTDIR: `path` exists and is a file. 124 // 125 // # Notes 126 // 127 // - This is like syscall.Mkdir, except the `path` is relative to this 128 // file system. 129 // - This is like `mkdir` in POSIX. See 130 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html 131 // - Implications of permissions are described in Chmod notes. 132 Mkdir(path string, perm fs.FileMode) syscall.Errno 133 // ^^ TODO: Consider syscall.Mkdir, though this implies defining and 134 // coercing flags and perms similar to what is done in os.Mkdir. 135 136 // Chmod changes the mode of the file. 137 // 138 // # Errors 139 // 140 // A zero syscall.Errno is success. The below are expected otherwise: 141 // - syscall.ENOSYS: the implementation does not support this function. 142 // - syscall.EINVAL: `path` is invalid. 143 // - syscall.ENOENT: `path` does not exist. 144 // 145 // # Notes 146 // 147 // - This is like syscall.Chmod, except the `path` is relative to this 148 // file system. 149 // - This is like `chmod` in POSIX. See 150 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/chmod.html 151 // - Windows ignores the execute bit, and any permissions come back as 152 // group and world. For example, chmod of 0400 reads back as 0444, and 153 // 0700 0666. Also, permissions on directories aren't supported at all. 154 Chmod(path string, perm fs.FileMode) syscall.Errno 155 156 // Chown changes the owner and group of a file. 157 // 158 // # Errors 159 // 160 // A zero syscall.Errno is success. The below are expected otherwise: 161 // - syscall.ENOSYS: the implementation does not support this function. 162 // - syscall.EINVAL: `path` is invalid. 163 // - syscall.ENOENT: `path` does not exist. 164 // 165 // # Notes 166 // 167 // - This is like syscall.Chown, except the `path` is relative to this 168 // file system. 169 // - This is like `chown` in POSIX. See 170 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html 171 // - This always returns syscall.ENOSYS on windows. 172 Chown(path string, uid, gid int) syscall.Errno 173 174 // Lchown changes the owner and group of a symbolic link. 175 // 176 // # Errors 177 // 178 // A zero syscall.Errno is success. The below are expected otherwise: 179 // - syscall.ENOSYS: the implementation does not support this function. 180 // - syscall.EINVAL: `path` is invalid. 181 // - syscall.ENOENT: `path` does not exist. 182 // 183 // # Notes 184 // 185 // - This is like syscall.Lchown, except the `path` is relative to this 186 // file system. 187 // - This is like `lchown` in POSIX. See 188 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/lchown.html 189 // - Windows will always return syscall.ENOSYS 190 Lchown(path string, uid, gid int) syscall.Errno 191 192 // Rename renames file or directory. 193 // 194 // # Errors 195 // 196 // A zero syscall.Errno is success. The below are expected otherwise: 197 // - syscall.ENOSYS: the implementation does not support this function. 198 // - syscall.EINVAL: `from` or `to` is invalid. 199 // - syscall.ENOENT: `from` or `to` don't exist. 200 // - syscall.ENOTDIR: `from` is a directory and `to` exists as a file. 201 // - syscall.EISDIR: `from` is a file and `to` exists as a directory. 202 // - syscall.ENOTEMPTY: `both from` and `to` are existing directory, but 203 // `to` is not empty. 204 // 205 // # Notes 206 // 207 // - This is like syscall.Rename, except the paths are relative to this 208 // file system. 209 // - This is like `rename` in POSIX. See 210 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html 211 // - Windows doesn't let you overwrite an existing directory. 212 Rename(from, to string) syscall.Errno 213 214 // Rmdir removes a directory. 215 // 216 // # Errors 217 // 218 // A zero syscall.Errno is success. The below are expected otherwise: 219 // - syscall.ENOSYS: the implementation does not support this function. 220 // - syscall.EINVAL: `path` is invalid. 221 // - syscall.ENOENT: `path` doesn't exist. 222 // - syscall.ENOTDIR: `path` exists, but isn't a directory. 223 // - syscall.ENOTEMPTY: `path` exists, but isn't empty. 224 // 225 // # Notes 226 // 227 // - This is like syscall.Rmdir, except the `path` is relative to this 228 // file system. 229 // - This is like `rmdir` in POSIX. See 230 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html 231 // - As of Go 1.19, Windows maps syscall.ENOTDIR to syscall.ENOENT. 232 Rmdir(path string) syscall.Errno 233 234 // Unlink removes a directory entry. 235 // 236 // # Errors 237 // 238 // A zero syscall.Errno is success. The below are expected otherwise: 239 // - syscall.ENOSYS: the implementation does not support this function. 240 // - syscall.EINVAL: `path` is invalid. 241 // - syscall.ENOENT: `path` doesn't exist. 242 // - syscall.EISDIR: `path` exists, but is a directory. 243 // 244 // # Notes 245 // 246 // - This is like syscall.Unlink, except the `path` is relative to this 247 // file system. 248 // - This is like `unlink` in POSIX. See 249 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html 250 // - On Windows, syscall.Unlink doesn't delete symlink to directory unlike other platforms. Implementations might 251 // want to combine syscall.RemoveDirectory with syscall.Unlink in order to delete such links on Windows. 252 // See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya 253 Unlink(path string) syscall.Errno 254 255 // Link creates a "hard" link from oldPath to newPath, in contrast to a 256 // soft link (via Symlink). 257 // 258 // # Errors 259 // 260 // A zero syscall.Errno is success. The below are expected otherwise: 261 // - syscall.ENOSYS: the implementation does not support this function. 262 // - syscall.EPERM: `oldPath` is invalid. 263 // - syscall.ENOENT: `oldPath` doesn't exist. 264 // - syscall.EISDIR: `newPath` exists, but is a directory. 265 // 266 // # Notes 267 // 268 // - This is like syscall.Link, except the `oldPath` is relative to this 269 // file system. 270 // - This is like `link` in POSIX. See 271 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/link.html 272 Link(oldPath, newPath string) syscall.Errno 273 274 // Symlink creates a "soft" link from oldPath to newPath, in contrast to a 275 // hard link (via Link). 276 // 277 // # Errors 278 // 279 // A zero syscall.Errno is success. The below are expected otherwise: 280 // - syscall.ENOSYS: the implementation does not support this function. 281 // - syscall.EPERM: `oldPath` or `newPath` is invalid. 282 // - syscall.EEXIST: `newPath` exists. 283 // 284 // # Notes 285 // 286 // - This is like syscall.Symlink, except the `oldPath` is relative to 287 // this file system. 288 // - This is like `symlink` in POSIX. See 289 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlink.html 290 // - Only `newPath` is relative to this file system and `oldPath` is kept 291 // as-is. That is because the link is only resolved relative to the 292 // directory when dereferencing it (e.g. ReadLink). 293 // See https://github.com/bytecodealliance/cap-std/blob/v1.0.4/cap-std/src/fs/dir.rs#L404-L409 294 // for how others implement this. 295 // - Symlinks in Windows requires `SeCreateSymbolicLinkPrivilege`. 296 // Otherwise, syscall.EPERM results. 297 // See https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links 298 Symlink(oldPath, linkName string) syscall.Errno 299 300 // Readlink reads the contents of a symbolic link. 301 // 302 // # Errors 303 // 304 // A zero syscall.Errno is success. The below are expected otherwise: 305 // - syscall.ENOSYS: the implementation does not support this function. 306 // - syscall.EINVAL: `path` is invalid. 307 // 308 // # Notes 309 // 310 // - This is like syscall.Readlink, except the path is relative to this 311 // filesystem. 312 // - This is like `readlink` in POSIX. See 313 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html 314 // - On Windows, the path separator is different from other platforms, 315 // but to provide consistent results to Wasm, this normalizes to a "/" 316 // separator. 317 Readlink(path string) (string, syscall.Errno) 318 319 // Truncate truncates a file to a specified length. 320 // 321 // # Errors 322 // 323 // A zero syscall.Errno is success. The below are expected otherwise: 324 // - syscall.ENOSYS: the implementation does not support this function. 325 // - syscall.EINVAL: `path` is invalid or size is negative. 326 // - syscall.ENOENT: `path` doesn't exist. 327 // - syscall.EISDIR: `path` is a directory. 328 // - syscall.EACCES: `path` doesn't have write access. 329 // 330 // # Notes 331 // 332 // - This is like syscall.Truncate, except the path is relative to this 333 // filesystem. 334 // - This is like `truncate` in POSIX. See 335 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html 336 Truncate(path string, size int64) syscall.Errno 337 338 // Utimens set file access and modification times on a path relative to 339 // this file system, at nanosecond precision. 340 // 341 // # Parameters 342 // 343 // The `times` parameter includes the access and modification timestamps to 344 // assign. Special syscall.Timespec NSec values platform.UTIME_NOW and 345 // platform.UTIME_OMIT may be specified instead of real timestamps. A nil 346 // `times` parameter behaves the same as if both were set to 347 // platform.UTIME_NOW. 348 // 349 // When the `symlinkFollow` parameter is true and the path is a symbolic link, 350 // the target of expanding that link is updated. 351 // 352 // # Errors 353 // 354 // A zero syscall.Errno is success. The below are expected otherwise: 355 // - syscall.ENOSYS: the implementation does not support this function. 356 // - syscall.EINVAL: `path` is invalid. 357 // - syscall.EEXIST: `path` exists and is a directory. 358 // - syscall.ENOTDIR: `path` exists and is a file. 359 // 360 // # Notes 361 // 362 // - This is like syscall.UtimesNano and `utimensat` with `AT_FDCWD` in 363 // POSIX. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html 364 Utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) syscall.Errno 365 }