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