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  }