1extern crate alloc;
2use crate::drivers::Device;
3use crate::fs::vfs::{FileSystem, Inode, Metadata, VNodeType, VfsError};
4use alloc::{
5 collections::BTreeMap,
6 string::{String, ToString},
7 sync::Arc,
8 vec::Vec,
9};
10use core::any::Any;
11use core::sync::atomic::{AtomicUsize, Ordering};
12use spin::RwLock;
13
14static NEXT_INODE_ID: AtomicUsize = AtomicUsize::new(1);
15
16fn create_metadata(node_type: VNodeType, size: u64) -> Metadata {
17 let permissions = match node_type {
18 VNodeType::Dir => 0o755,
19 VNodeType::File => 0o644,
20 VNodeType::SymLink => 0o777,
21 VNodeType::Device => 0o600,
22 };
23 Metadata {
24 size,
25 permissions,
26 uid: 0,
27 gid: 0,
28 ctime: 0,
29 mtime: 0,
30 blocks: size.div_ceil(512),
31 nlinks: 1,
32 }
33}
34
35#[derive(Debug)]
36pub enum MemNodeContent {
37 File {
38 data: Arc<RwLock<Vec<u8>>>,
39 },
40 Dir {
41 entries: RwLock<BTreeMap<String, Arc<MemVNode>>>,
42 },
43 SymLink {
44 target: String,
45 },
46 Device {
47 device: Arc<Device>,
48 },
49}
50
51#[derive(Debug)]
52pub struct MemVNode {
53 #[allow(dead_code)]
54 id: usize,
55 node_type: VNodeType,
56 metadata: RwLock<Metadata>,
57 content: MemNodeContent,
58}
59
60impl MemVNode {
61 fn new(node_type: VNodeType, content: MemNodeContent) -> Arc<Self> {
62 let id = NEXT_INODE_ID.fetch_add(1, Ordering::Relaxed);
63 let size = match &content {
64 MemNodeContent::File { data } => data.read().len() as u64,
65 MemNodeContent::Dir { .. } => 0,
66 MemNodeContent::SymLink { target } => target.len() as u64,
67 MemNodeContent::Device { .. } => 0,
68 };
69 Arc::new(Self {
70 id,
71 node_type,
72 metadata: RwLock::new(create_metadata(node_type, size)),
73 content,
74 })
75 }
76
77 fn update_mtime(&self) {}
78
79 fn update_size(&self, new_size: u64) {
80 let mut meta = self.metadata.write();
81 meta.size = new_size;
82 meta.blocks = new_size.div_ceil(512);
83 }
84
85 pub fn move_node(
86 source_parent: &Self,
87 target_parent: &Self,
88 old_name: &str,
89 new_name: &str,
90 ) -> Result<(), VfsError> {
91 let source_entries = match &source_parent.content {
92 MemNodeContent::Dir { entries } => entries,
93 _ => return Err(VfsError::NotADirectory),
94 };
95
96 let target_entries = match &target_parent.content {
97 MemNodeContent::Dir { entries } => entries,
98 _ => return Err(VfsError::NotADirectory),
99 };
100
101 let node_to_move = {
102 let source_read = source_entries.read();
103 source_read.get(old_name).ok_or(VfsError::NotFound)?.clone()
104 };
105
106 {
107 let target_read = target_entries.read();
108 if target_read.contains_key(new_name) {
109 return Err(VfsError::AlreadyExists);
110 }
111 }
112
113 {
114 let mut source_write = source_entries.write();
115 source_write.remove(old_name);
116 }
117
118 {
119 let mut target_write = target_entries.write();
120 target_write.insert(new_name.to_string(), node_to_move);
121 }
122
123 source_parent.update_mtime();
124 target_parent.update_mtime();
125
126 Ok(())
127 }
128}
129
130impl Inode for MemVNode {
131 fn metadata(&self) -> Result<Metadata, VfsError> {
132 Ok(self.metadata.read().clone())
133 }
134
135 fn set_metadata(&self, metadata: &Metadata) -> Result<(), VfsError> {
136 *self.metadata.write() = metadata.clone();
137 Ok(())
138 }
139
140 fn node_type(&self) -> VNodeType {
141 self.node_type
142 }
143
144 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize, VfsError> {
145 match &self.content {
146 MemNodeContent::File { data } => {
147 let data = data.read();
148 let data_len = data.len() as u64;
149 if offset >= data_len {
150 return Ok(0);
151 }
152 let bytes_to_read = (data_len - offset).min(buf.len() as u64) as usize;
153 let start = offset as usize;
154 let end = start + bytes_to_read;
155 buf[..bytes_to_read].copy_from_slice(&data[start..end]);
156 Ok(bytes_to_read)
157 }
158 MemNodeContent::Device { device } => {
159 if let Some(char_dev) = device.as_char_device() {
160 char_dev.read(buf).map_err(VfsError::DeviceError)
161 } else {
162 Err(VfsError::NotImplemented)
163 }
164 }
165 _ => Err(VfsError::NotAFile),
166 }
167 }
168
169 fn write_at(&self, offset: u64, buf: &[u8]) -> Result<usize, VfsError> {
170 match &self.content {
171 MemNodeContent::File { data } => {
172 let mut data = data.write();
173 let start = offset as usize;
174 let end = start + buf.len();
175
176 if end > data.len() {
177 data.resize(end, 0);
178 }
179
180 data[start..end].copy_from_slice(buf);
181
182 let new_len = data.len() as u64;
183 drop(data);
184 self.update_size(new_len);
185
186 Ok(buf.len())
187 }
188 MemNodeContent::Device { device } => {
189 if let Some(char_dev) = device.as_char_device() {
190 char_dev.write(buf).map_err(VfsError::DeviceError)
191 } else {
192 Err(VfsError::NotImplemented)
193 }
194 }
195 _ => Err(VfsError::NotAFile),
196 }
197 }
198
199 fn truncate(&self, size: u64) -> Result<(), VfsError> {
200 match &self.content {
201 MemNodeContent::File { data } => {
202 let mut data = data.write();
203 data.resize(size as usize, 0);
204 let new_len = data.len() as u64;
205 drop(data);
206 self.update_size(new_len);
207 Ok(())
208 }
209 _ => Err(VfsError::NotImplemented),
210 }
211 }
212
213 fn sync(&self) -> Result<(), VfsError> {
214 Ok(())
215 }
216
217 fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>, VfsError> {
218 match &self.content {
219 MemNodeContent::Dir { entries } => {
220 let entries = entries.read();
221 entries
222 .get(name)
223 .cloned()
224 .map(|node| node as Arc<dyn Inode>)
225 .ok_or(VfsError::NotFound)
226 }
227 _ => Err(VfsError::NotADirectory),
228 }
229 }
230
231 fn create(&self, name: &str, typ: VNodeType) -> Result<Arc<dyn Inode>, VfsError> {
232 match &self.content {
233 MemNodeContent::Dir { entries } => {
234 let mut entries = entries.write();
235 if entries.contains_key(name) {
236 return Err(VfsError::AlreadyExists);
237 }
238
239 let new_node = match typ {
240 VNodeType::File => MemVNode::new(
241 VNodeType::File,
242 MemNodeContent::File {
243 data: Arc::new(RwLock::new(Vec::new())),
244 },
245 ),
246 VNodeType::Dir => MemVNode::new(
247 VNodeType::Dir,
248 MemNodeContent::Dir {
249 entries: RwLock::new(BTreeMap::new()),
250 },
251 ),
252 _ => return Err(VfsError::NotImplemented),
253 };
254
255 entries.insert(name.to_string(), new_node.clone());
256 self.update_mtime();
257 Ok(new_node)
258 }
259 _ => Err(VfsError::NotADirectory),
260 }
261 }
262
263 fn create_symlink(&self, name: &str, target: &str) -> Result<Arc<dyn Inode>, VfsError> {
264 match &self.content {
265 MemNodeContent::Dir { entries } => {
266 let mut entries = entries.write();
267 if entries.contains_key(name) {
268 return Err(VfsError::AlreadyExists);
269 }
270 let new_node = MemVNode::new(
271 VNodeType::SymLink,
272 MemNodeContent::SymLink {
273 target: target.to_string(),
274 },
275 );
276 entries.insert(name.to_string(), new_node.clone());
277 self.update_mtime();
278 Ok(new_node)
279 }
280 _ => Err(VfsError::NotADirectory),
281 }
282 }
283
284 fn create_device(&self, name: &str, device: Arc<Device>) -> Result<Arc<dyn Inode>, VfsError> {
285 match &self.content {
286 MemNodeContent::Dir { entries } => {
287 let mut entries = entries.write();
288 if entries.contains_key(name) {
289 return Err(VfsError::AlreadyExists);
290 }
291
292 let new_node = MemVNode::new(VNodeType::Device, MemNodeContent::Device { device });
293 entries.insert(name.to_string(), new_node.clone());
294 self.update_mtime();
295 Ok(new_node)
296 }
297 _ => Err(VfsError::NotADirectory),
298 }
299 }
300
301 fn unlink(&self, name: &str) -> Result<(), VfsError> {
302 match &self.content {
303 MemNodeContent::Dir { entries } => {
304 let mut entries = entries.write();
305 if let Some(node) = entries.get(name) {
306 if node.node_type() == VNodeType::Dir {
307 if let MemNodeContent::Dir {
308 entries: sub_entries,
309 } = &node.content
310 {
311 if !sub_entries.read().is_empty() {
312 return Err(VfsError::DirectoryNotEmpty);
313 }
314 }
315 }
316 entries.remove(name);
317 self.update_mtime();
318 Ok(())
319 } else {
320 Err(VfsError::NotFound)
321 }
322 }
323 _ => Err(VfsError::NotADirectory),
324 }
325 }
326
327 fn rename(&self, old_name: &str, new_name: &str) -> Result<(), VfsError> {
328 match &self.content {
329 MemNodeContent::Dir { entries } => {
330 let mut entries = entries.write();
331 if !entries.contains_key(old_name) {
332 return Err(VfsError::NotFound);
333 }
334 if entries.contains_key(new_name) {
335 return Err(VfsError::AlreadyExists);
336 }
337 let node = entries.remove(old_name).unwrap();
338 entries.insert(new_name.to_string(), node);
339 self.update_mtime();
340 Ok(())
341 }
342 _ => Err(VfsError::NotADirectory),
343 }
344 }
345
346 fn list(&self) -> Result<Vec<String>, VfsError> {
347 match &self.content {
348 MemNodeContent::Dir { entries } => Ok(entries.read().keys().cloned().collect()),
349 _ => Err(VfsError::NotADirectory),
350 }
351 }
352
353 fn read_symlink(&self) -> Result<String, VfsError> {
354 match &self.content {
355 MemNodeContent::SymLink { target } => Ok(target.clone()),
356 _ => Err(VfsError::NotAFile),
357 }
358 }
359
360 fn as_any(&self) -> &dyn Any {
361 self
362 }
363}
364
365pub struct MemFs;
366
367impl FileSystem for MemFs {
368 fn mount(
369 &self,
370 _device: Option<Arc<Device>>,
371 _args: Option<&[&str]>,
372 ) -> Result<Arc<dyn Inode>, VfsError> {
373 let root_dir = MemVNode::new(
374 VNodeType::Dir,
375 MemNodeContent::Dir {
376 entries: RwLock::new(BTreeMap::new()),
377 },
378 );
379 Ok(root_dir)
380 }
381
382 fn fs_type(&self) -> &'static str {
383 "memfs"
384 }
385}
386
387#[cfg(test)]
388mod tests {
389 use super::*;
390 use alloc::vec;
391
392 #[test_case]
393 fn test_mount_creates_root() {
394 let fs = MemFs;
395 let root = fs.mount(None, None).unwrap();
396 assert_eq!(root.node_type(), VNodeType::Dir);
397 }
398
399 #[test_case]
400 fn test_create_file() {
401 let fs = MemFs;
402 let root = fs.mount(None, None).unwrap();
403
404 let file = root.create("test.txt", VNodeType::File).unwrap();
405 assert_eq!(file.node_type(), VNodeType::File);
406
407 let metadata = file.metadata().unwrap();
408 assert_eq!(metadata.size, 0);
409 }
410
411 #[test_case]
412 fn test_create_dir() {
413 let fs = MemFs;
414 let root = fs.mount(None, None).unwrap();
415
416 let dir = root.create("testdir", VNodeType::Dir).unwrap();
417 assert_eq!(dir.node_type(), VNodeType::Dir);
418
419 let metadata = dir.metadata().unwrap();
420 assert_eq!(metadata.size, 0);
421 }
422
423 #[test_case]
424 fn test_create_duplicate_fails() {
425 let fs = MemFs;
426 let root = fs.mount(None, None).unwrap();
427
428 root.create("test.txt", VNodeType::File).unwrap();
429 let result = root.create("test.txt", VNodeType::File);
430 assert!(matches!(result, Err(VfsError::AlreadyExists)));
431 }
432
433 #[test_case]
434 fn test_lookup() {
435 let fs = MemFs;
436 let root = fs.mount(None, None).unwrap();
437
438 root.create("test.txt", VNodeType::File).unwrap();
439 let file = root.lookup("test.txt").unwrap();
440 assert_eq!(file.node_type(), VNodeType::File);
441 }
442
443 #[test_case]
444 fn test_lookup_not_found() {
445 let fs = MemFs;
446 let root = fs.mount(None, None).unwrap();
447
448 let result = root.lookup("nonexistent.txt");
449 assert!(matches!(result, Err(VfsError::NotFound)));
450 }
451
452 #[test_case]
453 fn test_write_and_read() {
454 let fs = MemFs;
455 let root = fs.mount(None, None).unwrap();
456
457 let file = root.create("test.txt", VNodeType::File).unwrap();
458 let data = b"Hello, World!";
459 let written = file.write_at(0, data).unwrap();
460 assert_eq!(written, data.len());
461
462 let mut buffer = vec![0u8; data.len()];
463 let read = file.read_at(0, &mut buffer).unwrap();
464 assert_eq!(read, data.len());
465 assert_eq!(&buffer, data);
466
467 let metadata = file.metadata().unwrap();
468 assert_eq!(metadata.size, data.len() as u64);
469 }
470
471 #[test_case]
472 fn test_write_at_offset() {
473 let fs = MemFs;
474 let root = fs.mount(None, None).unwrap();
475
476 let file = root.create("test.txt", VNodeType::File).unwrap();
477 file.write_at(0, b"Hello, ").unwrap();
478 file.write_at(7, b"World!").unwrap();
479
480 let mut buffer = vec![0u8; 13];
481 file.read_at(0, &mut buffer).unwrap();
482 assert_eq!(&buffer, b"Hello, World!");
483 }
484
485 #[test_case]
486 fn test_read_beyond_file() {
487 let fs = MemFs;
488 let root = fs.mount(None, None).unwrap();
489
490 let file = root.create("test.txt", VNodeType::File).unwrap();
491 file.write_at(0, b"Hello").unwrap();
492
493 let mut buffer = vec![0u8; 10];
494 let read = file.read_at(0, &mut buffer).unwrap();
495 assert_eq!(read, 5);
496 }
497
498 #[test_case]
499 fn test_truncate() {
500 let fs = MemFs;
501 let root = fs.mount(None, None).unwrap();
502
503 let file = root.create("test.txt", VNodeType::File).unwrap();
504 file.write_at(0, b"Hello, World!").unwrap();
505
506 file.truncate(5).unwrap();
507 let metadata = file.metadata().unwrap();
508 assert_eq!(metadata.size, 5);
509
510 let mut buffer = vec![0u8; 10];
511 let read = file.read_at(0, &mut buffer).unwrap();
512 assert_eq!(read, 5);
513 assert_eq!(&buffer[..5], b"Hello");
514 }
515
516 #[test_case]
517 fn test_truncate_extend() {
518 let fs = MemFs;
519 let root = fs.mount(None, None).unwrap();
520
521 let file = root.create("test.txt", VNodeType::File).unwrap();
522 file.write_at(0, b"Hello").unwrap();
523
524 file.truncate(10).unwrap();
525 let metadata = file.metadata().unwrap();
526 assert_eq!(metadata.size, 10);
527
528 let mut buffer = vec![0u8; 10];
529 file.read_at(0, &mut buffer).unwrap();
530 assert_eq!(&buffer[..5], b"Hello");
531 assert_eq!(&buffer[5..], b"\x00\x00\x00\x00\x00");
532 }
533
534 #[test_case]
535 fn test_list() {
536 let fs = MemFs;
537 let root = fs.mount(None, None).unwrap();
538
539 root.create("file1.txt", VNodeType::File).unwrap();
540 root.create("file2.txt", VNodeType::File).unwrap();
541 root.create("dir1", VNodeType::Dir).unwrap();
542
543 let entries = root.list().unwrap();
544 assert_eq!(entries.len(), 3);
545 assert!(entries.contains(&String::from("file1.txt")));
546 assert!(entries.contains(&String::from("file2.txt")));
547 assert!(entries.contains(&String::from("dir1")));
548 }
549
550 #[test_case]
551 fn test_unlink() {
552 let fs = MemFs;
553 let root = fs.mount(None, None).unwrap();
554
555 root.create("test.txt", VNodeType::File).unwrap();
556 root.unlink("test.txt").unwrap();
557
558 let result = root.lookup("test.txt");
559 assert!(matches!(result, Err(VfsError::NotFound)));
560 }
561
562 #[test_case]
563 fn test_unlink_not_found() {
564 let fs = MemFs;
565 let root = fs.mount(None, None).unwrap();
566
567 let result = root.unlink("nonexistent.txt");
568 assert!(matches!(result, Err(VfsError::NotFound)));
569 }
570
571 #[test_case]
572 fn test_rename() {
573 let fs = MemFs;
574 let root = fs.mount(None, None).unwrap();
575
576 root.create("old.txt", VNodeType::File).unwrap();
577 root.rename("old.txt", "new.txt").unwrap();
578
579 let result = root.lookup("old.txt");
580 assert!(matches!(result, Err(VfsError::NotFound)));
581
582 let file = root.lookup("new.txt").unwrap();
583 assert_eq!(file.node_type(), VNodeType::File);
584 }
585
586 #[test_case]
587 fn test_rename_not_found() {
588 let fs = MemFs;
589 let root = fs.mount(None, None).unwrap();
590
591 let result = root.rename("old.txt", "new.txt");
592 assert!(matches!(result, Err(VfsError::NotFound)));
593 }
594
595 #[test_case]
596 fn test_rename_already_exists() {
597 let fs = MemFs;
598 let root = fs.mount(None, None).unwrap();
599
600 root.create("file1.txt", VNodeType::File).unwrap();
601 root.create("file2.txt", VNodeType::File).unwrap();
602
603 let result = root.rename("file1.txt", "file2.txt");
604 assert!(matches!(result, Err(VfsError::AlreadyExists)));
605 }
606
607 #[test_case]
608 fn test_create_symlink() {
609 let fs = MemFs;
610 let root = fs.mount(None, None).unwrap();
611
612 let link = root.create_symlink("link.txt", "target.txt").unwrap();
613 assert_eq!(link.node_type(), VNodeType::SymLink);
614
615 let target = link.read_symlink().unwrap();
616 assert_eq!(target, "target.txt");
617 }
618
619 #[test_case]
620 fn test_directory_operations() {
621 let fs = MemFs;
622 let root = fs.mount(None, None).unwrap();
623
624 let dir = root.create("testdir", VNodeType::Dir).unwrap();
625
626 let result = dir.read_at(0, &mut [0u8; 10]);
628 assert!(matches!(result, Err(VfsError::NotAFile)));
629
630 let result = dir.write_at(0, b"test");
631 assert!(matches!(result, Err(VfsError::NotAFile)));
632 }
633
634 #[test_case]
635 fn test_nested_directories() {
636 let fs = MemFs;
637 let root = fs.mount(None, None).unwrap();
638
639 let dir1 = root.create("dir1", VNodeType::Dir).unwrap();
640 let dir2 = dir1.create("dir2", VNodeType::Dir).unwrap();
641 let file = dir2.create("file.txt", VNodeType::File).unwrap();
642
643 file.write_at(0, b"nested").unwrap();
644
645 let lookup = dir2.lookup("file.txt").unwrap();
646 let mut buffer = vec![0u8; 6];
647 lookup.read_at(0, &mut buffer).unwrap();
648 assert_eq!(&buffer, b"nested");
649 }
650
651 #[test_case]
652 fn test_unlink_non_empty_dir() {
653 let fs = MemFs;
654 let root = fs.mount(None, None).unwrap();
655
656 let dir = root.create("testdir", VNodeType::Dir).unwrap();
657 dir.create("file.txt", VNodeType::File).unwrap();
658
659 let result = root.unlink("testdir");
660 assert!(matches!(result, Err(VfsError::DirectoryNotEmpty)));
661 }
662}