microsandbox_protocol/fs.rs
1//! Filesystem-related protocol message payloads.
2
3use serde::{Deserialize, Serialize};
4
5//--------------------------------------------------------------------------------------------------
6// Constants
7//--------------------------------------------------------------------------------------------------
8
9/// Maximum chunk size for streaming file data (3 MiB).
10///
11/// This stays safely under the 4 MiB frame limit after CBOR envelope overhead.
12pub const FS_CHUNK_SIZE: usize = 3 * 1024 * 1024;
13
14//--------------------------------------------------------------------------------------------------
15// Types
16//--------------------------------------------------------------------------------------------------
17
18/// A filesystem operation requested by the host.
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub enum FsOp {
21 /// Resolve a path to its canonical absolute form.
22 RealPath {
23 /// Guest path to resolve.
24 path: String,
25 },
26
27 /// Get metadata for a path.
28 Stat {
29 /// Guest path to stat.
30 path: String,
31
32 /// Whether to follow symlinks.
33 follow_symlink: bool,
34 },
35
36 /// Update metadata for a path.
37 SetStat {
38 /// Guest path to update.
39 path: String,
40
41 /// Whether to follow symlinks.
42 follow_symlink: bool,
43
44 /// Attributes to update.
45 attrs: FsSetAttrs,
46 },
47
48 /// List directory contents.
49 List {
50 /// Guest directory path to list.
51 path: String,
52 },
53
54 /// Read a symlink target.
55 ReadLink {
56 /// Guest symlink path to read.
57 path: String,
58 },
59
60 /// Create a symlink.
61 Symlink {
62 /// Symlink target.
63 target: String,
64
65 /// Symlink path to create.
66 link_path: String,
67 },
68
69 /// Create a directory (and parents).
70 Mkdir {
71 /// Guest directory path to create.
72 path: String,
73
74 /// Permission bits to set on creation (e.g. 0o755).
75 #[serde(default)]
76 mode: Option<u32>,
77 },
78
79 /// Remove a file.
80 Remove {
81 /// Guest file path to remove.
82 path: String,
83 },
84
85 /// Remove a directory.
86 RemoveDir {
87 /// Guest directory path to remove.
88 path: String,
89
90 /// Whether to remove recursively.
91 recursive: bool,
92 },
93
94 /// Copy a file or directory within the guest.
95 Copy {
96 /// Source path in guest.
97 src: String,
98 /// Destination path in guest.
99 dst: String,
100 },
101
102 /// Rename/move a file or directory.
103 Rename {
104 /// Source path in guest.
105 src: String,
106 /// Destination path in guest.
107 dst: String,
108 },
109
110 /// Open a file and allocate an agentd-side handle.
111 OpenFile {
112 /// Guest file path to open.
113 path: String,
114
115 /// File open options.
116 options: FsOpenOptions,
117 },
118
119 /// Open a directory and allocate an agentd-side handle.
120 OpenDir {
121 /// Guest directory path to open.
122 path: String,
123 },
124
125 /// Close a file or directory handle.
126 CloseHandle {
127 /// Agentd-side handle.
128 handle: u64,
129 },
130
131 /// Read from an open file handle.
132 Read {
133 /// Agentd-side file handle.
134 handle: u64,
135
136 /// Byte offset to read from.
137 offset: u64,
138
139 /// Maximum bytes to read. `None` means read to EOF.
140 len: Option<u64>,
141 },
142
143 /// Write to an open file handle.
144 Write {
145 /// Agentd-side file handle.
146 handle: u64,
147
148 /// Byte offset to write at.
149 offset: u64,
150
151 /// Expected byte count. `None` disables count validation.
152 len: Option<u64>,
153 },
154
155 /// Read the next batch of entries from an open directory handle.
156 ReadDir {
157 /// Agentd-side directory handle.
158 handle: u64,
159
160 /// Maximum entries to return. `None` uses the agent default.
161 limit: Option<u32>,
162 },
163
164 /// Get metadata for an open file or directory handle.
165 FStat {
166 /// Agentd-side handle.
167 handle: u64,
168 },
169
170 /// Update metadata for an open file handle.
171 FSetStat {
172 /// Agentd-side handle.
173 handle: u64,
174
175 /// Attributes to update.
176 attrs: FsSetAttrs,
177 },
178}
179
180/// Attributes accepted by setstat-style filesystem operations.
181#[derive(Debug, Clone, Default, Serialize, Deserialize)]
182pub struct FsSetAttrs {
183 /// Unix permission bits.
184 pub mode: Option<u32>,
185
186 /// Owner user ID.
187 pub uid: Option<u32>,
188
189 /// Owner group ID.
190 pub gid: Option<u32>,
191
192 /// File size.
193 pub size: Option<u64>,
194
195 /// Access time as Unix timestamp seconds.
196 pub atime: Option<i64>,
197
198 /// Modification time as Unix timestamp seconds.
199 pub mtime: Option<i64>,
200}
201
202/// Options used when opening a file handle.
203#[derive(Debug, Clone, Default, Serialize, Deserialize)]
204pub struct FsOpenOptions {
205 /// Open for reading.
206 pub read: bool,
207
208 /// Open for writing.
209 pub write: bool,
210
211 /// Append writes to the end.
212 pub append: bool,
213
214 /// Create the file if it is missing.
215 pub create: bool,
216
217 /// Truncate the file after opening.
218 pub truncate: bool,
219
220 /// Create a new file and fail if it already exists.
221 pub create_new: bool,
222
223 /// Permission bits to set on creation.
224 pub mode: Option<u32>,
225}
226
227/// Request to perform a filesystem operation in the guest.
228#[derive(Debug, Clone, Serialize, Deserialize)]
229pub struct FsRequest {
230 /// The operation to perform.
231 pub op: FsOp,
232}
233
234/// Metadata about a filesystem entry (wire format).
235#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct FsEntryInfo {
237 /// Path of the entry.
238 pub path: String,
239
240 /// Kind of entry: `"file"`, `"dir"`, `"symlink"`, or `"other"`.
241 pub kind: String,
242
243 /// Size in bytes.
244 pub size: u64,
245
246 /// Unix permission bits.
247 pub mode: u32,
248
249 /// Last modification time as Unix timestamp (seconds since epoch).
250 pub modified: Option<i64>,
251
252 /// Owner user ID.
253 pub uid: u32,
254
255 /// Owner group ID.
256 pub gid: u32,
257
258 /// Last access time as Unix timestamp (seconds since epoch).
259 pub atime: Option<i64>,
260
261 /// Last modification time as Unix timestamp (seconds since epoch).
262 pub mtime: Option<i64>,
263}
264
265/// Data variants that can be included in a filesystem response.
266#[derive(Debug, Clone, Serialize, Deserialize)]
267pub enum FsResponseData {
268 /// Stat result.
269 Stat(FsEntryInfo),
270
271 /// Directory listing result.
272 List(Vec<FsEntryInfo>),
273
274 /// Open handle.
275 Handle(u64),
276
277 /// Resolved path or symlink target.
278 Path(String),
279}
280
281/// Terminal response for a filesystem operation.
282///
283/// This is always the last message sent for a given correlation ID.
284/// For streaming reads, it follows the `FsData` chunks.
285/// For simple operations, it carries the result directly.
286#[derive(Debug, Clone, Serialize, Deserialize)]
287pub struct FsResponse {
288 /// Whether the operation succeeded.
289 pub ok: bool,
290
291 /// Error message if `ok` is false.
292 #[serde(default)]
293 pub error: Option<String>,
294
295 /// Optional result data (for stat/list operations).
296 #[serde(default)]
297 pub data: Option<FsResponseData>,
298}
299
300/// A chunk of file data for streaming read/write operations.
301///
302/// An empty `data` field signals EOF (like `ExecStdin` with empty data).
303#[derive(Debug, Serialize, Deserialize)]
304pub struct FsData {
305 /// The raw file data.
306 #[serde(with = "serde_bytes")]
307 pub data: Vec<u8>,
308}