componentized/directory

componentized:filesystem

interface dev

A collection of utility components that remix wasi:filesystem types and interfaces.

Interfaces

  • latch since 0.3.0-dev — Access control for `wasi:filesystem`.

Worlds

WIT

package componentized:filesystem@0.3.0-dev;

/// Access control for `wasi:filesystem`.
///
/// A gate consults a latch before performing each filesystem operation. The latch either defers,
/// raising no objection, or denies the operation. A latch never grants an operation, an
/// operation proceeds when the latch defers. Several latches can be aggregated into one, the
/// operation is denied when any of them denies it.
///
/// Deciding and acting on a decision are separate steps. `authorize` decides without side
/// effects, then the gate reports the final decision to `observe-decision`, where a latch updates
/// any state it keeps. A latch aggregated with others may not be asked to authorize an operation
/// another latch already denied, but it always observes the final decision.
@since(version = 0.3.0-dev)
interface latch {
  @since(version = 0.3.0-dev)
  use wasi:filesystem/types@0.3.0.{advice, descriptor, descriptor-flags, directory-entry, error-code as filesystem-error-code, filesize, open-flags, new-timestamp, path-flags};

  /// The path of a descriptor, the directory or file an operation is performed on, and that the
  /// relative path arguments of the operation are resolved against.
  ///
  /// A preopen is labeled with its name, e.g. `/` or `.`. A descriptor opened with `open-at` is
  /// labeled with the path it was opened at, joined to the path of the descriptor it was opened
  /// from: `.` and `..` are applied, and symlinks are followed where the host follows them.
  /// Path arguments of an operation are passed as given by the caller, relative to the
  /// descriptor's path.
  @since(version = 0.3.0-dev)
  type path = string;

  /// Arguments to wasi:filesystem/types#descriptor.read-via-stream.
  @since(version = 0.3.0-dev)
  record descriptor-read-via-stream-args {
    /// The offset in the file to start reading at.
    offset: filesize,
  }

  /// Arguments to wasi:filesystem/types#descriptor.write-via-stream.
  @since(version = 0.3.0-dev)
  record descriptor-write-via-stream-args {
    /// The offset in the file to start writing at.
    offset: filesize,
  }

  /// Arguments to wasi:filesystem/types#descriptor.advise.
  @since(version = 0.3.0-dev)
  record descriptor-advise-args {
    /// The offset of the range the advice applies to.
    offset: filesize,
    /// The length of the range the advice applies to.
    length: filesize,
    /// The advice for the range.
    advice: advice,
  }

  /// Arguments to wasi:filesystem/types#descriptor.set-size.
  @since(version = 0.3.0-dev)
  record descriptor-set-size-args {
    /// The new size of the file.
    size: filesize,
  }

  /// Arguments to wasi:filesystem/types#descriptor.set-times.
  @since(version = 0.3.0-dev)
  record descriptor-set-times-args {
    /// The new access time.
    data-access-timestamp: new-timestamp,
    /// The new modification time.
    data-modification-timestamp: new-timestamp,
  }

  /// Arguments to wasi:filesystem/types#descriptor.create-directory-at.
  @since(version = 0.3.0-dev)
  record descriptor-create-directory-at-args {
    /// The directory to create, relative to the descriptor's path.
    path: path,
  }

  /// Arguments to wasi:filesystem/types#descriptor.stat-at.
  @since(version = 0.3.0-dev)
  record descriptor-stat-at-args {
    /// Whether a symlink at the last component of the path is followed.
    path-flags: path-flags,
    /// The file or directory to stat, relative to the descriptor's path.
    path: path,
  }

  /// Arguments to wasi:filesystem/types#descriptor.set-times-at.
  @since(version = 0.3.0-dev)
  record descriptor-set-times-at-args {
    /// Whether a symlink at the last component of the path is followed.
    path-flags: path-flags,
    /// The file or directory to change, relative to the descriptor's path.
    path: path,
    /// The new access time.
    data-access-timestamp: new-timestamp,
    /// The new modification time.
    data-modification-timestamp: new-timestamp,
  }

  /// Arguments to wasi:filesystem/types#descriptor.link-at.
  @since(version = 0.3.0-dev)
  record descriptor-link-at-args {
    /// Whether a symlink at the last component of the old path is followed.
    old-path-flags: path-flags,
    /// The existing file to link to, relative to the descriptor's path.
    old-path: path,
    /// The directory the new path is relative to, a latch may query it.
    new-descriptor: borrow<descriptor>,
    /// The link to create, relative to the new descriptor.
    new-path: path,
  }

