blob: f320c87fa8b7d1fedbe3ff125327bf5a66ac0733 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library fuchsia.io;
using zx;
// TODO: We should run some experiments to see what's the optimum value, or
// what's the point of diminishing marginal returns.
/// The maximum I/O size that is allowed for read/write operations using
/// byte vectors.
const MAX_TRANSFER_SIZE uint64 = 8192;
/// The byte vector type used for read/write operations.
alias Transfer = vector<uint8>:MAX_TRANSFER_SIZE;
/// Denotes which hash algorithm is used to build the merkle tree for
/// fsverity-enabled files.
@available(added=HEAD)
type HashAlgorithm = flexible enum : uint8 {
SHA256 = 1;
SHA512 = 2;
};
/// Set of options used to enable verity on a file.
@available(added=HEAD)
type VerificationOptions = table {
1: hash_algorithm HashAlgorithm;
/// `salt` is prepended to each block before it is hashed.
2: salt vector<uint8>:32;
};
/// Auxiliary data for the file representation of a node.
type FileInfo = resource table {
/// True if the file is opened in append mode.
/// In append mode, the seek offset is moved to the end before every
/// write, the two steps performed in an atomic manner.
1: is_append bool;
/// An optional event which transmits information about an object's
/// readability or writability. This event relays information about the
/// underlying object, not the capability granted to client: this event
/// may be signalled "readable" on a connection that does not have
/// the capability to read.
///
/// This event will be present if the following conditions are met:
///
/// - The `available_operations` on the file connection is not empty.
/// - The filesystem supports signalling readability/writability events.
///
/// The [`FileSignal`] values may be observed on this event.
2: observer zx.Handle:EVENT;
/// An optional stream object, which can be used to read to and write from
/// the file.
///
/// Reading and writing the file using the stream object can be up to 20x
/// faster than reading and writing the file using the Read and Write
/// operations in the [`File`] protocol.
3: stream zx.Handle:STREAM;
/// Requested attributes for the file. This is only populated if requested.
@available(added=18)
4: attributes NodeAttributes2;
};
// TODO(https://fxbug.dev/42056856): Use a generated constant.
const FILE_PROTOCOL_NAME string = "fuchsia.io/File";
/// A [`Node`] which contains a sequence of bytes of definite length.
///
/// NOTE: cloned connections do not share their seek offset with their source
/// connection.
closed protocol File {
compose AdvisoryLocking;
@available(added=18)
compose Linkable;
compose Node;
compose Readable;
compose Writable;
@selector("fuchsia.io/File.Describe")
strict Describe() -> (FileInfo);
/// Moves the offset at which the next invocation of [`Read`] or [`Write`]
/// will occur. The seek offset is specific to each file connection.
///
/// + request `origin` the reference point where `offset` will be based on.
/// + request `offset` the number of bytes to seek.
/// - response `offset_from_start` the adjusted seek offset, from the start
/// of the file.
///
/// This method does not require any rights.
@selector("fuchsia.io/File.Seek")
strict Seek(struct {
origin SeekOrigin;
offset int64;
}) -> (struct {
offset_from_start uint64;
}) error zx.Status;
/// Reads up to 'count' bytes at the provided offset.
/// Does not affect the seek offset.
///
/// ## Invariants
///
/// * The returned `data.length` will never be greater than `count`.
/// * If `data.length` is less than `count`, it means that `ReadAt` has hit
/// the end of file as part of this operation.
/// * If `data.length` is zero while `count` is not, it means that `offset`
/// is at or past the end of file, and no data can be read.
/// * If `count` is zero, the server should perform all the checks ensuring
/// read access without actually reading anything, and return an empty
/// `data` vector.
///
/// This method requires the [`Rights.READ_BYTES`] right.
///
/// Returns `ZX_ERR_OUT_OF_RANGE` if `count` is greater than `MAX_TRANSFER_SIZE`.
@selector("fuchsia.io/File.ReadAt")
strict ReadAt(struct {
count uint64;
offset uint64;
}) -> (struct {
data Transfer;
}) error zx.Status;
/// Writes data at the provided offset.
/// Does not affect the seek offset.
///
/// The file size may grow if `offset` plus `data.length` is past the
/// current end of file.
///
/// + request `data` the byte buffer to write to the file.
/// + request `offset` the offset from start of the file to begin writing.
/// - response `actual_count` the number of bytes written.
///
/// ## Invariants
///
/// * The returned `actual_count` will never be greater than `data.length`.
/// * If the server is unable to write all the data due to e.g. not enough
/// space, `actual_count` may be less than `data.length`. If no bytes
/// could be written, an error is returned.
/// * If `data.length` is zero, the server should perform all the checks
/// ensuring write access without mutating the file, and will return a
/// successful write of zero bytes.
///
/// This method requires the [`Rights.WRITE_BYTES`] right.
@selector("fuchsia.io/File.WriteAt")
strict WriteAt(struct {
data Transfer;
offset uint64;
}) -> (struct {
actual_count uint64;
}) error zx.Status;
/// Shrinks or grows the file size to 'length' bytes.
///
/// If file size is reduced by this operation, the extra trailing data'
/// is discarded.
/// If file size is increased by this operation, the extended area appears
/// as if it was zeroed.
///
/// This method requires the [`Rights.WRITE_BYTES`] right.
@selector("fuchsia.io/File.Resize")
strict Resize(struct {
length uint64;
}) -> () error zx.Status;
/// Acquires a [`zx.Handle:VMO`] representing this file, if there is one,
/// with the requested access rights.
///
/// Implementations are not required to implement files backed by VMOs so
/// this request may fail. Additionally, implementations may only support
/// a certain subset of the flags. Clients should be prepared with fallback
/// behavior if this request fails.
///
/// If a client specifies neither `PRIVATE_CLONE` nor `SHARED_BUFFER`, the
/// implementation is free to choose the semantics of the returned VMO.
///
/// + request `flags` a [`VmoFlags`] indicating the desired mode of access.
/// - response `vmo` the requested [`zx.Handle:VMO`].
/// * error a [`zx.Status`] value indicating the failure.
///
/// This method requires the following rights:
///
/// * [`Rights.READ_BYTES`] if `flags` includes [`VmoFlags.READ`].
/// * [`Rights.WRITE_BYTES`] if `flags` includes [`VmoFlags.WRITE`].
/// * [`Rights.EXECUTE`] if `flags` includes [`VmoFlags.EXECUTE`].
@selector("fuchsia.io/File.GetBackingMemory")
strict GetBackingMemory(struct {
flags @generated_name("VmoFlags") strict bits : uint32 {
/// Requests that the VMO be readable.
READ = 0x00000001;
/// Requests that the VMO be writable.
WRITE = 0x00000002;
/// Request that the VMO be executable.
EXECUTE = 0x00000004;
/// Require a copy-on-write clone of the underlying VMO. The request
/// should fail if the VMO cannot be cloned. May not be supplied
/// with `SHARED_BUFFER`.
///
/// A private clone uses at least the guarantees of the
/// `ZX_VMO_CHILD_SNAPSHOT_AT_LEAST_ON_WRITE` flag to
/// `zx_vmo_create_child()`. This means that the returned VMO will
/// be copy-on-write (if `WRITE` is requested) but that it may or
/// may not reflect subsequent content changes to the underlying
/// file. The returned VMO will not reflect size changes to the
/// file. These semantics match those of the POSIX `mmap()`
/// `MAP_PRIVATE` flag.
///
/// In some cases, clients requiring a guaranteed snapshot of the
/// file can use `SHARED_BUFFER` and then use
/// `zx_vmo_create_child()` with `ZX_VMO_CHILD_SNAPSHOT`. However,
/// in addition to cases where the implementation can't return a
/// `SHARED_BUFFER`, creating a full snapshot will fail if the VMO
/// is attached to the pager. Since most filesystems will use the
/// paging system, the full snapshot approach should only be used in
/// specific cases where the client is talking to a known server.
PRIVATE_CLONE = 0x00010000;
/// Require a VMO that provides direct access to the contents of the
/// file's underlying VMO. The request should fail if such a VMO
/// cannot be provided. May not be supplied with `PRIVATE_CLONE`.
///
/// The returned VMO may not be resizable even when `WRITE` access is
/// requested. In this case, [`File.Resize`] should be used to resize
/// the file.
SHARED_BUFFER = 0x00020000;
};
}) -> (resource struct {
vmo zx.Handle:VMO;
}) error zx.Status;
/// Pre-allocate on-disk space for this file.
@available(added=HEAD)
@selector("fuchsia.io/File.Allocate")
strict Allocate(resource struct {
offset uint64;
length uint64;
/// If an empty bits is passed for mode, the default behavior is used. Otherwise the
/// behavior is modified as described for each mode bit. If the backing filesystem doesn't
/// support a particular provided mode bit, or combination of mode bits, an error is
/// returned.
mode @generated_name("AllocateMode") flexible bits : uint32 {
KEEP_SIZE = 0x00000001;
UNSHARE_RANGE = 0x00000002;
PUNCH_HOLE = 0x00000004;
COLLAPSE_RANGE = 0x00000008;
ZERO_RANGE = 0x00000010;
INSERT_RANGE = 0x00000020;
};
}) -> () error zx.Status;
/// Enables verification for the file (permanently) which involves computing a merkle tree for
/// the file. Forces a flush prior to building the merkle tree to ensure cached data is
/// captured. Future reads will be verified against the computed merkle tree and writes will be
/// rejected. This method can take some time to complete as it depends on the size of the file.
/// This method can be aborted by closing the connection that this method was issued on.
///
/// This method requires the [`Rights.UPDATE_ATTRIBUTES`] right.
/// Returns `ZX_ERR_NOT_SUPPORTED` if the filesystem does not support verity.
/// Returns `ZX_ERR_ALREADY_EXISTS` if the file was already fsverity-enabled.
/// Also returns any error that might arise from reading the file, or from flushing the file,
/// such as `ZX_ERR_IO`.
@selector("fuchsia.io/File.EnableVerity")
@available(added=HEAD)
strict EnableVerity(resource struct {
options VerificationOptions;
}) -> () error zx.Status;
};
closed protocol Readable {
/// Reads up to 'count' bytes at the seek offset.
/// The seek offset is moved forward by the number of bytes read.
///
/// ## Invariants
///
/// * The returned `data.length` will never be greater than `count`.
/// * If `data.length` is less than `count`, it means that the seek offset
/// has reached the end of file as part of this operation.
/// * If `data.length` is zero while `count` is not, it means that the
/// seek offset is already at or beyond the end of file, and no data could
/// be read.
/// * If `count` is zero, the server should perform all the checks ensuring
/// read access without actually read anything, and return an empty
/// `data` vector.
///
/// This method requires the [`Rights.READ_BYTES`] right.
///
/// Returns `ZX_ERR_OUT_OF_RANGE` if `count` is greater than `MAX_TRANSFER_SIZE`.
@selector("fuchsia.io/File.Read")
strict Read(struct {
count uint64;
}) -> (struct {
data Transfer;
}) error zx.Status;
};
closed protocol Writable {
/// Writes data at the seek offset.
/// The seek offset is moved forward by the number of bytes written.
/// If the file is in append mode, the seek offset is first set to the end
/// of the file, followed by the write, in one atomic step.
///
/// The file size may grow if the seek offset plus `data.length` is beyond
/// the current end of file.
///
/// + request `data` the byte buffer to write to the file.
/// - response `actual_count` the number of bytes written.
///
/// ## Invariants
///
/// * The returned `actual_count` will never be greater than `data.length`.
/// * If the server is unable to write all the data due to e.g. not enough
/// space, `actual_count` may be less than `data.length`. If no bytes
/// could be written, an error is returned.
/// * If `data.length` is zero, the server should perform all the checks
/// ensuring write access without mutating the file and return a
/// successful write of zero bytes. The seek offset is still updated if
/// in append mode.
///
/// This method requires the [`Rights.WRITE_BYTES`] right.
@selector("fuchsia.io/File.Write")
strict Write(struct {
data Transfer;
}) -> (struct {
actual_count uint64;
}) error zx.Status;
};
/// The reference point for updating the seek offset. See [`File.Seek`].
///
/// This enum matches the `zx_stream_seek_origin_t` enum.
type SeekOrigin = strict enum : uint32 {
/// Seek from the start of the file.
/// The seek offset will be set to `offset` bytes.
/// The seek offset cannot be negative in this case.
START = 0;
/// Seek from the current position in the file.
/// The seek offset will be the current seek offset plus `offset` bytes.
CURRENT = 1;
/// Seek from the end of the file.
/// The seek offset will be the file size plus `offset` bytes.
END = 2;
};
type FileSignal = strict bits : uint32 {
/// Indicates the file is ready for reading.
READABLE = 0x01000000; // ZX_USER_SIGNAL_0
/// Indicates the file is ready for writing.
WRITABLE = 0x02000000; // ZX_USER_SIGNAL_1
};