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  }