package wasi:filesystem@0.2.3;
/// WASI filesystem is a filesystem API primarily intended to let users run WASI
/// programs that access their files on their existing filesystems, without
/// significant overhead.
///
/// It is intended to be roughly portable between Unix-family platforms and
/// Windows, though it does not hide many of the major differences.
///
/// Paths are passed as interface-type `string`s, meaning they must consist of
/// a sequence of Unicode Scalar Values (USVs). Some filesystems may contain
/// paths which are not accessible by this API.
///
/// The directory separator in WASI is always the forward-slash (`/`).
///
/// All paths in WASI are relative paths, and are interpreted relative to a
/// `descriptor` referring to a base directory. If a `path` argument to any WASI
/// function starts with `/`, or if any step of resolving a `path`, including
/// `..` and symbolic link steps, reaches a directory outside of the base
/// directory, or reaches a symlink to an absolute or rooted path in the
/// underlying filesystem, the function fails with `error-code::not-permitted`.
///
/// For more information about WASI path resolution and sandboxing, see
/// [WASI filesystem path resolution].
///
/// [WASI filesystem path resolution]: https://github.com/WebAssembly/wasi-filesystem/blob/main/path-resolution.md
@since(version = 0.2.0)
interface types {
    @since(version = 0.2.0)
    use wasi:io/streams@0.2.3.{input-stream, output-stream, error};
    @since(version = 0.2.0)
    use wasi:clocks/wall-clock@0.2.3.{datetime};

    /// File size or length of a region within a file.
    @since(version = 0.2.0)
    type filesize = u64;

    /// The type of a filesystem object referenced by a descriptor.
    ///
    /// Note: This was called `filetype` in earlier versions of WASI.
    @since(version = 0.2.0)
    enum descriptor-type {
        /// The type of the descriptor or file is unknown or is different from
        /// any of the other types specified.
        unknown,
        /// The descriptor refers to a block device inode.
        block-device,
        /// The descriptor refers to a character device inode.
        character-device,
        /// The descriptor refers to a directory inode.
        directory,
        /// The descriptor refers to a named pipe.
        fifo,
        /// The file refers to a symbolic link inode.
        symbolic-link,
        /// The descriptor refers to a regular file inode.
        regular-file,
        /// The descriptor refers to a socket.
        socket,
    }

    /// Descriptor flags.
    ///
    /// Note: This was called `fdflags` in earlier versions of WASI.
    @since(version = 0.2.0)
    flags descriptor-flags {
        /// Read mode: Data can be read.
        read,
        /// Write mode: Data can be written to.
        write,
        /// Request that writes be performed according to synchronized I/O file
        /// integrity completion. The data stored in the file and the file's
        /// metadata are synchronized. This is similar to `O_SYNC` in POSIX.
        ///
        /// The precise semantics of this operation have not yet been defined for
        /// WASI. At this time, it should be interpreted as a request, and not a
        /// requirement.
        file-integrity-sync,
        /// Request that writes be performed according to synchronized I/O data
        /// integrity completion. Only the data stored in the file is
        /// synchronized. This is similar to `O_DSYNC` in POSIX.
        ///
        /// The precise semantics of this operation have not yet been defined for
        /// WASI. At this time, it should be interpreted as a request, and not a
        /// requirement.
        data-integrity-sync,
        /// Requests that reads be performed at the same level of integrity
        /// requested for writes. This is similar to `O_RSYNC` in POSIX.
        ///
        /// The precise semantics of this operation have not yet been defined for
        /// WASI. At this time, it should be interpreted as a request, and not a
        /// requirement.
        requested-write-sync,
        /// Mutating directories mode: Directory contents may be mutated.
        ///
        /// When this flag is unset on a descriptor, operations using the
        /// descriptor which would create, rename, delete, modify the data or
        /// metadata of filesystem objects, or obtain another handle which
        /// would permit any of those, shall fail with `error-code::read-only` if
        /// they would otherwise succeed.
        ///
        /// This may only be set on directories.
        mutate-directory,
    }

