⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/fs/
ramfs.rs

1//! RAM Filesystem Implementation
2//!
3//! A simple in-memory filesystem for testing and temporary storage.
4
5use alloc::{collections::BTreeMap, string::String, sync::Arc, vec, vec::Vec};
6
7#[cfg(not(target_arch = "aarch64"))]
8use spin::RwLock;
9
10#[cfg(target_arch = "aarch64")]
11use super::bare_lock::RwLock;
12use super::{DirEntry, Filesystem, Metadata, NodeType, Permissions, VfsNode};
13use crate::error::{FsError, KernelError};
14
15/// RAM filesystem node
16struct RamNode {
17    /// Node type
18    node_type: NodeType,
19
20    /// File data (for files)
21    data: RwLock<Vec<u8>>,
22
23    /// Children (for directories)
24    children: RwLock<BTreeMap<String, Arc<RamNode>>>,
25
26    /// Metadata
27    metadata: RwLock<Metadata>,
28
29    /// Inode number
30    inode: u64,
31
32    /// Parent directory inode (for ".." entries)
33    parent_inode: u64,
34}
35
36impl RamNode {
37    /// Create a new file node
38    fn new_file(inode: u64, parent_inode: u64, permissions: Permissions) -> Self {
39        Self {
40            node_type: NodeType::File,
41            data: RwLock::new(Vec::new()),
42            children: RwLock::new(BTreeMap::new()),
43            metadata: RwLock::new(Metadata {
44                node_type: NodeType::File,
45                size: 0,
46                permissions,
47                uid: 0,
48                gid: 0,
49                created: crate::arch::timer::get_timestamp_secs(),
50                modified: crate::arch::timer::get_timestamp_secs(),
51                accessed: crate::arch::timer::get_timestamp_secs(),
52                inode,
53            }),
54            inode,
55            parent_inode,
56        }
57    }
58
59    /// Create a new directory node
60    fn new_directory(inode: u64, parent_inode: u64, permissions: Permissions) -> Self {
61        Self {
62            node_type: NodeType::Directory,
63            data: RwLock::new(Vec::new()),
64            children: RwLock::new(BTreeMap::new()),
65            metadata: RwLock::new(Metadata {
66                node_type: NodeType::Directory,
67                size: 0,
68                permissions,
69                uid: 0,
70                gid: 0,
71                created: crate::arch::timer::get_timestamp_secs(),
72                modified: crate::arch::timer::get_timestamp_secs(),
73                accessed: crate::arch::timer::get_timestamp_secs(),
74                inode,
75            }),
76            inode,
77            parent_inode,
78        }
79    }
80
81    /// Create a new symbolic link node.
82    ///
83    /// The target path is stored in the node's `data` field.
84    fn new_symlink(inode: u64, parent_inode: u64, target: &str) -> Self {
85        let target_bytes = Vec::from(target.as_bytes());
86        let size = target_bytes.len();
87        Self {
88            node_type: NodeType::Symlink,
89            data: RwLock::new(target_bytes),
90            children: RwLock::new(BTreeMap::new()),
91            metadata: RwLock::new(Metadata {
92                node_type: NodeType::Symlink,
93                size,
94                permissions: Permissions::from_mode(0o777),
95                uid: 0,
96                gid: 0,
97                created: crate::arch::timer::get_timestamp_secs(),
98                modified: crate::arch::timer::get_timestamp_secs(),
99                accessed: crate::arch::timer::get_timestamp_secs(),
100                inode,
101            }),
102            inode,
103            parent_inode,
104        }
105    }
106}
107
108impl VfsNode for RamNode {
109    fn node_type(&self) -> NodeType {
110        self.node_type
111    }
112
113    fn read(&self, offset: usize, buffer: &mut [u8]) -> Result<usize, crate::error::KernelError> {
114        if self.node_type != NodeType::File {
115            return Err(KernelError::FsError(FsError::NotAFile));
116        }
117
118        let data = self.data.read();
119        if offset >= data.len() {
120            return Ok(0);
121        }
122
123        let bytes_to_read = core::cmp::min(buffer.len(), data.len() - offset);
124        buffer[..bytes_to_read].copy_from_slice(&data[offset..offset + bytes_to_read]);
125
126        // Update accessed time
127        self.metadata.write().accessed = crate::arch::timer::get_timestamp_secs();
128
129        Ok(bytes_to_read)
130    }
131
132    fn write(&self, offset: usize, data: &[u8]) -> Result<usize, crate::error::KernelError> {
133        if self.node_type != NodeType::File {
134            return Err(KernelError::FsError(FsError::NotAFile));
135        }
136
137        let mut file_data = self.data.write();
138
139        // Extend file if necessary
140        if offset > file_data.len() {
141            file_data.resize(offset, 0);
142        }
143
144        // Write data
145        if offset + data.len() > file_data.len() {
146            file_data.resize(offset + data.len(), 0);
147        }
148        file_data[offset..offset + data.len()].copy_from_slice(data);
149
150        // Update metadata
151        let mut metadata = self.metadata.write();
152        metadata.size = file_data.len();
153        metadata.modified = crate::arch::timer::get_timestamp_secs();
154
155        Ok(data.len())
156    }
157
158    fn metadata(&self) -> Result<Metadata, crate::error::KernelError> {
159        Ok(self.metadata.read().clone())
160    }
161
162    fn readdir(&self) -> Result<Vec<DirEntry>, crate::error::KernelError> {
163        if self.node_type != NodeType::Directory {
164            return Err(KernelError::FsError(FsError::NotADirectory));
165        }
166
167        let children = self.children.read();
168        let mut entries = Vec::new();
169
170        // Add . and .. entries
171        entries.push(DirEntry {
172            name: String::from("."),
173            node_type: NodeType::Directory,
174            inode: self.inode,
175        });
176
177        entries.push(DirEntry {
178            name: String::from(".."),
179            node_type: NodeType::Directory,
180            inode: self.parent_inode,
181        });
182
183        // Add children
184        for (name, child) in children.iter() {
185            entries.push(DirEntry {
186                name: name.clone(),
187                node_type: child.node_type,
188                inode: child.inode,
189            });
190        }
191
192        Ok(entries)
193    }
194
195    fn lookup(&self, name: &str) -> Result<Arc<dyn VfsNode>, crate::error::KernelError> {
196        if self.node_type != NodeType::Directory {
197            return Err(KernelError::FsError(FsError::NotADirectory));
198        }
199
200        let children = self.children.read();
201        children
202            .get(name)
203            .map(|node| node.clone() as Arc<dyn VfsNode>)
204            .ok_or(KernelError::FsError(FsError::NotFound))
205    }
206
207    fn create(
208        &self,
209        name: &str,
210        permissions: Permissions,
211    ) -> Result<Arc<dyn VfsNode>, crate::error::KernelError> {
212        if self.node_type != NodeType::Directory {
213            return Err(KernelError::FsError(FsError::NotADirectory));
214        }
215
216        let mut children = self.children.write();
217
218        if children.contains_key(name) {
219            return Err(KernelError::FsError(FsError::AlreadyExists));
220        }
221
222        let inode = NEXT_INODE.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
223        let new_file = Arc::new(RamNode::new_file(inode, self.inode, permissions));
224        children.insert(String::from(name), new_file.clone());
225
226        Ok(new_file as Arc<dyn VfsNode>)
227    }
228
229    fn mkdir(
230        &self,
231        name: &str,
232        permissions: Permissions,
233    ) -> Result<Arc<dyn VfsNode>, crate::error::KernelError> {
234        if self.node_type != NodeType::Directory {
235            return Err(KernelError::FsError(FsError::NotADirectory));
236        }
237
238        let mut children = self.children.write();
239
240        if children.contains_key(name) {
241            return Err(KernelError::FsError(FsError::AlreadyExists));
242        }
243
244        let inode = NEXT_INODE.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
245        let new_dir = Arc::new(RamNode::new_directory(inode, self.inode, permissions));
246        children.insert(String::from(name), new_dir.clone());
247
248        Ok(new_dir as Arc<dyn VfsNode>)
249    }
250
251    fn unlink(&self, name: &str) -> Result<(), crate::error::KernelError> {
252        if self.node_type != NodeType::Directory {
253            return Err(KernelError::FsError(FsError::NotADirectory));
254        }
255
256        let mut children = self.children.write();
257
258        if let Some(node) = children.get(name) {
259            if node.node_type == NodeType::Directory {
260                // Check if directory is empty
261                let dir_children = node.children.read();
262                if !dir_children.is_empty() {
263                    return Err(KernelError::FsError(FsError::DirectoryNotEmpty));
264                }
265            }
266
267            children.remove(name);
268            Ok(())
269        } else {
270            Err(KernelError::FsError(FsError::NotFound))
271        }
272    }
273
274    fn truncate(&self, size: usize) -> Result<(), crate::error::KernelError> {
275        if self.node_type != NodeType::File {
276            return Err(KernelError::FsError(FsError::NotAFile));
277        }
278
279        let mut data = self.data.write();
280        data.resize(size, 0);
281
282        let mut metadata = self.metadata.write();
283        metadata.size = size;
284        metadata.modified = crate::arch::timer::get_timestamp_secs();
285
286        Ok(())
287    }
288
289    fn link(&self, name: &str, target: Arc<dyn VfsNode>) -> Result<(), KernelError> {
290        if self.node_type != NodeType::Directory {
291            return Err(KernelError::FsError(FsError::NotADirectory));
292        }
293
294        // Hard links to directories are not allowed (POSIX)
295        if target.node_type() == NodeType::Directory {
296            return Err(KernelError::FsError(FsError::IsADirectory));
297        }
298
299        let mut children = self.children.write();
300        if children.contains_key(name) {
301            return Err(KernelError::FsError(FsError::AlreadyExists));
302        }
303
304        // RamFS hard link: create a new node that copies the target's data
305        // and shares the same inode number. This provides POSIX-compatible
306        // semantics (same inode visible via stat) although the data is
307        // copied rather than shared. True shared-data hard links would
308        // require Arc downcasting or a different internal representation.
309        let target_meta = target.metadata()?;
310        let inode = target_meta.inode;
311
312        let new_node = Arc::new(RamNode::new_file(
313            inode,
314            self.inode,
315            target_meta.permissions,
316        ));
317
318        // Copy file data from the target
319        let mut buf = vec![0u8; target_meta.size];
320        if !buf.is_empty() {
321            let bytes_read = target.read(0, &mut buf)?;
322            buf.truncate(bytes_read);
323        }
324        if !buf.is_empty() {
325            new_node.write(0, &buf)?;
326        }
327
328        children.insert(String::from(name), new_node);
329        Ok(())
330    }
331
332    fn symlink(&self, name: &str, target: &str) -> Result<Arc<dyn VfsNode>, KernelError> {
333        if self.node_type != NodeType::Directory {
334            return Err(KernelError::FsError(FsError::NotADirectory));
335        }
336
337        let mut children = self.children.write();
338        if children.contains_key(name) {
339            return Err(KernelError::FsError(FsError::AlreadyExists));
340        }
341
342        let inode = NEXT_INODE.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
343        let new_symlink = Arc::new(RamNode::new_symlink(inode, self.inode, target));
344        children.insert(String::from(name), new_symlink.clone());
345
346        Ok(new_symlink as Arc<dyn VfsNode>)
347    }
348
349    fn readlink(&self) -> Result<String, KernelError> {
350        if self.node_type != NodeType::Symlink {
351            return Err(KernelError::FsError(FsError::NotASymlink));
352        }
353
354        let data = self.data.read();
355        let s =
356            core::str::from_utf8(&data).map_err(|_| KernelError::FsError(FsError::InvalidPath))?;
357        Ok(String::from(s))
358    }
359
360    fn chmod(&self, permissions: Permissions) -> Result<(), KernelError> {
361        let mut metadata = self.metadata.write();
362        metadata.permissions = permissions;
363        metadata.modified = crate::arch::timer::get_timestamp_secs();
364        Ok(())
365    }
366}
367
368/// Global inode counter
369static NEXT_INODE: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(1);
370
371/// RAM filesystem
372pub struct RamFs {
373    root: Arc<RamNode>,
374}
375
376impl RamFs {
377    /// Create a new RAM filesystem
378    pub fn new() -> Self {
379        let root_inode = NEXT_INODE.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
380        // Root directory's parent is itself (standard POSIX behavior)
381        let root = Arc::new(RamNode::new_directory(
382            root_inode,
383            root_inode,
384            Permissions::default(),
385        ));
386
387        Self { root }
388    }
389}
390
391impl Default for RamFs {
392    fn default() -> Self {
393        Self::new()
394    }
395}
396
397impl Filesystem for RamFs {
398    fn root(&self) -> Arc<dyn VfsNode> {
399        self.root.clone() as Arc<dyn VfsNode>
400    }
401
402    fn name(&self) -> &str {
403        "ramfs"
404    }
405
406    fn is_readonly(&self) -> bool {
407        false
408    }
409
410    fn sync(&self) -> Result<(), crate::error::KernelError> {
411        // RAM filesystem doesn't need syncing
412        Ok(())
413    }
414}
415
416#[cfg(test)]
417mod tests {
418    use alloc::vec;
419
420    use super::*;
421
422    // --- RamFs construction tests ---
423
424    #[test]
425    fn test_ramfs_new() {
426        let fs = RamFs::new();
427        assert_eq!(fs.name(), "ramfs");
428        assert!(!fs.is_readonly());
429    }
430
431    #[test]
432    fn test_ramfs_default() {
433        let fs = RamFs::default();
434        assert_eq!(fs.name(), "ramfs");
435    }
436
437    #[test]
438    fn test_ramfs_root_is_directory() {
439        let fs = RamFs::new();
440        let root = fs.root();
441        assert_eq!(root.node_type(), NodeType::Directory);
442    }
443
444    #[test]
445    fn test_ramfs_sync() {
446        let fs = RamFs::new();
447        assert!(fs.sync().is_ok());
448    }
449
450    // --- File creation and I/O tests ---
451
452    #[test]
453    fn test_create_file() {
454        let fs = RamFs::new();
455        let root = fs.root();
456
457        let file = root.create("hello.txt", Permissions::default());
458        assert!(file.is_ok());
459        assert_eq!(file.unwrap().node_type(), NodeType::File);
460    }
461
462    #[test]
463    fn test_create_duplicate_file_fails() {
464        let fs = RamFs::new();
465        let root = fs.root();
466
467        root.create("dup.txt", Permissions::default()).unwrap();
468        let result = root.create("dup.txt", Permissions::default());
469        assert!(result.is_err());
470        assert_eq!(
471            result.err().expect("expected Err"),
472            KernelError::FsError(FsError::AlreadyExists)
473        );
474    }
475
476    #[test]
477    fn test_write_and_read_file() {
478        let fs = RamFs::new();
479        let root = fs.root();
480
481        let file = root.create("data.txt", Permissions::default()).unwrap();
482
483        // Write data
484        let written = file.write(0, b"Hello, World!");
485        assert!(written.is_ok());
486        assert_eq!(written.unwrap(), 13);
487
488        // Read data back
489        let mut buf = vec![0u8; 20];
490        let read = file.read(0, &mut buf);
491        assert!(read.is_ok());
492        assert_eq!(read.unwrap(), 13);
493        assert_eq!(&buf[..13], b"Hello, World!");
494    }
495
496    #[test]
497    fn test_write_at_offset() {
498        let fs = RamFs::new();
499        let root = fs.root();
500        let file = root.create("offset.txt", Permissions::default()).unwrap();
501
502        // Write at offset 0
503        file.write(0, b"AAAA").unwrap();
504        // Overwrite middle bytes
505        file.write(1, b"BB").unwrap();
506
507        let mut buf = vec![0u8; 4];
508        file.read(0, &mut buf).unwrap();
509        assert_eq!(&buf, b"ABBA");
510    }
511
512    #[test]
513    fn test_write_extends_file() {
514        let fs = RamFs::new();
515        let root = fs.root();
516        let file = root.create("extend.txt", Permissions::default()).unwrap();
517
518        // Write at offset beyond current size -- should zero-fill gap
519        file.write(5, b"end").unwrap();
520
521        let mut buf = vec![0u8; 8];
522        let n = file.read(0, &mut buf).unwrap();
523        assert_eq!(n, 8);
524        assert_eq!(&buf[..5], &[0, 0, 0, 0, 0]);
525        assert_eq!(&buf[5..8], b"end");
526    }
527
528    #[test]
529    fn test_read_at_offset_beyond_eof() {
530        let fs = RamFs::new();
531        let root = fs.root();
532        let file = root.create("eof.txt", Permissions::default()).unwrap();
533        file.write(0, b"short").unwrap();
534
535        let mut buf = vec![0u8; 10];
536        let n = file.read(100, &mut buf).unwrap();
537        assert_eq!(n, 0);
538    }
539
540    #[test]
541    fn test_read_partial() {
542        let fs = RamFs::new();
543        let root = fs.root();
544        let file = root.create("partial.txt", Permissions::default()).unwrap();
545        file.write(0, b"Hello, World!").unwrap();
546
547        // Read only 5 bytes
548        let mut buf = vec![0u8; 5];
549        let n = file.read(0, &mut buf).unwrap();
550        assert_eq!(n, 5);
551        assert_eq!(&buf, b"Hello");
552    }
553
554    #[test]
555    fn test_read_from_directory_fails() {
556        let fs = RamFs::new();
557        let root = fs.root();
558
559        let mut buf = vec![0u8; 10];
560        let result = root.read(0, &mut buf);
561        assert!(result.is_err());
562        assert_eq!(result.unwrap_err(), KernelError::FsError(FsError::NotAFile));
563    }
564
565    #[test]
566    fn test_write_to_directory_fails() {
567        let fs = RamFs::new();
568        let root = fs.root();
569
570        let result = root.write(0, b"data");
571        assert!(result.is_err());
572        assert_eq!(result.unwrap_err(), KernelError::FsError(FsError::NotAFile));
573    }
574
575    // --- File metadata tests ---
576
577    #[test]
578    fn test_file_metadata() {
579        let fs = RamFs::new();
580        let root = fs.root();
581        let file = root.create("meta.txt", Permissions::default()).unwrap();
582        file.write(0, b"content").unwrap();
583
584        let meta = file.metadata().unwrap();
585        assert_eq!(meta.node_type, NodeType::File);
586        assert_eq!(meta.size, 7);
587    }
588
589    #[test]
590    fn test_directory_metadata() {
591        let fs = RamFs::new();
592        let root = fs.root();
593        let meta = root.metadata().unwrap();
594        assert_eq!(meta.node_type, NodeType::Directory);
595    }
596
597    // --- Truncate tests ---
598
599    #[test]
600    fn test_truncate_file() {
601        let fs = RamFs::new();
602        let root = fs.root();
603        let file = root.create("trunc.txt", Permissions::default()).unwrap();
604        file.write(0, b"Hello, World!").unwrap();
605
606        // Truncate to 5 bytes
607        file.truncate(5).unwrap();
608
609        let meta = file.metadata().unwrap();
610        assert_eq!(meta.size, 5);
611
612        let mut buf = vec![0u8; 10];
613        let n = file.read(0, &mut buf).unwrap();
614        assert_eq!(n, 5);
615        assert_eq!(&buf[..5], b"Hello");
616    }
617
618    #[test]
619    fn test_truncate_to_zero() {
620        let fs = RamFs::new();
621        let root = fs.root();
622        let file = root.create("empty.txt", Permissions::default()).unwrap();
623        file.write(0, b"data").unwrap();
624
625        file.truncate(0).unwrap();
626        let meta = file.metadata().unwrap();
627        assert_eq!(meta.size, 0);
628    }
629
630    #[test]
631    fn test_truncate_directory_fails() {
632        let fs = RamFs::new();
633        let root = fs.root();
634        let result = root.truncate(0);
635        assert!(result.is_err());
636        assert_eq!(result.unwrap_err(), KernelError::FsError(FsError::NotAFile));
637    }
638
639    // --- Directory operations tests ---
640
641    #[test]
642    fn test_mkdir() {
643        let fs = RamFs::new();
644        let root = fs.root();
645
646        let dir = root.mkdir("subdir", Permissions::default());
647        assert!(dir.is_ok());
648        assert_eq!(dir.unwrap().node_type(), NodeType::Directory);
649    }
650
651    #[test]
652    fn test_mkdir_duplicate_fails() {
653        let fs = RamFs::new();
654        let root = fs.root();
655
656        root.mkdir("dup", Permissions::default()).unwrap();
657        let result = root.mkdir("dup", Permissions::default());
658        assert!(result.is_err());
659        assert_eq!(
660            result.err().expect("expected Err"),
661            KernelError::FsError(FsError::AlreadyExists)
662        );
663    }
664
665    #[test]
666    fn test_mkdir_on_file_fails() {
667        let fs = RamFs::new();
668        let root = fs.root();
669        let file = root.create("file", Permissions::default()).unwrap();
670
671        let result = file.mkdir("subdir", Permissions::default());
672        assert!(result.is_err());
673        assert_eq!(
674            result.err().expect("expected Err"),
675            KernelError::FsError(FsError::NotADirectory)
676        );
677    }
678
679    #[test]
680    fn test_lookup() {
681        let fs = RamFs::new();
682        let root = fs.root();
683
684        root.create("myfile", Permissions::default()).unwrap();
685
686        let found = root.lookup("myfile");
687        assert!(found.is_ok());
688        assert_eq!(found.unwrap().node_type(), NodeType::File);
689    }
690
691    #[test]
692    fn test_lookup_not_found() {
693        let fs = RamFs::new();
694        let root = fs.root();
695
696        let result = root.lookup("missing");
697        assert!(result.is_err());
698        assert_eq!(
699            result.err().expect("expected Err"),
700            KernelError::FsError(FsError::NotFound)
701        );
702    }
703
704    #[test]
705    fn test_lookup_on_file_fails() {
706        let fs = RamFs::new();
707        let root = fs.root();
708        let file = root.create("f", Permissions::default()).unwrap();
709
710        let result = file.lookup("anything");
711        assert!(result.is_err());
712        assert_eq!(
713            result.err().expect("expected Err"),
714            KernelError::FsError(FsError::NotADirectory)
715        );
716    }
717
718    #[test]
719    fn test_readdir() {
720        let fs = RamFs::new();
721        let root = fs.root();
722
723        root.create("file1", Permissions::default()).unwrap();
724        root.mkdir("dir1", Permissions::default()).unwrap();
725
726        let entries = root.readdir().unwrap();
727        // Should have ".", "..", "file1", "dir1"
728        assert_eq!(entries.len(), 4);
729
730        let names: Vec<&str> = entries.iter().map(|e| e.name.as_str()).collect();
731        assert!(names.contains(&"."));
732        assert!(names.contains(&".."));
733        assert!(names.contains(&"file1"));
734        assert!(names.contains(&"dir1"));
735    }
736
737    #[test]
738    fn test_readdir_on_file_fails() {
739        let fs = RamFs::new();
740        let root = fs.root();
741        let file = root.create("f", Permissions::default()).unwrap();
742
743        let result = file.readdir();
744        assert!(result.is_err());
745        assert_eq!(
746            result.err().expect("expected Err"),
747            KernelError::FsError(FsError::NotADirectory)
748        );
749    }
750
751    // --- Unlink tests ---
752
753    #[test]
754    fn test_unlink_file() {
755        let fs = RamFs::new();
756        let root = fs.root();
757
758        root.create("victim", Permissions::default()).unwrap();
759        let result = root.unlink("victim");
760        assert!(result.is_ok());
761
762        // Should no longer be found
763        assert!(root.lookup("victim").is_err());
764    }
765
766    #[test]
767    fn test_unlink_empty_directory() {
768        let fs = RamFs::new();
769        let root = fs.root();
770
771        root.mkdir("emptydir", Permissions::default()).unwrap();
772        let result = root.unlink("emptydir");
773        assert!(result.is_ok());
774    }
775
776    #[test]
777    fn test_unlink_nonempty_directory_fails() {
778        let fs = RamFs::new();
779        let root = fs.root();
780
781        let dir = root.mkdir("notempty", Permissions::default()).unwrap();
782        dir.create("child", Permissions::default()).unwrap();
783
784        let result = root.unlink("notempty");
785        assert!(result.is_err());
786        assert_eq!(
787            result.err().expect("expected Err"),
788            KernelError::FsError(FsError::DirectoryNotEmpty)
789        );
790    }
791
792    #[test]
793    fn test_unlink_not_found() {
794        let fs = RamFs::new();
795        let root = fs.root();
796
797        let result = root.unlink("phantom");
798        assert!(result.is_err());
799        assert_eq!(result.unwrap_err(), KernelError::FsError(FsError::NotFound));
800    }
801
802    #[test]
803    fn test_unlink_on_file_fails() {
804        let fs = RamFs::new();
805        let root = fs.root();
806        let file = root.create("f", Permissions::default()).unwrap();
807
808        let result = file.unlink("anything");
809        assert!(result.is_err());
810        assert_eq!(
811            result.err().expect("expected Err"),
812            KernelError::FsError(FsError::NotADirectory)
813        );
814    }
815
816    #[test]
817    fn test_create_on_file_fails() {
818        let fs = RamFs::new();
819        let root = fs.root();
820        let file = root.create("f", Permissions::default()).unwrap();
821
822        let result = file.create("sub", Permissions::default());
823        assert!(result.is_err());
824        assert_eq!(
825            result.err().expect("expected Err"),
826            KernelError::FsError(FsError::NotADirectory)
827        );
828    }
829}