github.com/tetratelabs/wazero@v1.2.1/internal/fsapi/file.go (about)

     1  package fsapi
     2  
     3  import (
     4  	"io/fs"
     5  	"syscall"
     6  	"time"
     7  )
     8  
     9  // File is a writeable fs.File bridge backed by syscall functions needed for ABI
    10  // including WASI and runtime.GOOS=js.
    11  //
    12  // Implementations should embed UnimplementedFile for forward compatability. Any
    13  // unsupported method or parameter should return syscall.ENOSYS.
    14  //
    15  // # Errors
    16  //
    17  // All methods that can return an error return a syscall.Errno, which is zero
    18  // on success.
    19  //
    20  // Restricting to syscall.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 File interface {
    30  	// Ino returns the inode (Stat_t.Ino) of this file, zero if unknown or an
    31  	// error there was an error retrieving it.
    32  	//
    33  	// # Errors
    34  	//
    35  	// Possible errors are those from Stat, except syscall.ENOSYS should not
    36  	// be returned. Zero should be returned if there is no implementation.
    37  	//
    38  	// # Notes
    39  	//
    40  	//   - Some implementations implement this with a cached call to Stat.
    41  	Ino() (uint64, syscall.Errno)
    42  
    43  	// IsNonblock returns true if the file was opened with O_NONBLOCK, or
    44  	// SetNonblock was successfully enabled on this file.
    45  	//
    46  	// # Notes
    47  	//
    48  	//   - This might not match the underlying state of the file descriptor if
    49  	//     the file was not opened via OpenFile.
    50  	IsNonblock() bool
    51  
    52  	// SetNonblock toggles the non-blocking mode (O_NONBLOCK) of this file.
    53  	//
    54  	// # Errors
    55  	//
    56  	// A zero syscall.Errno is success. The below are expected otherwise:
    57  	//   - syscall.ENOSYS: the implementation does not support this function.
    58  	//   - syscall.EBADF: the file or directory was closed.
    59  	//
    60  	// # Notes
    61  	//
    62  	//   - This is like syscall.SetNonblock and `fcntl` with O_NONBLOCK in
    63  	//     POSIX. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html
    64  	SetNonblock(enable bool) syscall.Errno
    65  
    66  	// IsAppend returns true if the file was opened with syscall.O_APPEND, or
    67  	// SetAppend was successfully enabled on this file.
    68  	//
    69  	// # Notes
    70  	//
    71  	//   - This might not match the underlying state of the file descriptor if
    72  	//     the file was not opened via OpenFile.
    73  	IsAppend() bool
    74  
    75  	// SetAppend toggles the append mode (syscall.O_APPEND) of this file.
    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.EBADF: the file or directory was closed.
    82  	//
    83  	// # Notes
    84  	//
    85  	//   - There is no `O_APPEND` for `fcntl` in POSIX, so implementations may
    86  	//     have to re-open the underlying file to apply this. See
    87  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html
    88  	SetAppend(enable bool) syscall.Errno
    89  
    90  	// Stat is similar to syscall.Fstat.
    91  	//
    92  	// # Errors
    93  	//
    94  	// A zero syscall.Errno is success. The below are expected otherwise:
    95  	//   - syscall.ENOSYS: the implementation does not support this function.
    96  	//   - syscall.EBADF: the file or directory was closed.
    97  	//
    98  	// # Notes
    99  	//
   100  	//   - This is like syscall.Fstat and `fstatat` with `AT_FDCWD` in POSIX.
   101  	//     See https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html
   102  	//   - A fs.FileInfo backed implementation sets atim, mtim and ctim to the
   103  	//     same value.
   104  	//   - Windows allows you to stat a closed directory.
   105  	Stat() (Stat_t, syscall.Errno)
   106  
   107  	// IsDir returns true if this file is a directory or an error there was an
   108  	// error retrieving this information.
   109  	//
   110  	// # Errors
   111  	//
   112  	// Possible errors are those from Stat.
   113  	//
   114  	// # Notes
   115  	//
   116  	//   - Some implementations implement this with a cached call to Stat.
   117  	IsDir() (bool, syscall.Errno)
   118  
   119  	// Read attempts to read all bytes in the file into `buf`, and returns the
   120  	// count read even on error.
   121  	//
   122  	// # Errors
   123  	//
   124  	// A zero syscall.Errno is success. The below are expected otherwise:
   125  	//   - syscall.ENOSYS: the implementation does not support this function.
   126  	//   - syscall.EBADF: the file or directory was closed or not readable.
   127  	//   - syscall.EISDIR: the file was a directory.
   128  	//
   129  	// # Notes
   130  	//
   131  	//   - This is like io.Reader and `read` in POSIX, preferring semantics of
   132  	//     io.Reader. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html
   133  	//   - Unlike io.Reader, there is no io.EOF returned on end-of-file. To
   134  	//     read the file completely, the caller must repeat until `n` is zero.
   135  	Read(buf []byte) (n int, errno syscall.Errno)
   136  
   137  	// Pread attempts to read all bytes in the file into `p`, starting at the
   138  	// offset `off`, and returns the count read even on error.
   139  	//
   140  	// # Errors
   141  	//
   142  	// A zero syscall.Errno is success. The below are expected otherwise:
   143  	//   - syscall.ENOSYS: the implementation does not support this function.
   144  	//   - syscall.EBADF: the file or directory was closed or not readable.
   145  	//   - syscall.EINVAL: the offset was negative.
   146  	//   - syscall.EISDIR: the file was a directory.
   147  	//
   148  	// # Notes
   149  	//
   150  	//   - This is like io.ReaderAt and `pread` in POSIX, preferring semantics
   151  	//     of io.ReaderAt. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html
   152  	//   - Unlike io.ReaderAt, there is no io.EOF returned on end-of-file. To
   153  	//     read the file completely, the caller must repeat until `n` is zero.
   154  	Pread(buf []byte, off int64) (n int, errno syscall.Errno)
   155  
   156  	// Seek attempts to set the next offset for Read or Write and returns the
   157  	// resulting absolute offset or an error.
   158  	//
   159  	// # Parameters
   160  	//
   161  	// The `offset` parameters is interpreted in terms of `whence`:
   162  	//   - io.SeekStart: relative to the start of the file, e.g. offset=0 sets
   163  	//     the next Read or Write to the beginning of the file.
   164  	//   - io.SeekCurrent: relative to the current offset, e.g. offset=16 sets
   165  	//     the next Read or Write 16 bytes past the prior.
   166  	//   - io.SeekEnd: relative to the end of the file, e.g. offset=-1 sets the
   167  	//     next Read or Write to the last byte in the file.
   168  	//
   169  	// # Behavior when a directory
   170  	//
   171  	// The only supported use case for a directory is seeking to `offset` zero
   172  	// (`whence` = io.SeekStart). This should have the same behavior as
   173  	// os.File, which resets any internal state used by Readdir.
   174  	//
   175  	// # Errors
   176  	//
   177  	// A zero syscall.Errno is success. The below are expected otherwise:
   178  	//   - syscall.ENOSYS: the implementation does not support this function.
   179  	//   - syscall.EBADF: the file or directory was closed or not readable.
   180  	//   - syscall.EINVAL: the offset was negative.
   181  	//
   182  	// # Notes
   183  	//
   184  	//   - This is like io.Seeker and `fseek` in POSIX, preferring semantics
   185  	//     of io.Seeker. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/fseek.html
   186  	Seek(offset int64, whence int) (newOffset int64, errno syscall.Errno)
   187  
   188  	// PollRead returns if the file has data ready to be read or an error.
   189  	//
   190  	// # Parameters
   191  	//
   192  	// The `timeout` parameter when nil blocks up to forever.
   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  	//
   199  	// # Notes
   200  	//
   201  	//   - This is like `poll` in POSIX, for a single file.
   202  	//     See https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
   203  	//   - No-op files, such as those which read from /dev/null, should return
   204  	//     immediately true to avoid hangs (because data will never become
   205  	//     available).
   206  	PollRead(timeout *time.Duration) (ready bool, errno syscall.Errno)
   207  
   208  	// Readdir reads the contents of the directory associated with file and
   209  	// returns a slice of up to n Dirent values in an arbitrary order. This is
   210  	// a stateful function, so subsequent calls return any next values.
   211  	//
   212  	// If n > 0, Readdir returns at most n entries or an error.
   213  	// If n <= 0, Readdir returns all remaining entries or an error.
   214  	//
   215  	// # Errors
   216  	//
   217  	// A zero syscall.Errno is success. The below are expected otherwise:
   218  	//   - syscall.ENOSYS: the implementation does not support this function.
   219  	//   - syscall.ENOTDIR: the file was not a directory
   220  	//
   221  	// # Notes
   222  	//
   223  	//   - This is like `Readdir` on os.File, but unlike `readdir` in POSIX.
   224  	//     See https://pubs.opengroup.org/onlinepubs/9699919799/functions/readdir.html
   225  	//   - For portability reasons, no error is returned at the end of the
   226  	//     directory, when the file is closed or removed while open.
   227  	//     See https://github.com/ziglang/zig/blob/0.10.1/lib/std/fs.zig#L635-L637
   228  	Readdir(n int) (dirents []Dirent, errno syscall.Errno)
   229  	// ^-- TODO: consider being more like POSIX, for example, returning a
   230  	// closeable Dirent object that can iterate on demand. This would
   231  	// centralize sizing logic needed by wasi, particularly extra dirents
   232  	// stored in the sys.FileEntry type. It could possibly reduce the need to
   233  	// reopen the whole file.
   234  
   235  	// Write attempts to write all bytes in `p` to the file, and returns the
   236  	// count written even on error.
   237  	//
   238  	// # Errors
   239  	//
   240  	// A zero syscall.Errno is success. The below are expected otherwise:
   241  	//   - syscall.ENOSYS: the implementation does not support this function.
   242  	//   - syscall.EBADF: the file was closed, not writeable, or a directory.
   243  	//
   244  	// # Notes
   245  	//
   246  	//   - This is like io.Writer and `write` in POSIX, preferring semantics of
   247  	//     io.Writer. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html
   248  	Write(buf []byte) (n int, errno syscall.Errno)
   249  
   250  	// Pwrite attempts to write all bytes in `p` to the file at the given
   251  	// offset `off`, and returns the count written even on error.
   252  	//
   253  	// # Errors
   254  	//
   255  	// A zero syscall.Errno is success. The below are expected otherwise:
   256  	//   - syscall.ENOSYS: the implementation does not support this function.
   257  	//   - syscall.EBADF: the file or directory was closed or not writeable.
   258  	//   - syscall.EINVAL: the offset was negative.
   259  	//   - syscall.EISDIR: the file was a directory.
   260  	//
   261  	// # Notes
   262  	//
   263  	//   - This is like io.WriterAt and `pwrite` in POSIX, preferring semantics
   264  	//     of io.WriterAt. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html
   265  	Pwrite(buf []byte, off int64) (n int, errno syscall.Errno)
   266  
   267  	// Truncate truncates a file to a specified length.
   268  	//
   269  	// # Errors
   270  	//
   271  	// A zero syscall.Errno is success. The below are expected otherwise:
   272  	//   - syscall.ENOSYS: the implementation does not support this function.
   273  	//   - syscall.EBADF: the file or directory was closed.
   274  	//   - syscall.EINVAL: the `size` is negative.
   275  	//   - syscall.EISDIR: the file was a directory.
   276  	//
   277  	// # Notes
   278  	//
   279  	//   - This is like syscall.Ftruncate and `ftruncate` in POSIX. See
   280  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
   281  	//   - Windows does not error when calling Truncate on a closed file.
   282  	Truncate(size int64) syscall.Errno
   283  
   284  	// Sync synchronizes changes to the file.
   285  	//
   286  	// # Errors
   287  	//
   288  	// A zero syscall.Errno is success. The below are expected otherwise:
   289  	//   - syscall.EBADF: the file or directory was closed.
   290  	//
   291  	// # Notes
   292  	//
   293  	//   - This is like syscall.Fsync and `fsync` in POSIX. See
   294  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html
   295  	//   - This returns with no error instead of syscall.ENOSYS when
   296  	//     unimplemented. This prevents fake filesystems from erring.
   297  	//   - Windows does not error when calling Sync on a closed file.
   298  	Sync() syscall.Errno
   299  
   300  	// Datasync synchronizes the data of a file.
   301  	//
   302  	// # Errors
   303  	//
   304  	// A zero syscall.Errno is success. The below are expected otherwise:
   305  	//   - syscall.EBADF: the file or directory was closed.
   306  	//
   307  	// # Notes
   308  	//
   309  	//   - This is like syscall.Fdatasync and `fdatasync` in POSIX. See
   310  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html
   311  	//   - This returns with no error instead of syscall.ENOSYS when
   312  	//     unimplemented. This prevents fake filesystems from erring.
   313  	//   - As this is commonly missing, some implementations dispatch to Sync.
   314  	Datasync() syscall.Errno
   315  
   316  	// Chmod changes the mode of the file.
   317  	//
   318  	// # Errors
   319  	//
   320  	// A zero syscall.Errno is success. The below are expected otherwise:
   321  	//   - syscall.ENOSYS: the implementation does not support this function.
   322  	//   - syscall.EBADF: the file or directory was closed.
   323  	//
   324  	// # Notes
   325  	//
   326  	//   - This is like syscall.Fchmod and `fchmod` in POSIX. See
   327  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html
   328  	//   - Windows ignores the execute bit, and any permissions come back as
   329  	//     group and world. For example, chmod of 0400 reads back as 0444, and
   330  	//     0700 0666. Also, permissions on directories aren't supported at all.
   331  	Chmod(fs.FileMode) syscall.Errno
   332  
   333  	// Chown changes the owner and group of a file.
   334  	//
   335  	// # Errors
   336  	//
   337  	// A zero syscall.Errno is success. The below are expected otherwise:
   338  	//   - syscall.ENOSYS: the implementation does not support this function.
   339  	//   - syscall.EBADF: the file or directory was closed.
   340  	//
   341  	// # Notes
   342  	//
   343  	//   - This is like syscall.Fchown and `fchown` in POSIX. See
   344  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html
   345  	//   - This always returns syscall.ENOSYS on windows.
   346  	Chown(uid, gid int) syscall.Errno
   347  
   348  	// Utimens set file access and modification times of this file, at
   349  	// nanosecond precision.
   350  	//
   351  	// # Parameters
   352  	//
   353  	// The `times` parameter includes the access and modification timestamps to
   354  	// assign. Special syscall.Timespec NSec values UTIME_NOW and UTIME_OMIT may be
   355  	// specified instead of real timestamps. A nil `times` parameter behaves the
   356  	// same as if both were set to UTIME_NOW.
   357  	//
   358  	// # Errors
   359  	//
   360  	// A zero syscall.Errno is success. The below are expected otherwise:
   361  	//   - syscall.ENOSYS: the implementation does not support this function.
   362  	//   - syscall.EBADF: the file or directory was closed.
   363  	//
   364  	// # Notes
   365  	//
   366  	//   - This is like syscall.UtimesNano and `futimens` in POSIX. See
   367  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html
   368  	//   - Windows requires files to be open with syscall.O_RDWR, which means you
   369  	//     cannot use this to update timestamps on a directory (syscall.EPERM).
   370  	Utimens(times *[2]syscall.Timespec) syscall.Errno
   371  
   372  	// Close closes the underlying file.
   373  	//
   374  	// A zero syscall.Errno is success. The below are expected otherwise:
   375  	//   - syscall.ENOSYS: the implementation does not support this function.
   376  	//
   377  	// # Notes
   378  	//
   379  	//   - This is like syscall.Close and `close` in POSIX. See
   380  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
   381  	Close() syscall.Errno
   382  }