  /// Arguments to wasi:filesystem/types#descriptor.open-at.
  @since(version = 0.3.0-dev)
  record descriptor-open-at-args {
    /// Whether a symlink at the last component of the path is followed.
    path-flags: path-flags,
    /// The file or directory to open, relative to the descriptor's path.
    path: path,
    /// How the file or directory is opened, e.g. whether it is created or truncated.
    open-flags: open-flags,
    /// What the opened descriptor may be used for, e.g. reading, writing or changing a
    /// directory.
    %flags: descriptor-flags,
  }

  /// Arguments to wasi:filesystem/types#descriptor.readlink-at.
  @since(version = 0.3.0-dev)
  record descriptor-readlink-at-args {
    /// The symlink to read, relative to the descriptor's path.
    path: path,
  }

  /// Arguments to wasi:filesystem/types#descriptor.remove-directory-at.
  @since(version = 0.3.0-dev)
  record descriptor-remove-directory-at-args {
    /// The directory to remove, relative to the descriptor's path.
    path: path,
  }

  /// Arguments to wasi:filesystem/types#descriptor.rename-at.
  @since(version = 0.3.0-dev)
  record descriptor-rename-at-args {
    /// The file or directory to rename, relative to the descriptor's path.
    old-path: path,
    /// The directory the new path is relative to, a latch may query it.
    new-descriptor: borrow<descriptor>,
    /// The new path, relative to the new descriptor.
    new-path: path,
  }

  /// Arguments to wasi:filesystem/types#descriptor.symlink-at.
  @since(version = 0.3.0-dev)
  record descriptor-symlink-at-args {
    /// The contents of the symlink, the path it points to. It is not resolved by the gate.
    old-path: path,
    /// The symlink to create, relative to the descriptor's path.
    new-path: path,
  }

  /// Arguments to wasi:filesystem/types#descriptor.unlink-file-at.
  @since(version = 0.3.0-dev)
  record descriptor-unlink-file-at-args {
    /// The file to unlink, relative to the descriptor's path.
    path: path,
  }

  /// Arguments to wasi:filesystem/types#descriptor.metadata-hash-at.
  @since(version = 0.3.0-dev)
  record descriptor-metadata-hash-at-args {
    /// Whether a symlink at the last component of the path is followed.
    path-flags: path-flags,
    /// The file or directory to hash, relative to the descriptor's path.
    path: path,
  }

  /// Operations of the wasi:filesystem/preopens interface.
  @since(version = 0.3.0-dev)
  variant preopens-operation {
    /// Authorized before the preopens are returned. A denial returns no preopens.
    get-directories,
    /// Authorized for each preopen, with its name. A denied preopen is left out of the
    /// preopens returned, the other preopens are still returned.
    get-directories-item(tuple<borrow<descriptor>, path>),
  }