    /// File attributes.
    ///
    /// Note: This was called `filestat` in earlier versions of WASI.
    @since(version = 0.2.0)
    record descriptor-stat {
        /// File type.
        %type: descriptor-type,
        /// Number of hard links to the file.
        link-count: link-count,
        /// For regular files, the file size in bytes. For symbolic links, the
        /// length in bytes of the pathname contained in the symbolic link.
        size: filesize,
        /// Last data access timestamp.
        ///
        /// If the `option` is none, the platform doesn't maintain an access
        /// timestamp for this file.
        data-access-timestamp: option<datetime>,
        /// Last data modification timestamp.
        ///
        /// If the `option` is none, the platform doesn't maintain a
        /// modification timestamp for this file.
        data-modification-timestamp: option<datetime>,
        /// Last file status-change timestamp.
        ///
        /// If the `option` is none, the platform doesn't maintain a
        /// status-change timestamp for this file.
        status-change-timestamp: option<datetime>,
    }

    /// Flags determining the method of how paths are resolved.
    @since(version = 0.2.0)
    flags path-flags {
        /// As long as the resolved path corresponds to a symbolic link, it is
        /// expanded.
        symlink-follow,
    }

    /// Open flags used by `open-at`.
    @since(version = 0.2.0)
    flags open-flags {
        /// Create file if it does not exist, similar to `O_CREAT` in POSIX.
        create,
        /// Fail if not a directory, similar to `O_DIRECTORY` in POSIX.
        directory,
        /// Fail if file already exists, similar to `O_EXCL` in POSIX.
        exclusive,
        /// Truncate file to size 0, similar to `O_TRUNC` in POSIX.
        truncate,
    }

    /// Number of hard links to an inode.
    @since(version = 0.2.0)
    type link-count = u64;

    /// When setting a timestamp, this gives the value to set it to.
    @since(version = 0.2.0)
    variant new-timestamp {
        /// Leave the timestamp set to its previous value.
        no-change,
        /// Set the timestamp to the current time of the system clock associated
        /// with the filesystem.
        now,
        /// Set the timestamp to the given value.
        timestamp(datetime),
    }

    /// A directory entry.
    record directory-entry {
        /// The type of the file referred to by this directory entry.
        %type: descriptor-type,

        /// The name of the object.
        name: string,
    }

    /// Error codes returned by functions, similar to `errno` in POSIX.
    /// Not all of these error codes are returned by the functions provided by this
    /// API; some are used in higher-level library layers, and others are provided
    /// merely for alignment with POSIX.
    enum error-code {
        /// Permission denied, similar to `EACCES` in POSIX.
        access,
        /// Resource unavailable, or operation would block, similar to `EAGAIN` and `EWOULDBLOCK` in POSIX.
        would-block,
        /// Connection already in progress, similar to `EALREADY` in POSIX.
        already,
        /// Bad descriptor, similar to `EBADF` in POSIX.
        bad-descriptor,
        /// Device or resource busy, similar to `EBUSY` in POSIX.
        busy,
        /// Resource deadlock would occur, similar to `EDEADLK` in POSIX.
        deadlock,
        /// Storage quota exceeded, similar to `EDQUOT` in POSIX.
        quota,
        /// File exists, similar to `EEXIST` in POSIX.
        exist,
        /// File too large, similar to `EFBIG` in POSIX.
        file-too-large,
        /// Illegal byte sequence, similar to `EILSEQ` in POSIX.
        illegal-byte-sequence,
        /// Operation in progress, similar to `EINPROGRESS` in POSIX.
        in-progress,
        /// Interrupted function, similar to `EINTR` in POSIX.
        interrupted,
        /// Invalid argument, similar to `EINVAL` in POSIX.
        invalid,
        /// I/O error, similar to `EIO` in POSIX.
        io,
        /// Is a directory, similar to `EISDIR` in POSIX.
        is-directory,
        /// Too many levels of symbolic links, similar to `ELOOP` in POSIX.
        loop,
        /// Too many links, similar to `EMLINK` in POSIX.
        too-many-links,
        /// Message too large, similar to `EMSGSIZE` in POSIX.
        message-size,
        /// Filename too long, similar to `ENAMETOOLONG` in POSIX.
        name-too-long,
        /// No such device, similar to `ENODEV` in POSIX.
        no-device,
        /// No such file or directory, similar to `ENOENT` in POSIX.
        no-entry,
        /// No locks available, similar to `ENOLCK` in POSIX.
        no-lock,
        /// Not enough space, similar to `ENOMEM` in POSIX.
        insufficient-memory,
        /// No space left on device, similar to `ENOSPC` in POSIX.
        insufficient-space,
        /// Not a directory or a symbolic link to a directory, similar to `ENOTDIR` in POSIX.
        not-directory,
        /// Directory not empty, similar to `ENOTEMPTY` in POSIX.
        not-empty,
        /// State not recoverable, similar to `ENOTRECOVERABLE` in POSIX.
        not-recoverable,
        /// Not supported, similar to `ENOTSUP` and `ENOSYS` in POSIX.
        unsupported,
        /// Inappropriate I/O control operation, similar to `ENOTTY` in POSIX.
        no-tty,
        /// No such device or address, similar to `ENXIO` in POSIX.
        no-such-device,
        /// Value too large to be stored in data type, similar to `EOVERFLOW` in POSIX.
        overflow,
        /// Operation not permitted, similar to `EPERM` in POSIX.
        not-permitted,
        /// Broken pipe, similar to `EPIPE` in POSIX.
        pipe,
        /// Read-only file system, similar to `EROFS` in POSIX.
        read-only,
        /// Invalid seek, similar to `ESPIPE` in POSIX.
        invalid-seek,
        /// Text file busy, similar to `ETXTBSY` in POSIX.
        text-file-busy,
        /// Cross-device link, similar to `EXDEV` in POSIX.
        cross-device,
    }

