| // Copyright 2018 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; |
| |
| type OpenFlags = strict bits : uint32 { |
| /// Can read from target object. |
| RIGHT_READABLE = 0x00000001; |
| /// Can write to target object. |
| RIGHT_WRITABLE = 0x00000002; |
| /// Connection can map target object executable. |
| RIGHT_EXECUTABLE = 0x00000008; |
| |
| /// Create the object if it doesn't exist. |
| CREATE = 0x00010000; |
| /// (with Create) Fail if the object already exists. |
| CREATE_IF_ABSENT = 0x00020000; |
| /// Truncate the object before usage. |
| TRUNCATE = 0x00040000; |
| /// Assert that the object to be opened is a directory. |
| /// Return an error if the target object is not a directory. |
| DIRECTORY = 0x00080000; |
| /// Seek to the end of the object before all writes. |
| APPEND = 0x00100000; |
| /// Open a reference to the object, not the object itself. |
| /// It is ONLY valid to pass the following flags together with `NODE_REFERENCE`: |
| /// - `DIRECTORY` |
| /// - `NOT_DIRECTORY` |
| /// - `DESCRIBE` |
| /// otherwise an error is returned. |
| /// If an object is opened or cloned using this method, the resulting connection does not carry |
| /// any permission flags. |
| /// The resulting connection allows a limited set of operations: `GetAttr`, `Clone`, `Close`, |
| /// `Describe`, and `GetFlags`. The connection will speak the `Node` protocol. Calling `SetAttr` |
| /// or `SetFlags` will result in `ZX_ERR_BAD_HANDLE`. |
| NODE_REFERENCE = 0x00400000; |
| /// Requests that an "OnOpen" event is sent to the interface request. |
| /// |
| /// The event will contain a non-null `NodeInfoDeprecated` if the open/clone is successful. This |
| /// can be used to open a protocol that does not compose fuchsia.io/Node; the event is sent as |
| /// if the protocol is fuchsia.io/Node and then the target protocol is used exclusively. |
| DESCRIBE = 0x00800000; |
| /// Specify this flag to request POSIX-compatibility with respect to write permission handling. |
| /// Currently, it affects permission handling specifically during Open: |
| /// - If the target path is a directory, the rights on the new connection expand to include |
| /// `WRITABLE` if and only if the current connection and all intermediate mount points |
| /// are writable. |
| /// - Otherwise, this flag is ignored. It is an access denied error to request more rights |
| /// than those on the current connection, or any intermediate mount points. |
| /// |
| /// If this flag is omitted, opening always uses the requested rights, failing the operation with |
| /// access denied error if requested rights exceeds the rights attached to the current connection. |
| /// |
| /// If the requesting connection is read-only and the requested rights are read-only, the flag |
| /// may be ignored by the server, and is not forwarded downstream. This is an implementation detail, |
| /// necessary to enforce hierarchical permissions across mount points, and should have no effect |
| /// on the expected behavior for clients. |
| POSIX_WRITABLE = 0x08000000; |
| /// Specify this flag to request POSIX-compatibility with respect to execute permission handling. |
| /// Currently, it affects permission handling specifically during Open: |
| /// - If the target path is a directory, the rights on the new connection expand to include |
| /// `EXECUTABLE` if and only if the current connection and all intermediate mount |
| /// points are executable. |
| /// - Otherwise, this flag is ignored. It is an access denied error to request more rights |
| /// than those on the current connection, or any intermediate mount points. |
| /// |
| /// If this flag is omitted, opening always uses the requested rights, failing the operation with |
| /// access denied error if requested rights exceeds the rights attached to the current connection. |
| /// |
| /// If the requesting connection is read-only and the requested rights are read-only, the flag |
| /// may be ignored by the server, and is not forwarded downstream. This is an implementation detail, |
| /// necessary to enforce hierarchical permissions across mount points, and should have no effect |
| /// on the expected behavior for clients. |
| POSIX_EXECUTABLE = 0x10000000; |
| /// Assert that the object to be opened is not a directory. |
| /// Return an error if the target object is a directory. |
| NOT_DIRECTORY = 0x02000000; |
| |
| /// When used during clone, the new connection inherits the rights on the source connection, |
| /// regardless if it is a file or directory. Otherwise, clone attempts to use the requested rights. |
| /// It is invalid to pass any of the `RIGHT_*` flags together with `OpenFlags.CLONE_SAME_RIGHTS`. |
| CLONE_SAME_RIGHTS = 0x04000000; |
| |
| /// Open the target object as a block device. |
| // TODO(https://fxbug.dev/120898): this form of protocol negotiation is unprincipled. |
| BLOCK_DEVICE = 0x01000000; |
| }; |
| |
| /// All known rights. |
| const OPEN_RIGHTS OpenFlags |
| = OpenFlags.RIGHT_READABLE | OpenFlags.RIGHT_WRITABLE | OpenFlags.RIGHT_EXECUTABLE; |
| |
| /// Flags used when opening a node reference must fall within this mask. |
| const OPEN_FLAGS_ALLOWED_WITH_NODE_REFERENCE OpenFlags |
| = OpenFlags.DIRECTORY | OpenFlags.NOT_DIRECTORY | OpenFlags.DESCRIBE | OpenFlags.NODE_REFERENCE; |
| |
| type ModeType = flexible bits : uint32 {}; |
| |
| /// The maximal buffer size which can be transmitted for buffered operations. |
| /// This capacity is currently set somewhat arbitrarily. |
| const MAX_BUF uint64 = 8192; |
| /// The maximum length, in bytes, of a filesystem string. |
| @available(deprecated=11, removed=12, note="Use MAX_PATH_LENGTH or Path (for strings) instead.") |
| const MAX_PATH uint64 = 4096; |
| /// The maximum length, in bytes, of a single filesystem component. |
| const MAX_FILENAME uint64 = 255; |
| |
| // Dirent type information associated with the results of ReadDirents. |
| // The following values are aligned with the values from libc's "dirent.h" "DT_...". |
| type DirentType = strict enum : uint8 { |
| /// A dirent with an unknown type. |
| UNKNOWN = 0; |
| /// A dirent representing a directory object. |
| DIRECTORY = 4; |
| /// A dirent representing a block device object. |
| BLOCK_DEVICE = 6; |
| /// A dirent representing a file object. |
| FILE = 8; |
| /// A symbolic link. |
| @available(added=HEAD) |
| SYMLINK = 10; |
| /// A dirent representing a service object. |
| SERVICE = 16; |
| }; |
| |
| /// Nodes which do not have ino values should return this value |
| /// from Readdir and GetAttr. |
| const INO_UNKNOWN uint64 = 0xFFFFFFFFFFFFFFFF; |
| |
| /// DirectoryWatcher transmits messages from a filesystem server |
| /// about events happening in the filesystem. Clients can register |
| /// new watchers using the `Directory.Watch` method, where they can |
| /// filter which events they want to receive notifications for. |
| /// |
| /// The DirectoryWatcher will send messages of the form: |
| /// ``` |
| /// struct { |
| /// uint8 event; |
| /// uint8 len; |
| /// char name[]; |
| /// }; |
| /// ``` |
| /// Where names are NOT null-terminated. The name is the relative |
| /// path to the entry the event is refering to. It will be empty if |
| /// the event isn't referencing a particular entry (e.g. for the |
| /// `IDLE` event). |
| protocol DirectoryWatcher {}; |
| |
| type WatchEvent = strict enum : uint8 { |
| /// Indicates the directory being watched has been deleted. The name returned for this event |
| /// will be `.` (dot), as it is refering to the directory itself. |
| DELETED = 0; |
| /// Indicates a node has been created (either new or moved) into a directory. |
| ADDED = 1; |
| /// Identifies a node has been removed (either deleted or moved) from the directory. |
| REMOVED = 2; |
| /// Identifies a node already existed in the directory when watching started. |
| EXISTING = 3; |
| /// Identifies that no more `EXISTING` events will be sent. The name returned for this event |
| /// will be empty, as it is not refering to a specific entry. |
| IDLE = 4; |
| }; |
| |
| type WatchMask = strict bits : uint32 { |
| /// Used by `Directory.Watch`. Requests transmission of `WatchEvent.DELETED`. |
| DELETED = 0x00000001; |
| /// Used by `Directory.Watch`. Requests transmission of `WatchEvent.ADDED`. |
| ADDED = 0x00000002; |
| /// Used by `Directory.Watch`. Requests transmission of `WatchEvent.REMOVED`. |
| REMOVED = 0x00000004; |
| /// Used by `Directory.Watch`. Requests transmission of `WatchEvent.EXISTING`. |
| EXISTING = 0x00000008; |
| /// Used by `Directory.Watch`. Requests transmission of `WatchEvent.IDLE`. |
| IDLE = 0x00000010; |
| }; |
| |
| protocol Directory { |
| compose Directory1; |
| compose Directory2; |
| }; |
| |
| // Extracted from Directory1 for composition with protocols in other libraries. |
| protocol Openable { |
| /// Opens a new object relative to this directory object. |
| /// |
| /// `path` may contain multiple segments, separated by "/" characters, and should never be |
| /// empty; i.e. "" is an invalid path. A trailing slash implies OpenFlags.DIRECTORY. Components |
| /// must not be empty (i.e. "foo//bar" is invalid). ".." is disallowed anywhere in the path. "." |
| /// is only allowed if the path is exactly ".", but not otherwise. A leading '/' is allowed (and |
| /// is treated the same way as if not present, i.e. "/foo/bar' and "foo/bar" are the same). |
| /// |
| /// If an unknown value is sent for flags the connection should be closed. |
| /// |
| /// `OpenFlags.RIGHT_*` flags provided in `flags` will restrict access rights on |
| /// the `object` channel which will be connected to the opened entity. |
| /// |
| /// Rights are never increased. When you open a nested entity within a directory, you may only |
| /// request the same rights as what the directory connection already has, or a subset of those. |
| /// Exceeding those rights causes an access denied error to be transmitted in the |
| /// `OnOpen` event if applicable, and the `object` connection closed. |
| /// |
| /// `mode` is ignored. |
| @available(deprecated=11, removed=12, note="Use the new signature of Open.") |
| @selector("fuchsia.io1/Directory.Open") |
| Open(resource struct { |
| flags OpenFlags; |
| mode ModeType; |
| path string:MAX_PATH; |
| object server_end:Node; |
| }); |
| |
| /// Opens a new object relative to this directory object. |
| /// |
| /// `path` may contain multiple segments, separated by "/" characters, and should never be |
| /// empty; i.e. "" is an invalid path. A trailing slash implies OpenFlags.DIRECTORY. Components |
| /// must not be empty (i.e. "foo//bar" is invalid). ".." is disallowed anywhere in the path. "." |
| /// is only allowed if the path is exactly ".", but not otherwise. A leading '/' is allowed (and |
| /// is treated the same way as if not present, i.e. "/foo/bar' and "foo/bar" are the same). |
| /// |
| /// If an unknown value is sent for flags the connection should be closed. |
| /// |
| /// `OpenFlags.RIGHT_*` flags provided in `flags` will restrict access rights on |
| /// the `object` channel which will be connected to the opened entity. |
| /// |
| /// Rights are never increased. When you open a nested entity within a directory, you may only |
| /// request the same rights as what the directory connection already has, or a subset of those. |
| /// Exceeding those rights causes an access denied error to be transmitted in the |
| /// `OnOpen` event if applicable, and the `object` connection closed. |
| /// |
| /// `mode` is ignored. |
| @available(added=12) |
| @selector("fuchsia.io1/Directory.Open") |
| Open(resource struct { |
| flags OpenFlags; |
| mode ModeType; |
| path string:MAX_PATH_LENGTH; |
| object server_end:Node; |
| }); |
| }; |
| |
| /// Directory defines a node which is capable of containing other Objects. |
| protocol Directory1 { |
| compose Node1; |
| compose Openable; |
| |
| /// Reads a collection of variably sized dirents into a buffer. |
| /// The number of dirents in a directory may be very large: akin to |
| /// calling read multiple times on a file, directories have a seek |
| /// offset which is updated on subsequent calls to ReadDirents. |
| /// Each call to ReadDirents will only return whole dirent structures, |
| /// they will not get split across ReadDirent calls. When the seek |
| /// offset reaches the end, `dirents` will be empty. |
| /// |
| /// These dirents are of the form: |
| /// ``` |
| /// struct dirent { |
| /// // Describes the inode of the entry. |
| /// uint64 ino; |
| /// // Describes the length of the dirent name in bytes. |
| /// uint8 size; |
| /// // Describes the type of the entry. Aligned with the |
| /// // POSIX d_type values. Use `DirentType` constants. |
| /// uint8 type; |
| /// // Unterminated name of entry. |
| /// char name[0]; |
| /// } |
| /// ``` |
| /// |
| /// This method does not require any rights, since one could always probe for |
| /// directory contents by triggering name conflicts during file creation. |
| @selector("fuchsia.io1/Directory.ReadDirents") |
| ReadDirents(struct { |
| max_bytes uint64; |
| }) -> (struct { |
| s zx.Status; |
| dirents vector<uint8>:MAX_BUF; |
| }); |
| |
| /// Resets the directory seek offset. |
| /// |
| /// This method does not require any rights, similar to ReadDirents. |
| @selector("fuchsia.io1/Directory.Rewind") |
| Rewind() -> (struct { |
| s zx.Status; |
| }); |
| |
| /// Acquires a token to a Directory which can be used to identify access to it at a later point |
| /// in time. The token will remain valid for as long as the connection requesting the token |
| /// remains open. |
| /// |
| /// This method requires following rights: `OpenFlags.RIGHT_WRITABLE`, otherwise returns |
| /// `ZX_ERR_BAD_HANDLE`. |
| @selector("fuchsia.io1/Directory.GetToken") |
| GetToken() -> (resource struct { |
| s zx.Status; |
| token zx.Handle:optional; |
| }); |
| |
| /// Creates a link to an object named src by the name dst, within a directory represented by |
| /// token. |
| /// |
| /// `src` must be a resolved object name. Including "/" in the string will |
| /// return `ZX_ERR_INVALID_ARGS`. |
| /// |
| /// `dst` must be a resolved object name. Including "/" in the string will |
| /// return `ZX_ERR_INVALID_ARGS`. |
| /// |
| /// This method requires following rights: `OpenFlags.RIGHT_WRITABLE`, otherwise returns |
| /// `ZX_ERR_BAD_HANDLE`. |
| @selector("fuchsia.io1/Directory.Link") |
| Link(resource struct { |
| src string:MAX_FILENAME; |
| dst_parent_token zx.Handle; |
| dst string:MAX_FILENAME; |
| }) -> (struct { |
| s zx.Status; |
| }); |
| |
| /// Watches a directory, receiving events of added messages on the |
| /// watcher request channel. |
| /// |
| /// Options must be zero; it is reserved. |
| /// |
| /// This method does not require any rights, similar to ReadDirents. |
| @selector("fuchsia.io1/Directory.Watch") |
| Watch(resource struct { |
| mask WatchMask; |
| options uint32; |
| watcher server_end:DirectoryWatcher; |
| }) -> (struct { |
| s zx.Status; |
| }); |
| }; |