1#![allow(clippy::should_implement_trait)]
6
7use alloc::{collections::BTreeMap, format, string::String, sync::Arc, vec, vec::Vec};
8
9use spin::RwLock;
10
11use crate::error::KernelError;
12
13#[cfg(target_arch = "aarch64")]
14pub mod bare_lock;
15pub mod blockdev;
16pub mod blockfs;
17pub mod devfs;
18pub mod eventfd;
19pub mod ext4;
20pub mod fat32;
21pub mod file;
22pub mod flock;
23pub mod inotify;
24pub mod pipe;
25pub mod procfs;
26pub mod pty;
27pub mod ramfs;
28pub mod signalfd;
29pub mod tar;
30pub mod timerfd;
31pub mod tmpfs;
32pub mod xattr;
33
34pub mod nfs;
36pub mod smb;
37
38pub use file::{File, FileDescriptor, FileTable, OpenFlags, SeekFrom};
39
40pub const PATH_MAX: usize = 4096;
42
43pub const NAME_MAX: usize = 255;
45
46pub const SYMLINK_MAX_DEPTH: usize = 40;
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum NodeType {
55 File,
56 Directory,
57 CharDevice,
58 BlockDevice,
59 Pipe,
60 Socket,
61 Symlink,
62}
63
64#[derive(Debug, Clone, Copy)]
66pub struct Permissions {
67 pub owner_read: bool,
68 pub owner_write: bool,
69 pub owner_exec: bool,
70 pub group_read: bool,
71 pub group_write: bool,
72 pub group_exec: bool,
73 pub other_read: bool,
74 pub other_write: bool,
75 pub other_exec: bool,
76}
77
78impl Permissions {
79 pub fn default() -> Self {
81 Self {
82 owner_read: true,
83 owner_write: true,
84 owner_exec: true,
85 group_read: true,
86 group_write: false,
87 group_exec: true,
88 other_read: true,
89 other_write: false,
90 other_exec: true,
91 }
92 }
93
94 pub fn read_only() -> Self {
96 Self {
97 owner_read: true,
98 owner_write: false,
99 owner_exec: false,
100 group_read: true,
101 group_write: false,
102 group_exec: false,
103 other_read: true,
104 other_write: false,
105 other_exec: false,
106 }
107 }
108
109 pub fn from_mode(mode: u32) -> Self {
111 Self {
112 owner_read: (mode & 0o400) != 0,
113 owner_write: (mode & 0o200) != 0,
114 owner_exec: (mode & 0o100) != 0,
115 group_read: (mode & 0o040) != 0,
116 group_write: (mode & 0o020) != 0,
117 group_exec: (mode & 0o010) != 0,
118 other_read: (mode & 0o004) != 0,
119 other_write: (mode & 0o002) != 0,
120 other_exec: (mode & 0o001) != 0,
121 }
122 }
123
124 pub fn can_read(&self, uid: u32, gid: u32, file_uid: u32, file_gid: u32) -> bool {
126 if uid == 0 {
127 return true; }
129 if uid == file_uid {
130 self.owner_read
131 } else if gid == file_gid {
132 self.group_read
133 } else {
134 self.other_read
135 }
136 }
137
138 pub fn can_write(&self, uid: u32, gid: u32, file_uid: u32, file_gid: u32) -> bool {
140 if uid == 0 {
141 return true;
142 }
143 if uid == file_uid {
144 self.owner_write
145 } else if gid == file_gid {
146 self.group_write
147 } else {
148 self.other_write
149 }
150 }
151
152 pub fn can_run(&self, uid: u32, gid: u32, file_uid: u32, file_gid: u32) -> bool {
154 if uid == 0 {
155 return true;
156 }
157 if uid == file_uid {
158 self.owner_exec
159 } else if gid == file_gid {
160 self.group_exec
161 } else {
162 self.other_exec
163 }
164 }
165}
166
167#[derive(Debug, Clone)]
169pub struct Metadata {
170 pub node_type: NodeType,
171 pub size: usize,
172 pub permissions: Permissions,
173 pub uid: u32,
174 pub gid: u32,
175 pub created: u64,
176 pub modified: u64,
177 pub accessed: u64,
178 pub inode: u64,
179}
180
181#[derive(Debug, Clone)]
183pub struct DirEntry {
184 pub name: String,
185 pub node_type: NodeType,
186 pub inode: u64,
187}
188
189pub trait VfsNode: Send + Sync {
191 fn node_type(&self) -> NodeType;
193
194 fn read(&self, offset: usize, buffer: &mut [u8]) -> Result<usize, KernelError>;
196
197 fn write(&self, offset: usize, data: &[u8]) -> Result<usize, KernelError>;
199
200 fn metadata(&self) -> Result<Metadata, KernelError>;
202
203 fn readdir(&self) -> Result<Vec<DirEntry>, KernelError>;
205
206 fn lookup(&self, name: &str) -> Result<Arc<dyn VfsNode>, KernelError>;
208
209 fn create(&self, name: &str, permissions: Permissions)
211 -> Result<Arc<dyn VfsNode>, KernelError>;
212
213 fn mkdir(&self, name: &str, permissions: Permissions) -> Result<Arc<dyn VfsNode>, KernelError>;
215
216 fn unlink(&self, name: &str) -> Result<(), KernelError>;
218
219 fn truncate(&self, size: usize) -> Result<(), KernelError>;
221
222 fn link(&self, _name: &str, _target: Arc<dyn VfsNode>) -> Result<(), KernelError> {
224 Err(KernelError::NotImplemented {
225 feature: "hard links",
226 })
227 }
228
229 fn symlink(&self, _name: &str, _target: &str) -> Result<Arc<dyn VfsNode>, KernelError> {
249 Err(KernelError::NotImplemented {
250 feature: "symbolic links",
251 })
252 }
253
254 fn readlink(&self) -> Result<String, KernelError> {
274 Err(KernelError::NotImplemented {
275 feature: "readlink",
276 })
277 }
278
279 fn chmod(&self, _permissions: Permissions) -> Result<(), KernelError> {
281 Err(KernelError::NotImplemented { feature: "chmod" })
282 }
283
284 fn poll_readiness(&self) -> u16 {
295 0x0001 | 0x0004 }
298
299 fn as_any(&self) -> Option<&dyn core::any::Any> {
306 None
307 }
308}
309
310pub trait Filesystem: Send + Sync {
312 fn root(&self) -> Arc<dyn VfsNode>;
314
315 fn name(&self) -> &str;
317
318 fn is_readonly(&self) -> bool;
320
321 fn sync(&self) -> Result<(), KernelError>;
323}
324
325pub struct MountPoint {
327 pub path: String,
328 pub filesystem: Arc<dyn Filesystem>,
329}
330
331pub struct Vfs {
333 root_fs: Option<Arc<dyn Filesystem>>,
335
336 mounts: BTreeMap<String, Arc<dyn Filesystem>>,
338
339 cwd: String,
344}
345
346impl Vfs {
347 pub fn new() -> Self {
349 Self {
350 root_fs: None,
351 mounts: BTreeMap::new(),
352 cwd: String::from("/"),
353 }
354 }
355}
356
357impl Default for Vfs {
358 fn default() -> Self {
359 Self::new()
360 }
361}
362
363impl Vfs {
364 pub fn mount_root(&mut self, fs: Arc<dyn Filesystem>) -> Result<(), KernelError> {
366 if self.root_fs.is_some() {
367 return Err(KernelError::FsError(crate::error::FsError::AlreadyMounted));
368 }
369 self.root_fs = Some(fs);
370 Ok(())
371 }
372
373 pub fn mount(&mut self, path: String, fs: Arc<dyn Filesystem>) -> Result<(), KernelError> {
375 if self.root_fs.is_none() {
376 return Err(KernelError::FsError(crate::error::FsError::NoRootFs));
377 }
378
379 if self.mounts.contains_key(&path) {
380 return Err(KernelError::FsError(crate::error::FsError::AlreadyMounted));
381 }
382
383 self.mounts.insert(path, fs);
384 Ok(())
385 }
386
387 pub fn mount_by_type(
389 &mut self,
390 path: &str,
391 fs_type: &str,
392 _flags: u32,
393 ) -> Result<(), KernelError> {
394 let fs: Arc<dyn Filesystem> = match fs_type {
395 "ramfs" => Arc::new(ramfs::RamFs::new()),
396 "devfs" => Arc::new(devfs::DevFs::new()),
397 "procfs" => Arc::new(procfs::ProcFs::new()),
398 "blockfs" => Arc::new(blockfs::BlockFs::new(10000, 1000)),
399 _ => return Err(KernelError::FsError(crate::error::FsError::UnknownFsType)),
400 };
401
402 if path == "/" {
403 self.mount_root(fs)
404 } else {
405 self.mount(path.into(), fs)
406 }
407 }
408
409 pub fn swap_root(&mut self, fs: Arc<dyn Filesystem>) {
414 self.root_fs = Some(fs);
415 }
416
417 pub fn unmount(&mut self, path: &str) -> Result<(), KernelError> {
419 self.mounts
420 .remove(path)
421 .ok_or(KernelError::FsError(crate::error::FsError::NotMounted))
422 .map(|_| ())
423 }
424
425 pub fn resolve_path(&self, path: &str) -> Result<Arc<dyn VfsNode>, KernelError> {
428 self.resolve_path_inner(path, &self.cwd, true, 0)
429 }
430
431 pub fn resolve_path_no_follow(&self, path: &str) -> Result<Arc<dyn VfsNode>, KernelError> {
435 self.resolve_path_inner(path, &self.cwd, false, 0)
436 }
437
438 pub fn resolve_from(&self, path: &str, cwd: &str) -> Result<Arc<dyn VfsNode>, KernelError> {
441 self.resolve_path_inner(path, cwd, true, 0)
442 }
443
444 pub fn resolve_from_no_follow(
447 &self,
448 path: &str,
449 cwd: &str,
450 ) -> Result<Arc<dyn VfsNode>, KernelError> {
451 self.resolve_path_inner(path, cwd, false, 0)
452 }
453
454 fn resolve_path_inner(
461 &self,
462 path: &str,
463 cwd: &str,
464 follow_last: bool,
465 symlink_depth: usize,
466 ) -> Result<Arc<dyn VfsNode>, KernelError> {
467 if symlink_depth > SYMLINK_MAX_DEPTH {
468 return Err(KernelError::FsError(crate::error::FsError::SymlinkLoop));
469 }
470
471 let root_fs = self
472 .root_fs
473 .as_ref()
474 .ok_or(KernelError::FsError(crate::error::FsError::NoRootFs))?;
475
476 let path: String = if path.starts_with('/') {
478 path.into()
479 } else if cwd.ends_with('/') {
480 format!("{}{}", cwd, path)
481 } else {
482 format!("{}/{}", cwd, path)
483 };
484
485 for (mount_path, fs) in self.mounts.iter().rev() {
487 if path.starts_with(mount_path) {
488 let relative_path = &path[mount_path.len()..];
489 return self.traverse_path(fs.root(), relative_path, follow_last, symlink_depth);
490 }
491 }
492
493 self.traverse_path(root_fs.root(), &path, follow_last, symlink_depth)
495 }
496
497 fn traverse_path(
504 &self,
505 mut node: Arc<dyn VfsNode>,
506 path: &str,
507 follow_last: bool,
508 mut symlink_depth: usize,
509 ) -> Result<Arc<dyn VfsNode>, KernelError> {
510 let mut path_stack: Vec<Arc<dyn VfsNode>> = Vec::new();
512 path_stack.push(node.clone());
513
514 let components: Vec<&str> = path
515 .split('/')
516 .filter(|s| !s.is_empty() && *s != ".")
517 .collect();
518
519 let last_idx = components.len().saturating_sub(1);
520
521 for (idx, component) in components.iter().enumerate() {
522 let is_last = idx == last_idx;
523
524 if *component == ".." {
525 if path_stack.len() > 1 {
527 path_stack.pop();
528 node = path_stack
529 .last()
530 .ok_or(KernelError::LegacyError {
531 message: "internal error: path stack unexpectedly empty",
532 })?
533 .clone();
534 }
535 } else {
537 node = node.lookup(component)?;
539
540 if node.node_type() == NodeType::Symlink {
542 if !is_last || follow_last {
544 symlink_depth += 1;
545 if symlink_depth > SYMLINK_MAX_DEPTH {
546 return Err(KernelError::FsError(crate::error::FsError::SymlinkLoop));
547 }
548
549 let target = node.readlink()?;
551
552 if target.starts_with('/') {
557 node = self.resolve_path_inner(
558 &target,
559 "/",
560 !is_last || follow_last,
565 symlink_depth,
566 )?;
567 } else {
568 node = self.resolve_path_inner(
575 &target,
576 "/",
577 !is_last || follow_last,
578 symlink_depth,
579 )?;
580 }
581 }
582 }
583
584 path_stack.push(node.clone());
585 }
586 }
587
588 Ok(node)
589 }
590
591 pub fn get_cwd(&self) -> &str {
593 &self.cwd
594 }
595
596 pub fn set_cwd(&mut self, path: String) -> Result<(), KernelError> {
598 let node = self.resolve_path(&path)?;
600 let metadata = node.metadata()?;
601
602 if metadata.node_type != NodeType::Directory {
603 return Err(KernelError::FsError(crate::error::FsError::NotADirectory));
604 }
605
606 self.cwd = path;
607 Ok(())
608 }
609
610 pub fn open(&self, path: &str, flags: OpenFlags) -> Result<Arc<dyn VfsNode>, KernelError> {
614 let access = if flags.write {
616 crate::security::AccessType::Write
617 } else {
618 crate::security::AccessType::Read
619 };
620
621 let pid = crate::process::current_process()
623 .map(|p| p.pid.0)
624 .unwrap_or(0);
625
626 crate::security::mac::check_file_access(path, access, pid)?;
627
628 self.resolve_path(path)
629 }
630
631 pub fn mkdir(&self, path: &str, permissions: Permissions) -> Result<(), KernelError> {
635 let path = path.trim_end_matches('/');
637 if path.is_empty() {
638 return Err(KernelError::FsError(crate::error::FsError::AlreadyExists));
639 }
640
641 let pid = crate::process::current_process()
643 .map(|p| p.pid.0)
644 .unwrap_or(0);
645 crate::security::mac::check_file_access(path, crate::security::AccessType::Write, pid)?;
646
647 let (parent_path, name) = if let Some(pos) = path.rfind('/') {
649 if pos == 0 {
650 ("/", &path[1..])
651 } else {
652 (&path[..pos], &path[pos + 1..])
653 }
654 } else {
655 return Err(KernelError::FsError(crate::error::FsError::InvalidPath));
656 };
657
658 let parent = self.resolve_path(parent_path)?;
660
661 parent.mkdir(name, permissions)?;
663 Ok(())
664 }
665
666 pub fn unlink(&self, path: &str) -> Result<(), KernelError> {
668 let (parent_path, name) = if let Some(pos) = path.rfind('/') {
670 if pos == 0 {
671 ("/", &path[1..])
672 } else {
673 (&path[..pos], &path[pos + 1..])
674 }
675 } else {
676 return Err(KernelError::FsError(crate::error::FsError::InvalidPath));
677 };
678
679 let parent = self.resolve_path(parent_path)?;
681
682 parent.unlink(name)
684 }
685
686 pub fn list_mounts(&self) -> Vec<(String, String, bool)> {
690 let mut result = Vec::new();
691
692 if let Some(ref root) = self.root_fs {
694 result.push((
695 String::from("/"),
696 String::from(root.name()),
697 root.is_readonly(),
698 ));
699 }
700
701 for (path, fs) in &self.mounts {
703 result.push((path.clone(), String::from(fs.name()), fs.is_readonly()));
704 }
705
706 result
707 }
708
709 pub fn sync(&self) -> Result<(), KernelError> {
711 if let Some(ref root) = self.root_fs {
713 root.sync()?;
714 }
715
716 for fs in self.mounts.values() {
718 fs.sync()?;
719 }
720
721 Ok(())
722 }
723}
724
725static VFS_LOCK: crate::sync::once_lock::OnceLock<RwLock<Vfs>> =
727 crate::sync::once_lock::OnceLock::new();
728
729pub fn get_vfs() -> &'static RwLock<Vfs> {
734 VFS_LOCK
735 .get()
736 .expect("VFS not initialized: init() was not called")
737}
738
739pub fn try_get_vfs() -> Option<&'static RwLock<Vfs>> {
741 VFS_LOCK.get()
742}
743
744pub fn init() {
746 #[allow(unused_imports)]
747 use crate::println;
748
749 println!("[VFS] Initializing Virtual Filesystem...");
750
751 println!("[VFS] Creating VFS structure...");
752 let vfs = Vfs::new();
753 let vfs_lock = RwLock::new(vfs);
754
755 match VFS_LOCK.set(vfs_lock) {
756 Ok(()) => println!("[VFS] VFS initialized successfully"),
757 Err(_) => {
758 println!("[VFS] WARNING: VFS already initialized! Skipping re-initialization.");
759 return;
760 }
761 }
762
763 #[cfg(feature = "alloc")]
765 {
766 println!("[VFS] Creating RAM filesystem...");
767
768 let ramfs = ramfs::RamFs::new();
770
771 {
773 let vfs = get_vfs();
774 let mut vfs_guard = vfs.write();
775 vfs_guard.mount_root(Arc::new(ramfs)).ok();
776 }
777
778 println!("[VFS] RAM filesystem mounted as root");
779
780 {
782 let vfs = get_vfs();
783 let vfs_guard = vfs.read();
784 if let Some(ref root_fs) = vfs_guard.root_fs {
785 let root = root_fs.root();
786 root.mkdir("bin", Permissions::default()).ok();
787 root.mkdir("boot", Permissions::default()).ok();
788 root.mkdir("dev", Permissions::default()).ok();
789 root.mkdir("etc", Permissions::default()).ok();
790 root.mkdir("home", Permissions::default()).ok();
791 root.mkdir("lib", Permissions::default()).ok();
792 root.mkdir("mnt", Permissions::default()).ok();
793 root.mkdir("opt", Permissions::default()).ok();
794 root.mkdir("proc", Permissions::default()).ok();
795 root.mkdir("root", Permissions::default()).ok();
796 root.mkdir("sbin", Permissions::default()).ok();
797 root.mkdir("sys", Permissions::default()).ok();
798 root.mkdir("tmp", Permissions::from_mode(0o777)).ok();
799 root.mkdir("usr", Permissions::default()).ok();
800 root.mkdir("var", Permissions::default()).ok();
801 }
802 }
803
804 println!("[VFS] Created standard directories");
805
806 {
808 let vfs = get_vfs();
809 let vfs_guard = vfs.read();
810 if let Some(ref root_fs) = vfs_guard.root_fs {
811 let root = root_fs.root();
812
813 if let Ok(usr) = root.lookup("usr") {
815 usr.mkdir("bin", Permissions::default()).ok();
816 usr.mkdir("sbin", Permissions::default()).ok();
817 usr.mkdir("lib", Permissions::default()).ok();
818 usr.mkdir("share", Permissions::default()).ok();
819 usr.mkdir("local", Permissions::default()).ok();
820 }
821
822 if let Ok(var) = root.lookup("var") {
824 var.mkdir("log", Permissions::default()).ok();
825 var.mkdir("tmp", Permissions::default()).ok();
826 var.mkdir("run", Permissions::default()).ok();
827 var.mkdir("cache", Permissions::default()).ok();
828 }
829
830 if let Ok(home) = root.lookup("home") {
832 home.mkdir("root", Permissions::default()).ok();
833 }
834 }
835 }
836
837 {
839 let vfs = get_vfs();
840 let vfs_guard = vfs.read();
841 if let Some(ref root_fs) = vfs_guard.root_fs {
842 let root = root_fs.root();
843 if let Ok(etc) = root.lookup("etc") {
844 if let Ok(f) = etc.create("hostname", Permissions::default()) {
846 f.write(0, b"veridian\n").ok();
847 }
848
849 if let Ok(f) = etc.create("os-release", Permissions::default()) {
851 f.write(
852 0,
853 b"NAME=\"VeridianOS\"\nVERSION=\"0.25.2\"\nID=veridian\nPRETTY_NAME=\"VeridianOS v0.25.2\"\n",
854 )
855 .ok();
856 }
857
858 if let Ok(f) = etc.create("passwd", Permissions::read_only()) {
860 f.write(0, b"root:x:0:0:root:/root:/bin/vsh\n").ok();
861 }
862
863 if let Ok(f) = etc.create("group", Permissions::read_only()) {
865 f.write(0, b"root:x:0:root\n").ok();
866 }
867
868 if let Ok(f) = etc.create("shells", Permissions::read_only()) {
870 f.write(0, b"/bin/vsh\n").ok();
871 }
872
873 if let Ok(f) = etc.create("motd", Permissions::read_only()) {
875 f.write(
876 0,
877 b"Welcome to VeridianOS - a capability-based microkernel OS\n",
878 )
879 .ok();
880 }
881
882 if let Ok(veridian_dir) = etc.mkdir("veridian", Permissions::default()) {
884 if let Ok(f) = veridian_dir.create("session.conf", Permissions::default()) {
885 f.write(
886 0,
887 b"# VeridianOS session configuration\n# session_type: plasma (KDE Plasma 6) or builtin (built-in DE)\nsession_type=plasma\n",
888 )
889 .ok();
890 }
891 }
892 }
893 }
894 }
895
896 println!("[VFS] Populated /etc and subdirectories");
897
898 println!("[VFS] Creating device filesystem...");
900 let devfs = devfs::DevFs::new();
901
902 {
903 let vfs = get_vfs();
904 let mut vfs_guard = vfs.write();
905 vfs_guard.mount("/dev".into(), Arc::new(devfs)).ok();
906 }
907
908 println!("[VFS] Device filesystem mounted at /dev");
909
910 println!("[VFS] Creating process filesystem...");
912 let procfs = procfs::ProcFs::new();
913
914 {
915 let vfs = get_vfs();
916 let mut vfs_guard = vfs.write();
917 vfs_guard.mount("/proc".into(), Arc::new(procfs)).ok();
918 }
919
920 println!("[VFS] Process filesystem mounted at /proc");
921
922 println!("[VFS] Virtual Filesystem initialization complete");
923 }
924
925 #[cfg(not(feature = "alloc"))]
926 {
927 println!("[VFS] Skipping VFS initialization (no alloc)");
928 }
929}
930
931pub fn read_file(path: &str) -> Result<Vec<u8>, KernelError> {
943 let vfs = get_vfs().read();
944
945 let node = vfs.resolve_path(path)?;
947
948 let metadata = node.metadata()?;
950
951 if metadata.node_type != NodeType::File {
953 return Err(KernelError::FsError(crate::error::FsError::NotAFile));
954 }
955
956 let size = metadata.size;
958 let mut buffer = vec![0u8; size];
959
960 let bytes_read = node.read(0, &mut buffer)?;
962
963 buffer.truncate(bytes_read);
965
966 Ok(buffer)
967}
968
969pub fn write_file(path: &str, data: &[u8]) -> Result<usize, KernelError> {
979 let vfs = get_vfs().read();
980
981 let node = match vfs.resolve_path(path) {
983 Ok(node) => node,
984 Err(_) => {
985 let (parent_path, filename) = if let Some(pos) = path.rfind('/') {
988 if pos == 0 {
989 ("/", &path[1..])
990 } else {
991 (&path[..pos], &path[pos + 1..])
992 }
993 } else {
994 return Err(KernelError::FsError(crate::error::FsError::InvalidPath));
995 };
996
997 let parent = vfs.resolve_path(parent_path)?;
999
1000 parent.create(filename, Permissions::default())?
1002 }
1003 };
1004
1005 node.truncate(0)?;
1007
1008 node.write(0, data)
1010}
1011
1012pub fn file_exists(path: &str) -> bool {
1014 let vfs = get_vfs().read();
1015 vfs.resolve_path(path).is_ok()
1016}
1017
1018pub fn file_size(path: &str) -> Result<usize, KernelError> {
1020 let vfs = get_vfs().read();
1021 let node = vfs.resolve_path(path)?;
1022 let metadata = node.metadata()?;
1023 Ok(metadata.size)
1024}
1025
1026pub fn copy_file(src_path: &str, dst_path: &str) -> Result<usize, KernelError> {
1028 let data = read_file(src_path)?;
1029 write_file(dst_path, &data)
1030}
1031
1032pub fn append_file(path: &str, data: &[u8]) -> Result<usize, KernelError> {
1034 let vfs = get_vfs().read();
1035 let node = vfs.resolve_path(path)?;
1036 let metadata = node.metadata()?;
1037 let current_size = metadata.size;
1038
1039 node.write(current_size, data)
1041}
1042
1043#[cfg(test)]
1044mod tests {
1045 use super::*;
1046
1047 fn make_vfs_with_root() -> Vfs {
1049 let mut vfs = Vfs::new();
1050 let ramfs = Arc::new(ramfs::RamFs::new());
1051 vfs.mount_root(ramfs).expect("mount_root should succeed");
1052 vfs
1053 }
1054
1055 #[test]
1058 fn test_permissions_default() {
1059 let perm = Permissions::default();
1060 assert!(perm.owner_read);
1061 assert!(perm.owner_write);
1062 assert!(perm.owner_exec);
1063 assert!(perm.group_read);
1064 assert!(!perm.group_write);
1065 assert!(perm.group_exec);
1066 assert!(perm.other_read);
1067 assert!(!perm.other_write);
1068 assert!(perm.other_exec);
1069 }
1070
1071 #[test]
1072 fn test_permissions_read_only() {
1073 let perm = Permissions::read_only();
1074 assert!(perm.owner_read);
1075 assert!(!perm.owner_write);
1076 assert!(!perm.owner_exec);
1077 assert!(perm.group_read);
1078 assert!(!perm.group_write);
1079 }
1080
1081 #[test]
1082 fn test_permissions_from_mode_755() {
1083 let perm = Permissions::from_mode(0o755);
1084 assert!(perm.owner_read);
1085 assert!(perm.owner_write);
1086 assert!(perm.owner_exec);
1087 assert!(perm.group_read);
1088 assert!(!perm.group_write);
1089 assert!(perm.group_exec);
1090 assert!(perm.other_read);
1091 assert!(!perm.other_write);
1092 assert!(perm.other_exec);
1093 }
1094
1095 #[test]
1096 fn test_permissions_from_mode_644() {
1097 let perm = Permissions::from_mode(0o644);
1098 assert!(perm.owner_read);
1099 assert!(perm.owner_write);
1100 assert!(!perm.owner_exec);
1101 assert!(perm.group_read);
1102 assert!(!perm.group_write);
1103 assert!(!perm.group_exec);
1104 assert!(perm.other_read);
1105 assert!(!perm.other_write);
1106 assert!(!perm.other_exec);
1107 }
1108
1109 #[test]
1110 fn test_permissions_from_mode_000() {
1111 let perm = Permissions::from_mode(0o000);
1112 assert!(!perm.owner_read);
1113 assert!(!perm.owner_write);
1114 assert!(!perm.owner_exec);
1115 assert!(!perm.group_read);
1116 assert!(!perm.other_read);
1117 }
1118
1119 #[test]
1122 fn test_vfs_new() {
1123 let vfs = Vfs::new();
1124 assert_eq!(vfs.get_cwd(), "/");
1125 }
1126
1127 #[test]
1128 fn test_vfs_default() {
1129 let vfs = Vfs::default();
1130 assert_eq!(vfs.get_cwd(), "/");
1131 }
1132
1133 #[test]
1136 fn test_mount_root() {
1137 let mut vfs = Vfs::new();
1138 let ramfs = Arc::new(ramfs::RamFs::new());
1139 let result = vfs.mount_root(ramfs);
1140 assert!(result.is_ok());
1141 }
1142
1143 #[test]
1144 fn test_mount_root_twice_fails() {
1145 let mut vfs = Vfs::new();
1146 let ramfs1 = Arc::new(ramfs::RamFs::new());
1147 let ramfs2 = Arc::new(ramfs::RamFs::new());
1148
1149 vfs.mount_root(ramfs1).unwrap();
1150 let result = vfs.mount_root(ramfs2);
1151 assert!(result.is_err());
1152 assert_eq!(
1153 result.unwrap_err(),
1154 KernelError::FsError(crate::error::FsError::AlreadyMounted)
1155 );
1156 }
1157
1158 #[test]
1159 fn test_mount_without_root_fails() {
1160 let mut vfs = Vfs::new();
1161 let ramfs = Arc::new(ramfs::RamFs::new());
1162 let result = vfs.mount("/dev".into(), ramfs);
1163 assert!(result.is_err());
1164 assert_eq!(
1165 result.unwrap_err(),
1166 KernelError::FsError(crate::error::FsError::NoRootFs)
1167 );
1168 }
1169
1170 #[test]
1171 fn test_mount_at_path() {
1172 let mut vfs = make_vfs_with_root();
1173 let devfs = Arc::new(devfs::DevFs::new());
1174 let result = vfs.mount("/dev".into(), devfs);
1175 assert!(result.is_ok());
1176 }
1177
1178 #[test]
1179 fn test_mount_duplicate_path_fails() {
1180 let mut vfs = make_vfs_with_root();
1181 let fs1 = Arc::new(ramfs::RamFs::new());
1182 let fs2 = Arc::new(ramfs::RamFs::new());
1183
1184 vfs.mount("/mnt".into(), fs1).unwrap();
1185 let result = vfs.mount("/mnt".into(), fs2);
1186 assert!(result.is_err());
1187 assert_eq!(
1188 result.unwrap_err(),
1189 KernelError::FsError(crate::error::FsError::AlreadyMounted)
1190 );
1191 }
1192
1193 #[test]
1196 fn test_unmount() {
1197 let mut vfs = make_vfs_with_root();
1198 let fs = Arc::new(ramfs::RamFs::new());
1199 vfs.mount("/mnt".into(), fs).unwrap();
1200
1201 let result = vfs.unmount("/mnt");
1202 assert!(result.is_ok());
1203 }
1204
1205 #[test]
1206 fn test_unmount_nonexistent_fails() {
1207 let mut vfs = make_vfs_with_root();
1208 let result = vfs.unmount("/nonexistent");
1209 assert!(result.is_err());
1210 assert_eq!(
1211 result.unwrap_err(),
1212 KernelError::FsError(crate::error::FsError::NotMounted)
1213 );
1214 }
1215
1216 #[test]
1219 fn test_mount_by_type_ramfs() {
1220 let mut vfs = make_vfs_with_root();
1221 let result = vfs.mount_by_type("/tmp", "ramfs", 0);
1222 assert!(result.is_ok());
1223 }
1224
1225 #[test]
1226 fn test_mount_by_type_devfs() {
1227 let mut vfs = make_vfs_with_root();
1228 let result = vfs.mount_by_type("/dev", "devfs", 0);
1229 assert!(result.is_ok());
1230 }
1231
1232 #[test]
1233 fn test_mount_by_type_procfs() {
1234 let mut vfs = make_vfs_with_root();
1235 let result = vfs.mount_by_type("/proc", "procfs", 0);
1236 assert!(result.is_ok());
1237 }
1238
1239 #[test]
1240 fn test_mount_by_type_unknown_fails() {
1241 let mut vfs = make_vfs_with_root();
1242 let result = vfs.mount_by_type("/foo", "unknownfs", 0);
1243 assert!(result.is_err());
1244 assert_eq!(
1245 result.unwrap_err(),
1246 KernelError::FsError(crate::error::FsError::UnknownFsType)
1247 );
1248 }
1249
1250 #[test]
1251 fn test_mount_by_type_root() {
1252 let mut vfs = Vfs::new();
1253 let result = vfs.mount_by_type("/", "ramfs", 0);
1254 assert!(result.is_ok());
1255 }
1256
1257 #[test]
1260 fn test_resolve_root_path() {
1261 let vfs = make_vfs_with_root();
1262 let result = vfs.resolve_path("/");
1263 assert!(result.is_ok());
1264 let node = result.unwrap();
1265 assert_eq!(node.node_type(), NodeType::Directory);
1266 }
1267
1268 #[test]
1269 fn test_resolve_no_root_fails() {
1270 let vfs = Vfs::new();
1271 let result = vfs.resolve_path("/anything");
1272 assert_eq!(
1273 result.err().expect("expected error"),
1274 KernelError::FsError(crate::error::FsError::NoRootFs)
1275 );
1276 }
1277
1278 #[test]
1279 fn test_resolve_nonexistent_path() {
1280 let vfs = make_vfs_with_root();
1281 let result = vfs.resolve_path("/nonexistent");
1282 assert!(result.is_err());
1283 }
1284
1285 #[test]
1286 fn test_resolve_created_directory() {
1287 let vfs = make_vfs_with_root();
1288
1289 let root = vfs.root_fs.as_ref().unwrap().root();
1291 root.mkdir("testdir", Permissions::default()).unwrap();
1292
1293 let result = vfs.resolve_path("/testdir");
1294 assert!(result.is_ok());
1295 assert_eq!(result.unwrap().node_type(), NodeType::Directory);
1296 }
1297
1298 #[test]
1299 fn test_resolve_nested_path() {
1300 let vfs = make_vfs_with_root();
1301
1302 let root = vfs.root_fs.as_ref().unwrap().root();
1303 let sub = root.mkdir("a", Permissions::default()).unwrap();
1304 sub.mkdir("b", Permissions::default()).unwrap();
1305
1306 let result = vfs.resolve_path("/a/b");
1307 assert!(result.is_ok());
1308 assert_eq!(result.unwrap().node_type(), NodeType::Directory);
1309 }
1310
1311 #[test]
1312 fn test_resolve_path_with_dot() {
1313 let vfs = make_vfs_with_root();
1314 let root = vfs.root_fs.as_ref().unwrap().root();
1315 root.mkdir("mydir", Permissions::default()).unwrap();
1316
1317 let result = vfs.resolve_path("/./mydir/.");
1319 assert!(result.is_ok());
1320 }
1321
1322 #[test]
1323 fn test_resolve_path_with_dotdot() {
1324 let vfs = make_vfs_with_root();
1325 let root = vfs.root_fs.as_ref().unwrap().root();
1326 let sub = root.mkdir("parent", Permissions::default()).unwrap();
1327 sub.mkdir("child", Permissions::default()).unwrap();
1328
1329 let result = vfs.resolve_path("/parent/child/..");
1331 assert!(result.is_ok());
1332 assert_eq!(result.unwrap().node_type(), NodeType::Directory);
1333 }
1334
1335 #[test]
1336 fn test_resolve_dotdot_at_root() {
1337 let vfs = make_vfs_with_root();
1338
1339 let result = vfs.resolve_path("/../..");
1341 assert!(result.is_ok());
1342 assert_eq!(result.unwrap().node_type(), NodeType::Directory);
1343 }
1344
1345 #[test]
1348 fn test_mkdir_via_vfs() {
1349 let vfs = make_vfs_with_root();
1350 let result = vfs.mkdir("/newdir", Permissions::default());
1351 assert!(result.is_ok());
1352
1353 let node = vfs.resolve_path("/newdir").unwrap();
1355 assert_eq!(node.node_type(), NodeType::Directory);
1356 }
1357
1358 #[test]
1359 fn test_mkdir_invalid_path() {
1360 let vfs = make_vfs_with_root();
1361 let result = vfs.mkdir("no_slash", Permissions::default());
1362 assert!(result.is_err());
1363 }
1364
1365 #[test]
1366 fn test_unlink_file() {
1367 let vfs = make_vfs_with_root();
1368 let root = vfs.root_fs.as_ref().unwrap().root();
1369 root.create("testfile", Permissions::default()).unwrap();
1370
1371 let result = vfs.unlink("/testfile");
1372 assert!(result.is_ok());
1373
1374 assert!(vfs.resolve_path("/testfile").is_err());
1376 }
1377
1378 #[test]
1379 fn test_unlink_nonexistent() {
1380 let vfs = make_vfs_with_root();
1381 let result = vfs.unlink("/ghost");
1382 assert!(result.is_err());
1383 }
1384
1385 #[test]
1388 fn test_set_cwd() {
1389 let mut vfs = make_vfs_with_root();
1390 let root = vfs.root_fs.as_ref().unwrap().root();
1391 root.mkdir("home", Permissions::default()).unwrap();
1392
1393 let result = vfs.set_cwd(String::from("/home"));
1394 assert!(result.is_ok());
1395 assert_eq!(vfs.get_cwd(), "/home");
1396 }
1397
1398 #[test]
1399 fn test_set_cwd_not_directory_fails() {
1400 let mut vfs = make_vfs_with_root();
1401 let root = vfs.root_fs.as_ref().unwrap().root();
1402 root.create("afile", Permissions::default()).unwrap();
1403
1404 let result = vfs.set_cwd(String::from("/afile"));
1405 assert!(result.is_err());
1406 assert_eq!(
1407 result.unwrap_err(),
1408 KernelError::FsError(crate::error::FsError::NotADirectory)
1409 );
1410 }
1411
1412 #[test]
1415 fn test_sync_with_root() {
1416 let vfs = make_vfs_with_root();
1417 let result = vfs.sync();
1418 assert!(result.is_ok());
1419 }
1420
1421 #[test]
1422 fn test_sync_without_root() {
1423 let vfs = Vfs::new();
1424 let result = vfs.sync();
1425 assert!(result.is_ok()); }
1427
1428 #[test]
1431 fn test_node_type_equality() {
1432 assert_eq!(NodeType::File, NodeType::File);
1433 assert_eq!(NodeType::Directory, NodeType::Directory);
1434 assert_ne!(NodeType::File, NodeType::Directory);
1435 assert_ne!(NodeType::CharDevice, NodeType::BlockDevice);
1436 }
1437}