Skip to main content

proka_kernel/fs/fs_impl/
memfs.rs

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        // File operations on directory should fail
627        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}