1use crate::sync::SpinLock;
51use crate::vfs::*;
52use crate::{device::block::BlockDriver, uapi::time::TimeSpec};
53use alloc::collections::BTreeMap;
54use alloc::string::String;
55use alloc::sync::Arc;
56use alloc::vec;
57use alloc::vec::Vec;
58use core::sync::atomic::{AtomicU64, Ordering};
59
60pub struct SimpleFs {
62 device: Option<Arc<dyn BlockDriver>>, root: Arc<SimpleFsInode>,
64}
65
66impl SimpleFs {
67 pub fn new() -> Arc<Self> {
69 let root = Arc::new(SimpleFsInode::new_dir(
70 1,
71 FileMode::S_IRUSR
72 | FileMode::S_IWUSR
73 | FileMode::S_IXUSR
74 | FileMode::S_IRGRP
75 | FileMode::S_IXGRP
76 | FileMode::S_IROTH
77 | FileMode::S_IXOTH,
78 ));
79 Arc::new(Self { device: None, root })
80 }
81}
82
83impl FileSystem for SimpleFs {
84 fn fs_type(&self) -> &'static str {
85 "simplefs"
86 }
87
88 fn root_inode(&self) -> Arc<dyn Inode> {
89 self.root.clone() as Arc<dyn Inode>
90 }
91
92 fn sync(&self) -> Result<(), FsError> {
93 Ok(()) }
95
96 fn statfs(&self) -> Result<StatFs, FsError> {
97 Ok(StatFs {
98 block_size: 4096,
99 total_blocks: 0,
100 free_blocks: 0,
101 available_blocks: 0,
102 total_inodes: 0,
103 free_inodes: 0,
104 fsid: 0,
105 max_filename_len: 255,
106 })
107 }
108}
109
110impl SimpleFs {
111 pub fn from_ramdisk(device: Arc<dyn BlockDriver>) -> Result<Self, FsError> {
113 let block_size = device.block_size();
115 let mut header_block = vec![0u8; block_size];
116 if !device.read_block(0, &mut header_block) {
117 return Err(FsError::IoError);
118 }
119
120 if &header_block[0..8] != b"RAMDISK\0" {
121 return Err(FsError::IoError);
122 }
123
124 let file_count = u32::from_le_bytes(header_block[8..12].try_into().unwrap());
125
126 let root = Arc::new(SimpleFsInode::new_dir(
128 1,
129 FileMode::S_IRUSR
130 | FileMode::S_IWUSR
131 | FileMode::S_IXUSR
132 | FileMode::S_IRGRP
133 | FileMode::S_IXGRP
134 | FileMode::S_IROTH
135 | FileMode::S_IXOTH,
136 ));
137
138 let mut offset = 16;
140 for _ in 0..file_count {
141 offset = Self::parse_file_entry(device.clone(), offset, root.clone())?;
142 }
143
144 Ok(Self {
145 device: Some(device),
146 root,
147 })
148 }
149
150 fn parse_file_entry(
152 device: Arc<dyn BlockDriver>,
153 offset: usize,
154 parent: Arc<SimpleFsInode>,
155 ) -> Result<usize, FsError> {
156 let mut header_buf = vec![0u8; 32];
158 Self::read_at_offset(device.clone(), offset, &mut header_buf)?;
159
160 let magic = u32::from_le_bytes(header_buf[0..4].try_into().unwrap());
161 if magic != 0x46494C45 {
162 return Err(FsError::IoError);
163 }
164
165 let name_len = u32::from_le_bytes(header_buf[4..8].try_into().unwrap()) as usize;
166 let data_len = u32::from_le_bytes(header_buf[8..12].try_into().unwrap()) as usize;
167 let file_type = u32::from_le_bytes(header_buf[12..16].try_into().unwrap());
168 let mode = u32::from_le_bytes(header_buf[16..20].try_into().unwrap());
169
170 let mut cur_offset = offset + 32;
171
172 let name_aligned = (name_len + 3) / 4 * 4;
174 let mut name_buf = vec![0u8; name_aligned];
175 Self::read_at_offset(device.clone(), cur_offset, &mut name_buf)?;
176 let name = String::from(String::from_utf8_lossy(&name_buf[..name_len]));
177 cur_offset += name_aligned;
178
179 let data_aligned = (data_len + 511) / 512 * 512;
181 let mut data_buf = vec![0u8; data_len];
182 if data_len > 0 {
183 Self::read_at_offset(device.clone(), cur_offset, &mut data_buf)?;
184 }
185 cur_offset += data_aligned;
186
187 let inode = if file_type == 0 {
189 let file_mode = FileMode::from_bits_truncate(mode);
191 let inode = SimpleFsInode::new_file(parent.next_inode_no(), file_mode);
192 inode.data.lock().extend_from_slice(&data_buf);
193 Arc::new(inode)
194 } else {
195 let dir_mode = FileMode::from_bits_truncate(mode);
197 Arc::new(SimpleFsInode::new_dir(parent.next_inode_no(), dir_mode))
198 };
199
200 Self::insert_inode_by_path(&name, inode, parent)?;
202
203 Ok(cur_offset)
204 }
205
206 fn read_at_offset(
208 device: Arc<dyn BlockDriver>,
209 offset: usize,
210 buf: &mut [u8],
211 ) -> Result<(), FsError> {
212 let block_size = device.block_size();
213 let mut buf_offset = 0;
214
215 while buf_offset < buf.len() {
216 let current_offset = offset + buf_offset;
218 let block_num = current_offset / block_size;
219 let block_offset = current_offset % block_size;
220
221 let mut block_buf = vec![0u8; block_size];
222 if !device.read_block(block_num, &mut block_buf) {
223 return Err(FsError::IoError);
224 }
225
226 let copy_len = (block_size - block_offset).min(buf.len() - buf_offset);
228
229 buf[buf_offset..buf_offset + copy_len]
230 .copy_from_slice(&block_buf[block_offset..block_offset + copy_len]);
231
232 buf_offset += copy_len;
233 }
234
235 Ok(())
236 }
237
238 fn insert_inode_by_path(
240 path: &str,
241 inode: Arc<SimpleFsInode>,
242 root: Arc<SimpleFsInode>,
243 ) -> Result<(), FsError> {
244 let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
245
246 if parts.is_empty() {
247 return Err(FsError::InvalidArgument);
248 }
249
250 let mut current = root;
251
252 for part in &parts[..parts.len() - 1] {
254 let child = {
255 let children = current.children.lock();
256 children.get(*part).cloned()
257 };
258
259 if let Some(child) = child {
260 current = child;
261 } else {
262 let new_dir = Arc::new(SimpleFsInode::new_dir(
264 current.next_inode_no(),
265 FileMode::S_IRUSR
266 | FileMode::S_IWUSR
267 | FileMode::S_IXUSR
268 | FileMode::S_IRGRP
269 | FileMode::S_IXGRP
270 | FileMode::S_IROTH
271 | FileMode::S_IXOTH,
272 ));
273 current
274 .children
275 .lock()
276 .insert(String::from(*part), new_dir.clone());
277 current = new_dir;
278 }
279 }
280
281 let final_name = parts[parts.len() - 1];
283 current
284 .children
285 .lock()
286 .insert(String::from(final_name), inode);
287
288 Ok(())
289 }
290}
291
292struct SimpleFsInode {
294 inode_no: usize,
295 inode_type: InodeType,
296 mode: FileMode,
297 data: SpinLock<Vec<u8>>,
298 children: SpinLock<BTreeMap<String, Arc<SimpleFsInode>>>,
299}
300
301impl SimpleFsInode {
302 fn new_file(inode_no: u64, mode: FileMode) -> Self {
304 let file_mode = FileMode::S_IFREG | mode;
305
306 Self {
307 inode_no: inode_no as usize,
308 inode_type: InodeType::File,
309 mode: file_mode,
310 data: SpinLock::new(Vec::new()),
311 children: SpinLock::new(BTreeMap::new()),
312 }
313 }
314
315 fn new_dir(inode_no: u64, mode: FileMode) -> Self {
317 let dir_mode = FileMode::S_IFDIR | mode;
318
319 Self {
320 inode_no: inode_no as usize,
321 inode_type: InodeType::Directory,
322 mode: dir_mode,
323 data: SpinLock::new(Vec::new()),
324 children: SpinLock::new(BTreeMap::new()),
325 }
326 }
327
328 fn next_inode_no(&self) -> u64 {
330 static NEXT_INODE: AtomicU64 = AtomicU64::new(2);
331 NEXT_INODE.fetch_add(1, Ordering::Relaxed)
332 }
333}
334
335impl Inode for SimpleFsInode {
336 fn metadata(&self) -> Result<InodeMetadata, FsError> {
337 let data = self.data.lock();
338 Ok(InodeMetadata {
339 inode_no: self.inode_no,
340 inode_type: self.inode_type,
341 mode: self.mode.clone(),
342 uid: 0,
343 gid: 0,
344 size: data.len(),
345 atime: TimeSpec::now(),
346 mtime: TimeSpec::now(),
347 ctime: TimeSpec::now(),
348 nlinks: 1,
349 blocks: (data.len() + 511) / 512,
350 rdev: 0,
351 })
352 }
353
354 fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, FsError> {
355 if self.inode_type == InodeType::Directory {
356 return Err(FsError::IsDirectory);
357 }
358
359 let data = self.data.lock();
360 if offset >= data.len() {
361 return Ok(0);
362 }
363 let len = core::cmp::min(buf.len(), data.len() - offset);
364
365 buf[..len].copy_from_slice(&data[offset..offset + len]);
366 Ok(len)
367 }
368
369 fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, FsError> {
370 if self.inode_type == InodeType::Directory {
371 return Err(FsError::IsDirectory);
372 }
373
374 let mut data = self.data.lock();
375 if offset + buf.len() > data.len() {
376 data.resize(offset + buf.len(), 0);
377 }
378 data[offset..offset + buf.len()].copy_from_slice(buf);
379 Ok(buf.len())
380 }
381
382 fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>, FsError> {
383 if self.inode_type != InodeType::Directory {
384 return Err(FsError::NotDirectory);
385 }
386 self.children
387 .lock()
388 .get(name)
389 .cloned()
390 .ok_or(FsError::NotFound)
391 .map(|inode| inode as Arc<dyn Inode>)
392 }
393
394 fn create(&self, name: &str, mode: FileMode) -> Result<Arc<dyn Inode>, FsError> {
395 if self.inode_type != InodeType::Directory {
396 return Err(FsError::NotDirectory);
397 }
398
399 let mut children = self.children.lock();
400 if children.contains_key(name) {
401 return Err(FsError::AlreadyExists);
402 }
403
404 let new_inode = Arc::new(SimpleFsInode::new_file((children.len() + 2) as u64, mode));
405 children.insert(String::from(name), new_inode.clone());
406
407 Ok(new_inode as Arc<dyn Inode>)
408 }
409
410 fn mkdir(&self, name: &str, mode: FileMode) -> Result<Arc<dyn Inode>, FsError> {
411 if self.inode_type != InodeType::Directory {
412 return Err(FsError::NotDirectory);
413 }
414
415 let mut children = self.children.lock();
416 if children.contains_key(name) {
417 return Err(FsError::AlreadyExists);
418 }
419
420 let new_inode = Arc::new(SimpleFsInode::new_dir((children.len() + 2) as u64, mode));
421 children.insert(String::from(name), new_inode.clone());
422
423 Ok(new_inode as Arc<dyn Inode>)
424 }
425
426 fn unlink(&self, name: &str) -> Result<(), FsError> {
427 if self.inode_type != InodeType::Directory {
428 return Err(FsError::NotDirectory);
429 }
430
431 let mut children = self.children.lock();
432 children.remove(name).ok_or(FsError::NotFound)?;
433 Ok(())
434 }
435
436 fn readdir(&self) -> Result<Vec<DirEntry>, FsError> {
437 if self.inode_type != InodeType::Directory {
438 return Err(FsError::NotDirectory);
439 }
440
441 let children = self.children.lock();
442 let mut entries = Vec::new();
443
444 for (name, child) in children.iter() {
445 entries.push(DirEntry {
446 name: name.clone(),
447 inode_no: child.inode_no,
448 inode_type: child.inode_type,
449 });
450 }
451
452 Ok(entries)
453 }
454
455 fn truncate(&self, size: usize) -> Result<(), FsError> {
456 let mut data = self.data.lock();
457 data.resize(size, 0);
458 Ok(())
459 }
460
461 fn sync(&self) -> Result<(), FsError> {
462 Ok(())
463 }
464
465 fn as_any(&self) -> &dyn core::any::Any {
466 self as &dyn core::any::Any
467 }
468
469 fn symlink(&self, _name: &str, _target: &str) -> Result<Arc<dyn Inode>, FsError> {
470 Err(FsError::NotSupported)
471 }
472
473 fn link(&self, _name: &str, _target: &Arc<dyn Inode>) -> Result<(), FsError> {
474 Err(FsError::NotSupported)
475 }
476
477 fn rmdir(&self, _name: &str) -> Result<(), FsError> {
478 Err(FsError::NotSupported)
479 }
480
481 fn rename(
482 &self,
483 _old_name: &str,
484 _new_parent: Arc<dyn Inode>,
485 _new_name: &str,
486 ) -> Result<(), FsError> {
487 Err(FsError::NotSupported)
488 }
489
490 fn set_times(&self, _atime: Option<TimeSpec>, _mtime: Option<TimeSpec>) -> Result<(), FsError> {
491 Err(FsError::NotSupported)
492 }
493
494 fn readlink(&self) -> Result<String, FsError> {
495 Err(FsError::NotSupported)
496 }
497
498 fn mknod(&self, _name: &str, _mode: FileMode, _dev: u64) -> Result<Arc<dyn Inode>, FsError> {
499 Err(FsError::NotSupported)
500 }
501
502 fn chmod(&self, _mode: FileMode) -> Result<(), FsError> {
503 Err(FsError::NotSupported)
504 }
505
506 fn chown(&self, _uid: u32, _gid: u32) -> Result<(), FsError> {
507 Err(FsError::NotSupported)
508 }
509}