github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/experimental/sys/file.go (about)

     1  package sys
     2  
     3  import "github.com/wasilibs/wazerox/sys"
     4  
     5  // File is a writeable fs.File bridge backed by syscall functions needed for ABI
     6  // including WASI and runtime.GOOS=js.
     7  //
     8  // Implementations should embed UnimplementedFile for forward compatability. Any
     9  // unsupported method or parameter should return ENOSYS.
    10  //
    11  // # Errors
    12  //
    13  // All methods that can return an error return a Errno, which is zero
    14  // on success.
    15  //
    16  // Restricting to Errno matches current WebAssembly host functions,
    17  // which are constrained to well-known error codes. For example, `GOOS=js` maps
    18  // hard coded values and panics otherwise. More commonly, WASI maps syscall
    19  // errors to u32 numeric values.
    20  //
    21  // # Notes
    22  //
    23  //   - You must call Close to avoid file resource conflicts. For example,
    24  //     Windows cannot delete the underlying directory while a handle to it
    25  //     remains open.
    26  //   - A writable filesystem abstraction is not yet implemented as of Go 1.20.
    27  //     See https://github.com/golang/go/issues/45757
    28  type File interface {
    29  	// Dev returns the device ID (Stat_t.Dev) of this file, zero if unknown or
    30  	// an error retrieving it.
    31  	//
    32  	// # Errors
    33  	//
    34  	// Possible errors are those from Stat, except ENOSYS should not
    35  	// be returned. Zero should be returned if there is no implementation.
    36  	//
    37  	// # Notes
    38  	//
    39  	//   - Implementations should cache this result.
    40  	//   - This combined with Ino can implement os.SameFile.
    41  	Dev() (uint64, Errno)
    42  
    43  	// Ino returns the serial number (Stat_t.Ino) of this file, zero if unknown
    44  	// or an error retrieving it.
    45  	//
    46  	// # Errors
    47  	//
    48  	// Possible errors are those from Stat, except ENOSYS should not
    49  	// be returned. Zero should be returned if there is no implementation.
    50  	//
    51  	// # Notes
    52  	//
    53  	//   - Implementations should cache this result.
    54  	//   - This combined with Dev can implement os.SameFile.
    55  	Ino() (sys.Inode, Errno)
    56  
    57  	// IsDir returns true if this file is a directory or an error there was an
    58  	// error retrieving this information.
    59  	//
    60  	// # Errors
    61  	//
    62  	// Possible errors are those from Stat, except ENOSYS should not
    63  	// be returned. false should be returned if there is no implementation.
    64  	//
    65  	// # Notes
    66  	//
    67  	//   - Implementations should cache this result.
    68  	IsDir() (bool, Errno)
    69  
    70  	// IsAppend returns true if the file was opened with O_APPEND, or
    71  	// SetAppend was successfully enabled on this file.
    72  	//
    73  	// # Notes
    74  	//
    75  	//   - This might not match the underlying state of the file descriptor if
    76  	//     the file was not opened via OpenFile.
    77  	IsAppend() bool
    78  
    79  	// SetAppend toggles the append mode (O_APPEND) of this file.
    80  	//
    81  	// # Errors
    82  	//
    83  	// A zero Errno is success. The below are expected otherwise:
    84  	//   - ENOSYS: the implementation does not support this function.
    85  	//   - EBADF: the file or directory was closed.
    86  	//
    87  	// # Notes
    88  	//
    89  	//   - There is no `O_APPEND` for `fcntl` in POSIX, so implementations may
    90  	//     have to re-open the underlying file to apply this. See
    91  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html
    92  	SetAppend(enable bool) Errno
    93  
    94  	// Stat is similar to syscall.Fstat.
    95  	//
    96  	// # Errors
    97  	//
    98  	// A zero Errno is success. The below are expected otherwise:
    99  	//   - ENOSYS: the implementation does not support this function.
   100  	//   - EBADF: the file or directory was closed.
   101  	//
   102  	// # Notes
   103  	//
   104  	//   - This is like syscall.Fstat and `fstatat` with `AT_FDCWD` in POSIX.
   105  	//     See https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html
   106  	//   - A fs.FileInfo backed implementation sets atim, mtim and ctim to the
   107  	//     same value.
   108  	//   - Windows allows you to stat a closed directory.
   109  	Stat() (sys.Stat_t, Errno)
   110  
   111  	// Read attempts to read all bytes in the file into `buf`, and returns the
   112  	// count read even on error.
   113  	//
   114  	// # Errors
   115  	//
   116  	// A zero Errno is success. The below are expected otherwise:
   117  	//   - ENOSYS: the implementation does not support this function.
   118  	//   - EBADF: the file or directory was closed or not readable.
   119  	//   - EISDIR: the file was a directory.
   120  	//
   121  	// # Notes
   122  	//
   123  	//   - This is like io.Reader and `read` in POSIX, preferring semantics of
   124  	//     io.Reader. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html
   125  	//   - Unlike io.Reader, there is no io.EOF returned on end-of-file. To
   126  	//     read the file completely, the caller must repeat until `n` is zero.
   127  	Read(buf []byte) (n int, errno Errno)
   128  
   129  	// Pread attempts to read all bytes in the file into `p`, starting at the
   130  	// offset `off`, and returns the count read even on error.
   131  	//
   132  	// # Errors
   133  	//
   134  	// A zero Errno is success. The below are expected otherwise:
   135  	//   - ENOSYS: the implementation does not support this function.
   136  	//   - EBADF: the file or directory was closed or not readable.
   137  	//   - EINVAL: the offset was negative.
   138  	//   - EISDIR: the file was a directory.
   139  	//
   140  	// # Notes
   141  	//
   142  	//   - This is like io.ReaderAt and `pread` in POSIX, preferring semantics
   143  	//     of io.ReaderAt. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html
   144  	//   - Unlike io.ReaderAt, there is no io.EOF returned on end-of-file. To
   145  	//     read the file completely, the caller must repeat until `n` is zero.
   146  	Pread(buf []byte, off int64) (n int, errno Errno)
   147  
   148  	// Seek attempts to set the next offset for Read or Write and returns the
   149  	// resulting absolute offset or an error.
   150  	//
   151  	// # Parameters
   152  	//
   153  	// The `offset` parameters is interpreted in terms of `whence`:
   154  	//   - io.SeekStart: relative to the start of the file, e.g. offset=0 sets
   155  	//     the next Read or Write to the beginning of the file.
   156  	//   - io.SeekCurrent: relative to the current offset, e.g. offset=16 sets
   157  	//     the next Read or Write 16 bytes past the prior.
   158  	//   - io.SeekEnd: relative to the end of the file, e.g. offset=-1 sets the
   159  	//     next Read or Write to the last byte in the file.
   160  	//
   161  	// # Behavior when a directory
   162  	//
   163  	// The only supported use case for a directory is seeking to `offset` zero
   164  	// (`whence` = io.SeekStart). This should have the same behavior as
   165  	// os.File, which resets any internal state used by Readdir.
   166  	//
   167  	// # Errors
   168  	//
   169  	// A zero Errno is success. The below are expected otherwise:
   170  	//   - ENOSYS: the implementation does not support this function.
   171  	//   - EBADF: the file or directory was closed or not readable.
   172  	//   - EINVAL: the offset was negative.
   173  	//
   174  	// # Notes
   175  	//
   176  	//   - This is like io.Seeker and `fseek` in POSIX, preferring semantics
   177  	//     of io.Seeker. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/fseek.html
   178  	Seek(offset int64, whence int) (newOffset int64, errno Errno)
   179  
   180  	// Readdir reads the contents of the directory associated with file and
   181  	// returns a slice of up to n Dirent values in an arbitrary order. This is
   182  	// a stateful function, so subsequent calls return any next values.
   183  	//
   184  	// If n > 0, Readdir returns at most n entries or an error.
   185  	// If n <= 0, Readdir returns all remaining entries or an error.
   186  	//
   187  	// # Errors
   188  	//
   189  	// A zero Errno is success. The below are expected otherwise:
   190  	//   - ENOSYS: the implementation does not support this function.
   191  	//   - EBADF: the file was closed or not a directory.
   192  	//   - ENOENT: the directory could not be read (e.g. deleted).
   193  	//
   194  	// # Notes
   195  	//
   196  	//   - This is like `Readdir` on os.File, but unlike `readdir` in POSIX.
   197  	//     See https://pubs.opengroup.org/onlinepubs/9699919799/functions/readdir.html
   198  	//   - Unlike os.File, there is no io.EOF returned on end-of-directory. To
   199  	//     read the directory completely, the caller must repeat until the
   200  	//     count read (`len(dirents)`) is less than `n`.
   201  	//   - See /RATIONALE.md for design notes.
   202  	Readdir(n int) (dirents []Dirent, errno Errno)
   203  
   204  	// Write attempts to write all bytes in `p` to the file, and returns the
   205  	// count written even on error.
   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  	//   - EBADF: the file was closed, not writeable, or a directory.
   212  	//
   213  	// # Notes
   214  	//
   215  	//   - This is like io.Writer and `write` in POSIX, preferring semantics of
   216  	//     io.Writer. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html
   217  	Write(buf []byte) (n int, errno Errno)
   218  
   219  	// Pwrite attempts to write all bytes in `p` to the file at the given
   220  	// offset `off`, and returns the count written even on error.
   221  	//
   222  	// # Errors
   223  	//
   224  	// A zero Errno is success. The below are expected otherwise:
   225  	//   - ENOSYS: the implementation does not support this function.
   226  	//   - EBADF: the file or directory was closed or not writeable.
   227  	//   - EINVAL: the offset was negative.
   228  	//   - EISDIR: the file was a directory.
   229  	//
   230  	// # Notes
   231  	//
   232  	//   - This is like io.WriterAt and `pwrite` in POSIX, preferring semantics
   233  	//     of io.WriterAt. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html
   234  	Pwrite(buf []byte, off int64) (n int, errno Errno)
   235  
   236  	// Truncate truncates a file to a specified length.
   237  	//
   238  	// # Errors
   239  	//
   240  	// A zero Errno is success. The below are expected otherwise:
   241  	//   - ENOSYS: the implementation does not support this function.
   242  	//   - EBADF: the file or directory was closed.
   243  	//   - EINVAL: the `size` is negative.
   244  	//   - EISDIR: the file was a directory.
   245  	//
   246  	// # Notes
   247  	//
   248  	//   - This is like syscall.Ftruncate and `ftruncate` in POSIX. See
   249  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
   250  	//   - Windows does not error when calling Truncate on a closed file.
   251  	Truncate(size int64) Errno
   252  
   253  	// Sync synchronizes changes to the file.
   254  	//
   255  	// # Errors
   256  	//
   257  	// A zero Errno is success. The below are expected otherwise:
   258  	//   - EBADF: the file or directory was closed.
   259  	//
   260  	// # Notes
   261  	//
   262  	//   - This is like syscall.Fsync and `fsync` in POSIX. See
   263  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html
   264  	//   - This returns with no error instead of ENOSYS when
   265  	//     unimplemented. This prevents fake filesystems from erring.
   266  	//   - Windows does not error when calling Sync on a closed file.
   267  	Sync() Errno
   268  
   269  	// Datasync synchronizes the data of a file.
   270  	//
   271  	// # Errors
   272  	//
   273  	// A zero Errno is success. The below are expected otherwise:
   274  	//   - EBADF: the file or directory was closed.
   275  	//
   276  	// # Notes
   277  	//
   278  	//   - This is like syscall.Fdatasync and `fdatasync` in POSIX. See
   279  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html
   280  	//   - This returns with no error instead of ENOSYS when
   281  	//     unimplemented. This prevents fake filesystems from erring.
   282  	//   - As this is commonly missing, some implementations dispatch to Sync.
   283  	Datasync() Errno
   284  
   285  	// Utimens set file access and modification times of this file, at
   286  	// nanosecond precision.
   287  	//
   288  	// # Parameters
   289  	//
   290  	// The `atim` and `mtim` parameters refer to access and modification time
   291  	// stamps as defined in sys.Stat_t. To retain one or the other, substitute
   292  	// it with the pseudo-timestamp UTIME_OMIT.
   293  	//
   294  	// # Errors
   295  	//
   296  	// A zero Errno is success. The below are expected otherwise:
   297  	//   - ENOSYS: the implementation does not support this function.
   298  	//   - EBADF: the file or directory was closed.
   299  	//
   300  	// # Notes
   301  	//
   302  	//   - This is like syscall.UtimesNano and `futimens` in POSIX. See
   303  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html
   304  	//   - Windows requires files to be open with O_RDWR, which means you
   305  	//     cannot use this to update timestamps on a directory (EPERM).
   306  	Utimens(atim, mtim int64) Errno
   307  
   308  	// Close closes the underlying file.
   309  	//
   310  	// A zero Errno is returned if unimplemented or success.
   311  	//
   312  	// # Notes
   313  	//
   314  	//   - This is like syscall.Close and `close` in POSIX. See
   315  	//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
   316  	Close() Errno
   317  }