// -*- Protocol-Buffers -*- //============================================================================== /// @file vfs.proto /// @brief Virtual Filesystem gRPC/ProtoBuf interface /// @author Tor Slettnes //============================================================================== syntax = "proto3"; package picarro.platform.vfs; import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; import "signal.proto"; import "variant.proto"; service VirtualFileSystem { // List known virtual filesystem contexts. rpc get_contexts (google.protobuf.Empty) returns (ContextMap); // List open virtual filesystem contexts. rpc get_open_contexts (google.protobuf.Empty) returns (ContextMap); // List known virtual filesystem contexts. rpc get_context_spec (Path) returns (ContextSpec); // Explicitly open a virtual context. Internally this increments a reference // counter to keep the corresponding virtual filesystem context (VFC) open. // For instance, in the case of a removable or remote drive the drive will // remain mounted, thereby eliminating overhead associated with // mounting/unmounting for individual file transactions. // // Once access is no longer needed The client should invoke // `close_context()', thereby allowing the context to be closed. rpc open_context (Path) returns (ContextSpec); // Close a previously-opened virtual context. Internally, this decrements a // reference counter associated with the underlying filesystem context, and // closes the context (e.g. unmounts) if it reaches zero. rpc close_context (Path) returns (google.protobuf.Empty); // Return information about the mounted filesystem containing the specified `path`. rpc get_volume_info (PathRequest) returns (VolumeInfo); // Return information about the specified `path`. // Unlike `list_folder()` this does not descend if the path is a folder, // but rather returns the status of the folder itself. rpc get_file_info (PathRequest) returns (FileInfo); // List contents of the specified path (context/folder). rpc get_directory (PathRequest) returns (Directory); /// Recursively locate files matching specific filename and/or attribute patterns. rpc locate (LocateRequest) returns (Directory); // Copy `sources` to `path`. // If multiple sources are specified, `inside_target` must be set to // indicate that the target `path` represents a folder. rpc copy (PathRequest) returns (google.protobuf.Empty); // Move `sources` to `target`. // If multiple sources are specified, `inside_target` must be set to // indicate that the target `path` represents a folder. rpc move (PathRequest) returns (google.protobuf.Empty); // Create a folder rpc create_folder (PathRequest) returns (google.protobuf.Empty); // Delete a file or folder as specified by `path`, // or multiple files and/or folders specified as `sources`. rpc remove (PathRequest) returns (google.protobuf.Empty); // Read the specified file, and stream its contents in chunks. rpc read_file (Path) returns (stream FileChunk); // Write to a file in chunks. The path must be specified with the first chunk. rpc write_file (stream FileChunk) returns (google.protobuf.Empty); // Return attributes associated with the specified path. rpc get_attributes (Path) returns (picarro.variant.KeyValueMap); // Set/update attributes associated with the specified path. rpc set_attributes (AttributeRequest) returns (google.protobuf.Empty); // Clear all attributes associated with the specified path. rpc clear_attributes (Path) returns (google.protobuf.Empty); //======================================================================== // Watch for changes rpc watch (picarro.signal.Filter) returns (stream Signal); } enum PathType { // Synchronized to C++ STL 'std::filesystem::file_type' TYPE_NONE = 0; // Not applicable, or unknown TYPE_FILE = 1; // Regular file TYPE_DIRECTORY = 2; // Regular directory TYPE_SYMLINK = 3; // Symbolic link TYPE_CHARDEV = 4; // Character special device TYPE_BLOCKDEV = 5; // Block special device TYPE_PIPE = 6; // Named pipe TYPE_SOCKET = 7; // Named (UNIX domain) socket } message ContextSpec { // Name for this context. string name = 1; // Root of context within native filesystem string root = 2; // Writable access granted // Individual files/folers may have further restrictions. bool writable = 3; // Whether the context represents a removable volume (e.g. USB drive); // Only used in replies from server. bool removable = 4; // Human readable name (e.g volume label for a removable drive) string title = 5; } message ContextMap { map map = 1; } message Path { // Virtual Filesystem Context, e.g., "usb0", "logs", ... string context = 1; // Path relative to context string relpath = 2; } message PathRequest { // Virtual path comprising a filesystem context and a relative path. Path path = 2; // Source path(s) for `copy()` / `move()`, as well as optional additional // paths for `remove()`. repeated Path sources = 3; // Enables the following behaviors, rather than failing: // - Recursively copy/move/remove a folder and its children // - Replaces an existing target regardless of type // - Copies metadata from source, even if replacing existing target // - Creates missing parent folder(s) leading up to `target`. bool force = 4; // Whether to follow symbolic links on source or target. // Be vewwy vewwy cautious when used together with `force`. // Note that links are never followed outside the context. bool dereference = 5; // Merge rather than replace an existing target folder. // Effective only if `path` and all `sources` are folders. bool merge = 6; // Update only; only copy if target does not exist or is older than source. bool update = 7; // Include custom attributes in request bool with_attributes = 8; // Include hidden files in directory list bool include_hidden = 9; // Indicates that `target` is not the final target path, but a // parent folder into which the source path(s) will be copied/moved. // copy()/move() require this option if there is more than one source. bool inside_target = 10; } message LocateRequest { // Where to start the search Path root = 1; // Zero or more glob-style filename masks, e.g., `*.txt`. repeated string filename_masks = 2; // Zero or more tag/value pairs to match. // Tags may be repeated for cumulative value matches. picarro.variant.TaggedValueList attribute_filters = 5; // Include custom attributes in request bool with_attributes = 8; // Include hidden files in directory list bool include_hidden = 9; // Ignore case in filename bool ignore_case = 10; } message FileInfo { string name = 1; // Base name, without leading directory PathType type = 2; // DIRECTORY, FILE, etc. uint64 size = 3; // Size in bytes string link = 4; // Target for symbolic links uint32 mode = 5; // UNIX mode mask bool readable = 6; // Readable file/listable directory bool writable = 7; // Writable file/modifiable directory uint32 uid = 8; // Owner numeric ID uint32 gid = 9; // Group numeric ID string ownername = 10; // Owner name string groupname = 11; // Group name (`group` is a reserved ProtoBuf word) google.protobuf.Timestamp accessTime = 12; // Last access google.protobuf.Timestamp modifyTime = 13; // Last modification google.protobuf.Timestamp createTime = 14; // Creation picarro.variant.KeyValueMap attributes = 15; // Custom file attributes // TBD: Access Control Lists, SELinux contexts } message Directory { map map = 1; } message AttributeRequest { Path path = 1; picarro.variant.KeyValueMap attributes = 2; } message VolumeInfo { uint64 capacity = 1; // Total size, in bytes uint64 free = 2; // Free size, in bytes uint64 available = 3; // Available size, in bytes } message FileChunk { Path path = 1; bytes data = 2; } message Signal { picarro.signal.MappingAction mapping_action = 1; string mapping_key = 2; oneof signal { ContextSpec context = 8; // A filesystem context has been added/removed/modified ContextSpec context_in_use = 9; // A context has been opened/closed }; }