    /// File or memory access pattern advisory information.
    @since(version = 0.2.0)
    enum advice {
        /// The application has no advice to give on its behavior with respect
        /// to the specified data.
        normal,
        /// The application expects to access the specified data sequentially
        /// from lower offsets to higher offsets.
        sequential,
        /// The application expects to access the specified data in a random
        /// order.
        random,
        /// The application expects to access the specified data in the near
        /// future.
        will-need,
        /// The application expects that it will not access the specified data
        /// in the near future.
        dont-need,
        /// The application expects to access the specified data once and then
        /// not reuse it thereafter.
        no-reuse,
    }

    /// A 128-bit hash value, split into parts because wasm doesn't have a
    /// 128-bit integer type.
    @since(version = 0.2.0)
    record metadata-hash-value {
       /// 64 bits of a 128-bit hash value.
       lower: u64,
       /// Another 64 bits of a 128-bit hash value.
       upper: u64,
    }

    /// A descriptor is a reference to a filesystem object, which may be a file,
    /// directory, named pipe, special file, or other object on which filesystem
    /// calls may be made.
    @since(version = 0.2.0)
    resource descriptor {
        /// Return a stream for reading from a file, if available.
        ///
        /// May fail with an error-code describing why the file cannot be read.
        ///
        /// Multiple read, write, and append streams may be active on the same open
        /// file and they do not interfere with each other.
        ///
        /// Note: This allows using `read-stream`, which is similar to `read` in POSIX.
        @since(version = 0.2.0)
        read-via-stream: func(
            /// The offset within the file at which to start reading.
            offset: filesize,
        ) -> result<input-stream, error-code>;

        /// Return a stream for writing to a file, if available.
        ///
        /// May fail with an error-code describing why the file cannot be written.
        ///
        /// Note: This allows using `write-stream`, which is similar to `write` in
        /// POSIX.
        @since(version = 0.2.0)
        write-via-stream: func(
            /// The offset within the file at which to start writing.
            offset: filesize,
        ) -> result<output-stream, error-code>;

        /// Return a stream for appending to a file, if available.
        ///
        /// May fail with an error-code describing why the file cannot be appended.
        ///
        /// Note: This allows using `write-stream`, which is similar to `write` with
        /// `O_APPEND` in POSIX.
        @since(version = 0.2.0)
        append-via-stream: func() -> result<output-stream, error-code>;

        /// Provide file advisory information on a descriptor.
        ///
        /// This is similar to `posix_fadvise` in POSIX.
        @since(version = 0.2.0)
        advise: func(
            /// The offset within the file to which the advisory applies.
            offset: filesize,
            /// The length of the region to which the advisory applies.
            length: filesize,
            /// The advice.
            advice: advice
        ) -> result<_, error-code>;

        /// Synchronize the data of a file to disk.
        ///
        /// This function succeeds with no effect if the file descriptor is not
        /// opened for writing.
        ///
        /// Note: This is similar to `fdatasync` in POSIX.
        @since(version = 0.2.0)
        sync-data: func() -> result<_, error-code>;

        /// Get flags associated with a descriptor.
        ///
        /// Note: This returns similar flags to `fcntl(fd, F_GETFL)` in POSIX.
        ///
        /// Note: This returns the value that was the `fs_flags` value returned
        /// from `fdstat_get` in earlier versions of WASI.
        @since(version = 0.2.0)
        get-flags: func() -> result<descriptor-flags, error-code>;

        /// Get the dynamic type of a descriptor.
        ///
        /// Note: This returns the same value as the `type` field of the `fd-stat`
        /// returned by `stat`, `stat-at` and similar.
        ///
        /// Note: This returns similar flags to the `st_mode & S_IFMT` value provided
        /// by `fstat` in POSIX.
        ///
        /// Note: This returns the value that was the `fs_filetype` value returned
        /// from `fdstat_get` in earlier versions of WASI.
        @since(version = 0.2.0)
        get-type: func() -> result<descriptor-type, error-code>;

        /// Adjust the size of an open file. If this increases the file's size, the
        /// extra bytes are filled with zeros.
        ///
        /// Note: This was called `fd_filestat_set_size` in earlier versions of WASI.
        @since(version = 0.2.0)
        set-size: func(size: filesize) -> result<_, error-code>;

        /// Adjust the timestamps of an open file or directory.
        ///
        /// Note: This is similar to `futimens` in POSIX.
        ///
        /// Note: This was called `fd_filestat_set_times` in earlier versions of WASI.
        @since(version = 0.2.0)
        set-times: func(
            /// The desired values of the data access timestamp.
            data-access-timestamp: new-timestamp,
            /// The desired values of the data modification timestamp.
            data-modification-timestamp: new-timestamp,
        ) -> result<_, error-code>;

        /// Read from a descriptor, without using and updating the descriptor's offset.
        ///
        /// This function returns a list of bytes containing the data that was
        /// read, along with a bool which, when true, indicates that the end of the
        /// file was reached. The returned list will contain up to `length` bytes; it
        /// may return fewer than requested, if the end of the file is reached or
        /// if the I/O operation is interrupted.
        ///
        /// In the future, this may change to return a `stream<u8, error-code>`.
        ///
        /// Note: This is similar to `pread` in POSIX.
        @since(version = 0.2.0)
        read: func(
            /// The maximum number of bytes to read.
            length: filesize,
            /// The offset within the file at which to read.
            offset: filesize,
        ) -> result<tuple<list<u8>, bool>, error-code>;

        /// Write to a descriptor, without using and updating the descriptor's offset.
        ///
        /// It is valid to write past the end of a file; the file is extended to the
        /// extent of the write, with bytes between the previous end and the start of
        /// the write set to zero.
        ///
        /// In the future, this may change to take a `stream<u8, error-code>`.
        ///
        /// Note: This is similar to `pwrite` in POSIX.
        @since(version = 0.2.0)
        write: func(
            /// Data to write
            buffer: list<u8>,
            /// The offset within the file at which to write.
            offset: filesize,
        ) -> result<filesize, error-code>;

        /// Read directory entries from a directory.
        ///
        /// On filesystems where directories contain entries referring to themselves
        /// and their parents, often named `.` and `..` respectively, these entries
        /// are omitted.
        ///
        /// This always returns a new stream which starts at the beginning of the
        /// directory. Multiple streams may be active on the same directory, and they
        /// do not interfere with each other.
        @since(version = 0.2.0)
        read-directory: func() -> result<directory-entry-stream, error-code>;

        /// Synchronize the data and metadata of a file to disk.
        ///
        /// This function succeeds with no effect if the file descriptor is not
        /// opened for writing.
        ///
        /// Note: This is similar to `fsync` in POSIX.
        @since(version = 0.2.0)
        sync: func() -> result<_, error-code>;

        /// Create a directory.
        ///
        /// Note: This is similar to `mkdirat` in POSIX.
        @since(version = 0.2.0)
        create-directory-at: func(
            /// The relative path at which to create the directory.
            path: string,
        ) -> result<_, error-code>;

        /// Return the attributes of an open file or directory.
        ///
        /// Note: This is similar to `fstat` in POSIX, except that it does not return
        /// device and inode information. For testing whether two descriptors refer to
        /// the same underlying filesystem object, use `is-same-object`. To obtain
        /// additional data that can be used do determine whether a file has been
        /// modified, use `metadata-hash`.
        ///
        /// Note: This was called `fd_filestat_get` in earlier versions of WASI.
        @since(version = 0.2.0)
        stat: func() -> result<descriptor-stat, error-code>;

        /// Return the attributes of a file or directory.
        ///
        /// Note: This is similar to `fstatat` in POSIX, except that it does not
        /// return device and inode information. See the `stat` description for a
        /// discussion of alternatives.
        ///
        /// Note: This was called `path_filestat_get` in earlier versions of WASI.
        @since(version = 0.2.0)
        stat-at: func(
            /// Flags determining the method of how the path is resolved.
            path-flags: path-flags,
            /// The relative path of the file or directory to inspect.
            path: string,
        ) -> result<descriptor-stat, error-code>;

        /// Adjust the timestamps of a file or directory.
        ///
        /// Note: This is similar to `utimensat` in POSIX.
        ///
        /// Note: This was called `path_filestat_set_times` in earlier versions of
        /// WASI.
        @since(version = 0.2.0)
        set-times-at: func(
            /// Flags determining the method of how the path is resolved.
            path-flags: path-flags,
            /// The relative path of the file or directory to operate on.
            path: string,
            /// The desired values of the data access timestamp.
            data-access-timestamp: new-timestamp,
            /// The desired values of the data modification timestamp.
            data-modification-timestamp: new-timestamp,
        ) -> result<_, error-code>;

        /// Create a hard link.
        ///
        /// Note: This is similar to `linkat` in POSIX.
        @since(version = 0.2.0)
        link-at: func(
            /// Flags determining the method of how the path is resolved.
            old-path-flags: path-flags,
            /// The relative source path from which to link.
            old-path: string,
            /// The base directory for `new-path`.
            new-descriptor: borrow<descriptor>,
            /// The relative destination path at which to create the hard link.
            new-path: string,
        ) -> result<_, error-code>;

        /// Open a file or directory.
        ///
        /// If `flags` contains `descriptor-flags::mutate-directory`, and the base
        /// descriptor doesn't have `descriptor-flags::mutate-directory` set,
        /// `open-at` fails with `error-code::read-only`.
        ///
        /// If `flags` contains `write` or `mutate-directory`, or `open-flags`
        /// contains `truncate` or `create`, and the base descriptor doesn't have
        /// `descriptor-flags::mutate-directory` set, `open-at` fails with
        /// `error-code::read-only`.
        ///
        /// Note: This is similar to `openat` in POSIX.
        @since(version = 0.2.0)
        open-at: func(
            /// Flags determining the method of how the path is resolved.
            path-flags: path-flags,
            /// The relative path of the object to open.
            path: string,
            /// The method by which to open the file.
            open-flags: open-flags,
            /// Flags to use for the resulting descriptor.
            %flags: descriptor-flags,
        ) -> result<descriptor, error-code>;

        /// Read the contents of a symbolic link.
        ///
        /// If the contents contain an absolute or rooted path in the underlying
        /// filesystem, this function fails with `error-code::not-permitted`.
        ///
        /// Note: This is similar to `readlinkat` in POSIX.
        @since(version = 0.2.0)
        readlink-at: func(
            /// The relative path of the symbolic link from which to read.
            path: string,
        ) -> result<string, error-code>;

        /// Remove a directory.
        ///
        /// Return `error-code::not-empty` if the directory is not empty.
        ///
        /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX.
        @since(version = 0.2.0)
        remove-directory-at: func(
            /// The relative path to a directory to remove.
            path: string,
        ) -> result<_, error-code>;

        /// Rename a filesystem object.
        ///
        /// Note: This is similar to `renameat` in POSIX.
        @since(version = 0.2.0)
        rename-at: func(
            /// The relative source path of the file or directory to rename.
            old-path: string,
            /// The base directory for `new-path`.
            new-descriptor: borrow<descriptor>,
            /// The relative destination path to which to rename the file or directory.
            new-path: string,
        ) -> result<_, error-code>;

        /// Create a symbolic link (also known as a "symlink").
        ///
        /// If `old-path` starts with `/`, the function fails with
        /// `error-code::not-permitted`.
        ///
        /// Note: This is similar to `symlinkat` in POSIX.
        @since(version = 0.2.0)
        symlink-at: func(
            /// The contents of the symbolic link.
            old-path: string,
            /// The relative destination path at which to create the symbolic link.
            new-path: string,
        ) -> result<_, error-code>;

        /// Unlink a filesystem object that is not a directory.
        ///
        /// Return `error-code::is-directory` if the path refers to a directory.
        /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX.
        @since(version = 0.2.0)
        unlink-file-at: func(
            /// The relative path to a file to unlink.
            path: string,
        ) -> result<_, error-code>;

        /// Test whether two descriptors refer to the same filesystem object.
        ///
        /// In POSIX, this corresponds to testing whether the two descriptors have the
        /// same device (`st_dev`) and inode (`st_ino` or `d_ino`) numbers.
        /// wasi-filesystem does not expose device and inode numbers, so this function
        /// may be used instead.
        @since(version = 0.2.0)
        is-same-object: func(other: borrow<descriptor>) -> bool;

        /// Return a hash of the metadata associated with a filesystem object referred
        /// to by a descriptor.
        ///
        /// This returns a hash of the last-modification timestamp and file size, and
        /// may also include the inode number, device number, birth timestamp, and
        /// other metadata fields that may change when the file is modified or
        /// replaced. It may also include a secret value chosen by the
        /// implementation and not otherwise exposed.
        ///
        /// Implementations are encouraged to provide the following properties:
        ///
        ///  - If the file is not modified or replaced, the computed hash value should
        ///    usually not change.
        ///  - If the object is modified or replaced, the computed hash value should
        ///    usually change.
        ///  - The inputs to the hash should not be easily computable from the
        ///    computed hash.
        ///
        /// However, none of these is required.
        @since(version = 0.2.0)
        metadata-hash: func() -> result<metadata-hash-value, error-code>;

        /// Return a hash of the metadata associated with a filesystem object referred
        /// to by a directory descriptor and a relative path.
        ///
        /// This performs the same hash computation as `metadata-hash`.
        @since(version = 0.2.0)
        metadata-hash-at: func(
            /// Flags determining the method of how the path is resolved.
            path-flags: path-flags,
            /// The relative path of the file or directory to inspect.
            path: string,
        ) -> result<metadata-hash-value, error-code>;
    }

    /// A stream of directory entries.
    @since(version = 0.2.0)
    resource directory-entry-stream {
        /// Read a single directory entry from a `directory-entry-stream`.
        @since(version = 0.2.0)
        read-directory-entry: func() -> result<option<directory-entry>, error-code>;
    }

    /// Attempts to extract a filesystem-related `error-code` from the stream
    /// `error` provided.
    ///
    /// Stream operations which return `stream-error::last-operation-failed`
    /// have a payload with more information about the operation that failed.
    /// This payload can be passed through to this function to see if there's
    /// filesystem-related information about the error to return.
    ///
    /// Note that this function is fallible because not all stream-related
    /// errors are filesystem-related errors.
    @since(version = 0.2.0)
    filesystem-error-code: func(err: borrow<error>) -> option<error-code>;
}
