// pkg/proto/filesystem.proto

syntax = "proto3";

package sandbox0.fs;

option go_package = "github.com/sandbox0-ai/sandbox0/storage-proxy/proto/fs";

message PosixActor {
  uint32 pid = 1;           // Process ID making the request
  uint32 uid = 2;           // Effective user ID making the request
  repeated uint32 gids = 3; // Effective group IDs making the request
}

// Read request
message ReadRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode identifier
  int64 offset = 3;      // Read offset
  int64 size = 4;        // Number of bytes to read
  uint64 handle_id = 5;  // File handle from Open
  PosixActor actor = 6;  // Caller POSIX identity
}

message ReadResponse {
  bytes data = 1;        // File data
  bool eof = 2;          // End of file marker
}

// Write request
message WriteRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode identifier
  int64 offset = 3;      // Write offset
  bytes data = 4;        // Data to write
  uint64 handle_id = 5;  // File handle from Open
  PosixActor actor = 6;  // Caller POSIX identity
}

message WriteResponse {
  int64 bytes_written = 1;  // Number of bytes written
}

// Open file
message OpenRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode to open
  uint32 flags = 3;      // Open flags
  PosixActor actor = 4;  // Caller POSIX identity
}

message OpenResponse {
  uint64 handle_id = 1;  // File handle for operations
}

// Release (close) file
message ReleaseRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode identifier
  uint64 handle_id = 3;  // File handle to release
  PosixActor actor = 4;  // Caller POSIX identity
}

// Create file
message CreateRequest {
  string volume_id = 1;  // Volume identifier
  uint64 parent = 2;     // Parent directory inode
  string name = 3;       // File name
  uint32 mode = 4;       // File mode (permissions)
  uint32 flags = 5;      // Open flags
  uint32 umask = 6;      // Umask
  PosixActor actor = 7;  // Caller POSIX identity
}

// Create directory
message MkdirRequest {
  string volume_id = 1;  // Volume identifier
  uint64 parent = 2;     // Parent directory inode
  string name = 3;       // Directory name
  uint32 mode = 4;       // Directory mode
  uint32 umask = 5;      // Umask
  PosixActor actor = 6;  // Caller POSIX identity
}

// Create node (file/device)
message MknodRequest {
  string volume_id = 1;  // Volume identifier
  uint64 parent = 2;     // Parent directory inode
  string name = 3;       // Node name
  uint32 mode = 4;       // Node mode (permissions + type)
  uint32 rdev = 5;       // Device ID for special files
  uint32 umask = 6;      // Umask
  PosixActor actor = 7;  // Caller POSIX identity
}

// Node response (for Create, Mkdir, Lookup)
message NodeResponse {
  uint64 inode = 1;          // Created/existing inode
  uint64 generation = 2;     // Generation number
  GetAttrResponse attr = 3;  // Node attributes
  uint64 handle_id = 4;      // File handle for operations
}

// Get file/directory attributes
message GetAttrRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode to query
  PosixActor actor = 3;  // Caller POSIX identity
}

message GetAttrResponse {
  uint64 ino = 1;        // Inode number
  uint32 mode = 2;       // File type and mode
  uint32 nlink = 3;      // Number of hard links
  uint32 uid = 4;        // Owner user ID
  uint32 gid = 5;        // Owner group ID
  uint64 rdev = 6;       // Device ID (if special file)
  uint64 size = 7;       // Size in bytes
  uint64 blocks = 8;     // Number of 512-byte blocks
  int64 atime_sec = 9;   // Last access time (seconds)
  int64 atime_nsec = 10; // Last access time (nanoseconds)
  int64 mtime_sec = 11;  // Last modification time (seconds)
  int64 mtime_nsec = 12; // Last modification time (nanoseconds)
  int64 ctime_sec = 13;  // Last status change time (seconds)
  int64 ctime_nsec = 14; // Last status change time (nanoseconds)
}

// Set attributes
message SetAttrRequest {
  string volume_id = 1;      // Volume identifier
  uint64 inode = 2;          // Inode to modify
  uint32 valid = 3;          // Mask of fields to set
  GetAttrResponse attr = 4;  // Attributes to set
  uint64 handle_id = 5;      // File handle when available
  PosixActor actor = 6;      // Caller POSIX identity
}

message SetAttrResponse {
  GetAttrResponse attr = 1;  // Updated attributes
}

// Lookup entry in directory
message LookupRequest {
  string volume_id = 1;  // Volume identifier
  uint64 parent = 2;     // Parent directory inode
  string name = 3;       // Entry name to lookup
  PosixActor actor = 4;  // Caller POSIX identity
}