  /// Operations of the wasi:filesystem/types#descriptor resource.
  ///
  /// The borrowed descriptor is the descriptor the operation is performed on, followed by its
  /// path, a latch may query the descriptor, for example for its type or flags. A denial fails
  /// the operation with the denial's error code, unless noted otherwise.
  @since(version = 0.3.0-dev)
  variant descriptor-operation {
    /// Authorized before reading a file. A denial returns an empty stream, the future
    /// resolves to the error code.
    read-via-stream(tuple<borrow<descriptor>, path, descriptor-read-via-stream-args>),
    /// Authorized before writing a file. A denial reads nothing from the stream, the future
    /// resolves to the error code.
    write-via-stream(tuple<borrow<descriptor>, path, descriptor-write-via-stream-args>),
    /// Authorized before appending to a file. A denial reads nothing from the stream, the
    /// future resolves to the error code.
    append-via-stream(tuple<borrow<descriptor>, path>),
    /// Authorized before giving advice for a file.
    advise(tuple<borrow<descriptor>, path, descriptor-advise-args>),
    /// Authorized before syncing the data of a file.
    sync-data(tuple<borrow<descriptor>, path>),
    /// Authorized before reading the flags of a descriptor.
    get-flags(tuple<borrow<descriptor>, path>),
    /// Authorized before reading the type of a descriptor.
    get-type(tuple<borrow<descriptor>, path>),
    /// Authorized before changing the size of a file.
    set-size(tuple<borrow<descriptor>, path, descriptor-set-size-args>),
    /// Authorized before changing the times of a file or directory.
    set-times(tuple<borrow<descriptor>, path, descriptor-set-times-args>),
    /// Authorized before reading a directory. A denial returns an empty stream, the future
    /// resolves to the error code.
    read-directory(tuple<borrow<descriptor>, path>),
    /// Authorized for each entry of a directory being read. A denied entry is left out of the
    /// stream, the other entries are still returned.
    read-directory-entry(tuple<borrow<descriptor>, path, directory-entry>),
    /// Authorized before syncing the data and metadata of a file or directory.
    sync(tuple<borrow<descriptor>, path>),
    /// Authorized before creating a directory.
    create-directory-at(tuple<borrow<descriptor>, path, descriptor-create-directory-at-args>),
    /// Authorized before reading the attributes of a file or directory.
    stat(tuple<borrow<descriptor>, path>),
    /// Authorized before reading the attributes of a file or directory at a path.
    stat-at(tuple<borrow<descriptor>, path, descriptor-stat-at-args>),
    /// Authorized before changing the times of a file or directory at a path.
    set-times-at(tuple<borrow<descriptor>, path, descriptor-set-times-at-args>),
    /// Authorized before creating a hard link.
    link-at(tuple<borrow<descriptor>, path, descriptor-link-at-args>),
    /// Authorized before opening a file or directory.
    open-at(tuple<borrow<descriptor>, path, descriptor-open-at-args>),
    /// Authorized before reading the contents of a symlink.
    readlink-at(tuple<borrow<descriptor>, path, descriptor-readlink-at-args>),
    /// Authorized before removing a directory.
    remove-directory-at(tuple<borrow<descriptor>, path, descriptor-remove-directory-at-args>),
    /// Authorized before renaming a file or directory.
    rename-at(tuple<borrow<descriptor>, path, descriptor-rename-at-args>),
    /// Authorized before creating a symlink.
    symlink-at(tuple<borrow<descriptor>, path, descriptor-symlink-at-args>),
    /// Authorized before unlinking a file.
    unlink-file-at(tuple<borrow<descriptor>, path, descriptor-unlink-file-at-args>),
    /// Authorized before hashing the metadata of a file or directory.
    metadata-hash(tuple<borrow<descriptor>, path>),
    /// Authorized before hashing the metadata of a file or directory at a path.
    metadata-hash-at(tuple<borrow<descriptor>, path, descriptor-metadata-hash-at-args>),
  }

  /// Operations of the wasi:filesystem package a gate asks a latch to authorize.
  @since(version = 0.3.0-dev)
  variant operation {
    /// An operation of wasi:filesystem/preopens.
    preopens(preopens-operation),
    /// An operation on a wasi:filesystem/types#descriptor.
    descriptor(descriptor-operation),
  }

  /// Whether the operation is allowed to proceed.
  @since(version = 0.3.0-dev)
  variant decision {
    /// The latch raises no objection, the operation proceeds unless another latch denies it.
    deferred,
    /// The operation must not proceed. The error code is returned to the caller for
    /// operations that fail. For items that are left out instead, a preopen or a directory
    /// entry, it is only logged.
    denied(filesystem-error-code),
  }

  /// The name of a latch component, identifying which latch reported an error.
  @since(version = 0.3.0-dev)
  type latch-name = string;

  /// A latch was unable to decide or observe. The gate fails the operation, a directory entry
  /// fails the directory read. Getting the preopens can't fail, the gate traps instead.
  @since(version = 0.3.0-dev)
  variant error-code {
    /// The latch's configuration is invalid, the cause is logged by the latch.
    invalid-config(latch-name),
    /// The latch was unable to act on the final decision.
    observation-failed(latch-name),
    /// Any other error.
    other(option<string>),
  }

  /// Decide whether the operation may proceed.
  ///
  /// Must not have side effects. When latches are aggregated, a latch is not asked about an
  /// operation another latch already denied, so state changed here could disagree with what
  /// actually happened. Act on decisions in `observe-decision` instead.
  @since(version = 0.3.0-dev)
  authorize: func(operation: operation) -> result<decision, error-code>;

  /// Observe the final decision for an operation, after `authorize` returned a decision.
  ///
  /// Called for both deferred and denied operations, including operations this latch was not
  /// asked to authorize because an aggregated latch denied them first. The final decision is
  /// what the gate enforces, so this is where a latch updates any state it keeps. Not called
  /// when `authorize` returned an error.
  ///
  /// An error fails the operation, since the latch could not act on the decision.
  @since(version = 0.3.0-dev)
  observe-decision: func(final-decision: decision, operation: operation) -> result<_, error-code>;
}

world imports {
  import wasi:clocks/types@0.3.0;
  import wasi:clocks/system-clock@0.3.0;
  import wasi:filesystem/types@0.3.0;
  import latch;
}