Nothing to see here, move along meow
1use crate::cap::FsRights;
2use crate::error::FsError;
3
4pub use lancer_vfs_proto::READDIR_ENTRY_SIZE;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[repr(u8)]
8pub enum FsOpcode {
9 Open = 1,
10 Read = 2,
11 Write = 3,
12 Close = 4,
13 Stat = 5,
14 Mkdir = 6,
15 Unlink = 7,
16 ReadDir = 8,
17 CreateSnapshot = 9,
18 DeleteSnapshot = 10,
19 Sync = 11,
20 StatFs = 12,
21 Rename = 14,
22 Truncate = 15,
23}
24
25impl FsOpcode {
26 pub const fn from_u8(v: u8) -> Option<Self> {
27 match v {
28 1 => Some(Self::Open),
29 2 => Some(Self::Read),
30 3 => Some(Self::Write),
31 4 => Some(Self::Close),
32 5 => Some(Self::Stat),
33 6 => Some(Self::Mkdir),
34 7 => Some(Self::Unlink),
35 8 => Some(Self::ReadDir),
36 9 => Some(Self::CreateSnapshot),
37 10 => Some(Self::DeleteSnapshot),
38 11 => Some(Self::Sync),
39 12 => Some(Self::StatFs),
40 14 => Some(Self::Rename),
41 15 => Some(Self::Truncate),
42 _ => None,
43 }
44 }
45}
46
47#[derive(Debug, Clone, Copy)]
48#[repr(C)]
49pub struct FsRequest {
50 pub opcode: u8,
51 pub handle: u8,
52 pub flags: u8,
53 pub _pad: u8,
54 pub tag: u32,
55 pub arg0: u64,
56 pub arg1: u64,
57 pub arg2: u64,
58}
59
60const _: () = assert!(core::mem::size_of::<FsRequest>() == 32);
61
62impl FsRequest {
63 pub const SIZE: usize = 32;
64
65 pub fn from_bytes(buf: &[u8]) -> Option<Self> {
66 match buf.len() >= Self::SIZE {
67 true => Some(unsafe { core::ptr::read_unaligned(buf.as_ptr() as *const Self) }),
68 false => None,
69 }
70 }
71
72 pub fn as_bytes(&self) -> &[u8] {
73 unsafe { core::slice::from_raw_parts(self as *const Self as *const u8, Self::SIZE) }
74 }
75
76 pub fn open(tag: u32, dir_handle: u8, mode: FsRights, name_offset: u64, name_len: u64) -> Self {
77 Self {
78 opcode: FsOpcode::Open as u8,
79 handle: dir_handle,
80 flags: mode.raw() as u8,
81 _pad: 0,
82 tag,
83 arg0: name_offset,
84 arg1: name_len,
85 arg2: 0,
86 }
87 }
88
89 pub fn read(tag: u32, handle: u8, offset: u64, len: u32, buf_offset: u32) -> Self {
90 Self {
91 opcode: FsOpcode::Read as u8,
92 handle,
93 flags: 0,
94 _pad: 0,
95 tag,
96 arg0: offset,
97 arg1: len as u64,
98 arg2: buf_offset as u64,
99 }
100 }
101
102 pub fn write(tag: u32, handle: u8, offset: u64, len: u32, buf_offset: u32) -> Self {
103 Self {
104 opcode: FsOpcode::Write as u8,
105 handle,
106 flags: 0,
107 _pad: 0,
108 tag,
109 arg0: offset,
110 arg1: len as u64,
111 arg2: buf_offset as u64,
112 }
113 }
114
115 pub fn close(tag: u32, handle: u8) -> Self {
116 Self {
117 opcode: FsOpcode::Close as u8,
118 handle,
119 flags: 0,
120 _pad: 0,
121 tag,
122 arg0: 0,
123 arg1: 0,
124 arg2: 0,
125 }
126 }
127
128 pub fn stat(tag: u32, handle: u8) -> Self {
129 Self {
130 opcode: FsOpcode::Stat as u8,
131 handle,
132 flags: 0,
133 _pad: 0,
134 tag,
135 arg0: 0,
136 arg1: 0,
137 arg2: 0,
138 }
139 }
140
141 pub fn mkdir(tag: u32, dir_handle: u8, name_offset: u64, name_len: u64) -> Self {
142 Self {
143 opcode: FsOpcode::Mkdir as u8,
144 handle: dir_handle,
145 flags: 0,
146 _pad: 0,
147 tag,
148 arg0: name_offset,
149 arg1: name_len,
150 arg2: 0,
151 }
152 }
153
154 pub fn unlink(tag: u32, dir_handle: u8, name_offset: u64, name_len: u64) -> Self {
155 Self {
156 opcode: FsOpcode::Unlink as u8,
157 handle: dir_handle,
158 flags: 0,
159 _pad: 0,
160 tag,
161 arg0: name_offset,
162 arg1: name_len,
163 arg2: 0,
164 }
165 }
166
167 pub fn readdir(tag: u32, dir_handle: u8, cursor: u64, buf_offset: u64, buf_len: u64) -> Self {
168 Self {
169 opcode: FsOpcode::ReadDir as u8,
170 handle: dir_handle,
171 flags: 0,
172 _pad: 0,
173 tag,
174 arg0: cursor,
175 arg1: buf_offset,
176 arg2: buf_len,
177 }
178 }
179
180 pub fn create_snapshot(tag: u32, name_offset: u64, name_len: u64) -> Self {
181 Self {
182 opcode: FsOpcode::CreateSnapshot as u8,
183 handle: 0,
184 flags: 0,
185 _pad: 0,
186 tag,
187 arg0: name_offset,
188 arg1: name_len,
189 arg2: 0,
190 }
191 }
192
193 pub fn delete_snapshot(tag: u32, name_offset: u64, name_len: u64) -> Self {
194 Self {
195 opcode: FsOpcode::DeleteSnapshot as u8,
196 handle: 0,
197 flags: 0,
198 _pad: 0,
199 tag,
200 arg0: name_offset,
201 arg1: name_len,
202 arg2: 0,
203 }
204 }
205
206 pub fn sync(tag: u32) -> Self {
207 Self {
208 opcode: FsOpcode::Sync as u8,
209 handle: 0,
210 flags: 0,
211 _pad: 0,
212 tag,
213 arg0: 0,
214 arg1: 0,
215 arg2: 0,
216 }
217 }
218}
219
220#[derive(Debug, Clone, Copy)]
221#[repr(C)]
222pub struct FsResponse {
223 pub opcode: u8,
224 pub status: u8,
225 pub _pad: [u8; 2],
226 pub tag: u32,
227 pub val0: u64,
228 pub val1: u64,
229}
230
231const _: () = assert!(core::mem::size_of::<FsResponse>() == 24);
232
233impl FsResponse {
234 pub const SIZE: usize = 24;
235
236 pub fn from_bytes(buf: &[u8]) -> Option<Self> {
237 match buf.len() >= Self::SIZE {
238 true => Some(unsafe { core::ptr::read_unaligned(buf.as_ptr() as *const Self) }),
239 false => None,
240 }
241 }
242
243 pub fn as_bytes(&self) -> &[u8] {
244 unsafe { core::slice::from_raw_parts(self as *const Self as *const u8, Self::SIZE) }
245 }
246
247 pub fn success(opcode: u8, tag: u32, val0: u64, val1: u64) -> Self {
248 Self {
249 opcode,
250 status: 0,
251 _pad: [0; 2],
252 tag,
253 val0,
254 val1,
255 }
256 }
257
258 pub fn error(opcode: u8, tag: u32, err: FsError) -> Self {
259 Self {
260 opcode,
261 status: fs_error_to_status(err),
262 _pad: [0; 2],
263 tag,
264 val0: 0,
265 val1: 0,
266 }
267 }
268}
269
270pub const FS_STATUS_OK: u8 = 0;
271pub const FS_STATUS_NOT_FOUND: u8 = 1;
272pub const FS_STATUS_PERMISSION_DENIED: u8 = 2;
273pub const FS_STATUS_INVALID_HANDLE: u8 = 3;
274pub const FS_STATUS_HANDLE_TABLE_FULL: u8 = 4;
275pub const FS_STATUS_IO_ERROR: u8 = 5;
276pub const FS_STATUS_DISK_FULL: u8 = 6;
277pub const FS_STATUS_NOT_A_DIRECTORY: u8 = 7;
278pub const FS_STATUS_NOT_A_FILE: u8 = 8;
279pub const FS_STATUS_IS_A_DIRECTORY: u8 = 9;
280pub const FS_STATUS_DIR_NOT_EMPTY: u8 = 10;
281pub const FS_STATUS_FILE_EXISTS: u8 = 11;
282pub const FS_STATUS_NAME_TOO_LONG: u8 = 12;
283pub const FS_STATUS_PATH_TOO_DEEP: u8 = 13;
284pub const FS_STATUS_INTEGRITY_ERROR: u8 = 14;
285pub const FS_STATUS_STALE_CAP: u8 = 15;
286pub const FS_STATUS_INVALID_OP: u8 = 16;
287pub const FS_STATUS_SYMLINK_DEPTH: u8 = 17;
288pub const FS_STATUS_CORRUPT: u8 = 18;
289pub const FS_STATUS_UNKNOWN: u8 = 255;
290
291pub fn fs_error_to_status(err: FsError) -> u8 {
292 match err {
293 FsError::NotFound | FsError::KeyNotFound => FS_STATUS_NOT_FOUND,
294 FsError::NotADirectory => FS_STATUS_NOT_A_DIRECTORY,
295 FsError::NotAFile => FS_STATUS_NOT_A_FILE,
296 FsError::IsADirectory => FS_STATUS_IS_A_DIRECTORY,
297 FsError::DirectoryNotEmpty => FS_STATUS_DIR_NOT_EMPTY,
298 FsError::FileExists => FS_STATUS_FILE_EXISTS,
299 FsError::NameTooLong => FS_STATUS_NAME_TOO_LONG,
300 FsError::PathTooDeep => FS_STATUS_PATH_TOO_DEEP,
301 FsError::IntegrityFailure => FS_STATUS_INTEGRITY_ERROR,
302 FsError::SymlinkDepthExceeded => FS_STATUS_SYMLINK_DEPTH,
303 FsError::FreemapExhausted | FsError::ReservedExhausted => FS_STATUS_DISK_FULL,
304 FsError::CorruptSuperblock | FsError::CorruptNode => FS_STATUS_CORRUPT,
305 FsError::Io(_) | FsError::CacheFull | FsError::RingFull => FS_STATUS_IO_ERROR,
306 FsError::PoolExhausted | FsError::TreeFull | FsError::DuplicateKey => FS_STATUS_IO_ERROR,
307 FsError::InvalidBlock | FsError::InvalidName | FsError::DecompressError => {
308 FS_STATUS_CORRUPT
309 }
310 FsError::InsufficientRights | FsError::StaleGeneration => FS_STATUS_PERMISSION_DENIED,
311 FsError::HandleTableFull => FS_STATUS_HANDLE_TABLE_FULL,
312 FsError::InvalidHandle => FS_STATUS_INVALID_HANDLE,
313 FsError::DoubleFree => FS_STATUS_INVALID_HANDLE,
314 }
315}