// Read directory
message ReadDirRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Directory inode
  uint64 handle_id = 3;  // Directory handle
  int64 offset = 4;      // Read offset
  uint32 size = 5;       // Max entries to read (approximate)
  bool plus = 6;         // Include attributes if true
  PosixActor actor = 7;  // Caller POSIX identity
}

message ReadDirResponse {
  repeated DirEntry entries = 1;  // Directory entries
  bool eof = 2;                   // End of directory marker
}

// Open directory
message OpenDirRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Directory inode
  uint32 flags = 3;      // Open flags
  PosixActor actor = 4;  // Caller POSIX identity
}

message OpenDirResponse {
  uint64 handle_id = 1;  // Directory handle
}

// Release directory handle
message ReleaseDirRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Directory inode
  uint64 handle_id = 3;  // Directory handle
  PosixActor actor = 4;  // Caller POSIX identity
}

message DirEntry {
  uint64 inode = 1;            // Entry inode
  uint64 offset = 2;           // Entry offset
  string name = 3;             // Entry name
  uint32 type = 4;             // Entry type
  GetAttrResponse attr = 5;    // Entry attributes
}

// Unlink (delete) file
message UnlinkRequest {
  string volume_id = 1;  // Volume identifier
  uint64 parent = 2;     // Parent directory inode
  string name = 3;       // File name to delete
  PosixActor actor = 4;  // Caller POSIX identity
}

// Remove directory (delete empty directory)
message RmdirRequest {
  string volume_id = 1;  // Volume identifier
  uint64 parent = 2;     // Parent directory inode
  string name = 3;       // Directory name to delete
  PosixActor actor = 4;  // Caller POSIX identity
}

// Rename entry
message RenameRequest {
  string volume_id = 1;  // Volume identifier
  uint64 old_parent = 2; // Old parent directory inode
  string old_name = 3;   // Old name
  uint64 new_parent = 4; // New parent directory inode
  string new_name = 5;   // New name
  uint32 flags = 6;      // Rename flags
  PosixActor actor = 7;  // Caller POSIX identity
}

// Flush file
message FlushRequest {
  string volume_id = 1;  // Volume identifier
  uint64 handle_id = 2;  // File handle to flush
  PosixActor actor = 3;  // Caller POSIX identity
}

// Synchronize file
message FsyncRequest {
  string volume_id = 1;  // Volume identifier
  uint64 handle_id = 2;  // File handle to sync
  bool datasync = 3;     // Sync only data
  PosixActor actor = 4;  // Caller POSIX identity
}

// Mount volume
message MountVolumeRequest {
  string volume_id = 1;
}

message MountVolumeResponse {
  string volume_id = 1;
  int64 mounted_at = 2;
  string mount_session_id = 3;
}

message UnmountVolumeRequest {
  string volume_id = 1;
  string mount_session_id = 2;
}

message AckInvalidateRequest {
  string volume_id = 1;
  string mount_session_id = 2;
  string invalidate_id = 3;
  bool success = 4;
  string error_message = 5;
}

// Watch request for volume events.
message WatchRequest {
  string volume_id = 1;
  string path_prefix = 2;   // Only events under this path (optional)
  bool recursive = 3;       // Include subdirectories
  bool include_self = 4;    // Include events originating from same sandbox
  string sandbox_id = 5;    // Sandbox identifier for self-filtering
}

// Volume event type.
enum WatchEventType {
  WATCH_EVENT_TYPE_UNSPECIFIED = 0;
  WATCH_EVENT_TYPE_CREATE = 1;
  WATCH_EVENT_TYPE_WRITE = 2;
  WATCH_EVENT_TYPE_REMOVE = 3;
  WATCH_EVENT_TYPE_RENAME = 4;
  WATCH_EVENT_TYPE_CHMOD = 5;
  WATCH_EVENT_TYPE_INVALIDATE = 6; // Use when path cannot be resolved
}

// Watch event for volume changes.
message WatchEvent {
  string volume_id = 1;
  WatchEventType event_type = 2;
  string path = 3;
  string old_path = 4;
  uint64 inode = 5;
  int64 timestamp_unix = 6;
  string origin_instance = 7;
  string origin_sandbox_id = 8;
  string invalidate_id = 9;
}

message PrimaryRedirect {
  string volume_id = 1;
  string primary_node_id = 2;
  string primary_addr = 3;
  uint64 epoch = 4;
}

// Filesystem statistics
message StatFsRequest {
  string volume_id = 1;  // Volume identifier
  PosixActor actor = 2;  // Caller POSIX identity
}

message StatFsResponse {
  uint64 blocks = 1;      // Total data blocks in filesystem
  uint64 bfree = 2;       // Free blocks in filesystem
  uint64 bavail = 3;      // Free blocks available to unprivileged user
  uint64 files = 4;       // Total file nodes in filesystem
  uint64 ffree = 5;       // Free file nodes in filesystem
  uint32 bsize = 6;       // Block size
  uint32 namelen = 7;     // Maximum filename length
  uint32 frsize = 8;      // Fragment size
}

// Symbolic link operations
message SymlinkRequest {
  string volume_id = 1;  // Volume identifier
  uint64 parent = 2;     // Parent directory inode
  string name = 3;       // Link name
  string target = 4;     // Target path
  PosixActor actor = 5;  // Caller POSIX identity
}

message ReadlinkRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Symlink inode
  PosixActor actor = 3;  // Caller POSIX identity
}

message ReadlinkResponse {
  string target = 1;     // Target path
}

// Hard link operations
message LinkRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Existing file inode
  uint64 new_parent = 3; // New parent directory inode
  string new_name = 4;   // New link name
  PosixActor actor = 5;  // Caller POSIX identity
}

// Access check
message AccessRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode to check
  uint32 mask = 3;       // Access mode mask (R_OK=4, W_OK=2, X_OK=1, F_OK=0)
  uint32 uid = 4;        // User ID making the request
  repeated uint32 gids = 5;  // Group IDs of the user
  PosixActor actor = 6;  // Caller POSIX identity
}

// Fallocate - preallocate or deallocate space
message FallocateRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode to allocate space for
  uint32 mode = 3;       // Fallocate mode (0=default, 1=KEEP_SIZE, 2=PUNCH_HOLE, etc.)
  int64 offset = 4;      // Offset to start allocation
  int64 length = 5;      // Length to allocate
  uint64 handle_id = 6;  // File handle from Open
  PosixActor actor = 7;  // Caller POSIX identity
}

// Copy file range
message CopyFileRangeRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode_in = 2;   // Source inode
  uint64 handle_in = 3;  // Source handle
  uint64 offset_in = 4;  // Source offset
  uint64 inode_out = 5;  // Destination inode
  uint64 handle_out = 6; // Destination handle
  uint64 offset_out = 7; // Destination offset
  uint64 length = 8;     // Length to copy
  uint32 flags = 9;      // Copy flags
  PosixActor actor = 10; // Caller POSIX identity
}

message CopyFileRangeResponse {
  uint64 bytes_copied = 1;
}

// File lock state
message FileLock {
  uint64 start = 1;
  uint64 end = 2;
  uint32 typ = 3;
  uint32 pid = 4;
}

message GetLkRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode identifier
  uint64 handle_id = 3;  // File handle
  uint64 owner = 4;      // Lock owner
  FileLock lock = 5;     // Requested lock
  PosixActor actor = 6;  // Caller POSIX identity
}

message GetLkResponse {
  FileLock lock = 1;
}

message SetLkRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode identifier
  uint64 handle_id = 3;  // File handle
  uint64 owner = 4;      // Lock owner
  FileLock lock = 5;     // Lock to set
  bool block = 6;        // Blocking lock
  PosixActor actor = 7;  // Caller POSIX identity
}

message FlockRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode identifier
  uint64 handle_id = 3;  // File handle
  uint64 owner = 4;      // Lock owner
  uint32 typ = 5;        // Lock type
  bool block = 6;        // Blocking lock
  PosixActor actor = 7;  // Caller POSIX identity
}

// Ioctl
message IoctlRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode identifier
  uint32 cmd = 3;        // Ioctl command
  uint64 arg = 4;        // Ioctl argument
  bytes data_in = 5;     // Input buffer
  uint32 data_out_size = 6; // Expected output size
  PosixActor actor = 7;  // Caller POSIX identity
}

message IoctlResponse {
  bytes data_out = 1;    // Output buffer
}

// Extended attributes (xattr)
message GetXattrRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode identifier
  string name = 3;       // Attribute name
  uint32 size = 4;       // Buffer size (0 to query size)
  PosixActor actor = 5;  // Caller POSIX identity
}

message GetXattrResponse {
  bytes value = 1;       // Attribute value
}

message SetXattrRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode identifier
  string name = 3;       // Attribute name
  bytes value = 4;       // Attribute value
  uint32 flags = 5;      // XATTR_CREATE=1, XATTR_REPLACE=2
  PosixActor actor = 6;  // Caller POSIX identity
}

message ListXattrRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode identifier
  int32 size = 3;        // Buffer size (0 to query size)
  PosixActor actor = 4;  // Caller POSIX identity
}

message ListXattrResponse {
  bytes data = 1;        // Null-terminated attribute names
}

message RemoveXattrRequest {
  string volume_id = 1;  // Volume identifier
  uint64 inode = 2;      // Inode identifier
  string name = 3;       // Attribute name to remove
  PosixActor actor = 4;  // Caller POSIX identity
}

message Empty {}
