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

veridian_kernel/fs/
mod.rs

1//! Virtual Filesystem (VFS) Layer
2//!
3//! Provides a unified interface for different filesystem implementations.
4
5#![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
34// Phase 8 Wave 3: Enterprise Storage
35pub mod nfs;
36pub mod smb;
37
38pub use file::{File, FileDescriptor, FileTable, OpenFlags, SeekFrom};
39
40/// Maximum path length
41pub const PATH_MAX: usize = 4096;
42
43/// Maximum filename length
44pub const NAME_MAX: usize = 255;
45
46/// Maximum number of symbolic link traversals before returning ELOOP.
47///
48/// POSIX recommends at least `SYMLOOP_MAX` (typically 8-40). We use 40
49/// to be generous while still detecting infinite cycles.
50pub const SYMLINK_MAX_DEPTH: usize = 40;
51
52/// Filesystem node types
53#[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/// File permissions (Unix-style)
65#[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    /// Create default permissions (rwxr-xr-x)
80    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    /// Create read-only permissions
95    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    /// Create permissions from Unix mode bits
110    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    /// Check if the given uid/gid has read access.
125    pub fn can_read(&self, uid: u32, gid: u32, file_uid: u32, file_gid: u32) -> bool {
126        if uid == 0 {
127            return true; // root bypasses permission checks
128        }
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    /// Check if the given uid/gid has write access.
139    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    /// Check if the given uid/gid has run access.
153    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/// File metadata
168#[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/// Directory entry
182#[derive(Debug, Clone)]
183pub struct DirEntry {
184    pub name: String,
185    pub node_type: NodeType,
186    pub inode: u64,
187}
188
189/// VFS node operations trait
190pub trait VfsNode: Send + Sync {
191    /// Node type query (also serves as vtable slot padding for AArch64)
192    fn node_type(&self) -> NodeType;
193
194    /// Read data from the node
195    fn read(&self, offset: usize, buffer: &mut [u8]) -> Result<usize, KernelError>;
196
197    /// Write data to the node
198    fn write(&self, offset: usize, data: &[u8]) -> Result<usize, KernelError>;
199
200    /// Get metadata for the node
201    fn metadata(&self) -> Result<Metadata, KernelError>;
202
203    /// List directory entries (if this is a directory)
204    fn readdir(&self) -> Result<Vec<DirEntry>, KernelError>;
205
206    /// Look up a child node by name (if this is a directory)
207    fn lookup(&self, name: &str) -> Result<Arc<dyn VfsNode>, KernelError>;
208
209    /// Create a new file in this directory
210    fn create(&self, name: &str, permissions: Permissions)
211        -> Result<Arc<dyn VfsNode>, KernelError>;
212
213    /// Create a new directory in this directory
214    fn mkdir(&self, name: &str, permissions: Permissions) -> Result<Arc<dyn VfsNode>, KernelError>;
215
216    /// Remove a file or empty directory
217    fn unlink(&self, name: &str) -> Result<(), KernelError>;
218
219    /// Truncate the file to the specified size
220    fn truncate(&self, size: usize) -> Result<(), KernelError>;
221
222    /// Create a hard link to this node
223    fn link(&self, _name: &str, _target: Arc<dyn VfsNode>) -> Result<(), KernelError> {
224        Err(KernelError::NotImplemented {
225            feature: "hard links",
226        })
227    }
228
229    /// Create a symbolic link in this directory.
230    ///
231    /// Creates a new symlink entry named `name` in this directory node
232    /// that points to `target`. The target path is stored as the symlink's
233    /// data content and is not validated (it may be relative or absolute,
234    /// and the target need not exist).
235    ///
236    /// # Default Implementation
237    ///
238    /// Returns `NotImplemented` for filesystems that do not support
239    /// symbolic links (e.g., DevFS, ProcFS). Filesystems that support
240    /// symlinks (e.g., RamFS, BlockFS) override this method.
241    ///
242    /// # Arguments
243    /// - `name`: The name of the symlink entry to create in this directory.
244    /// - `target`: The target path that the symlink points to.
245    ///
246    /// # Returns
247    /// An `Arc<dyn VfsNode>` representing the newly created symlink node.
248    fn symlink(&self, _name: &str, _target: &str) -> Result<Arc<dyn VfsNode>, KernelError> {
249        Err(KernelError::NotImplemented {
250            feature: "symbolic links",
251        })
252    }
253
254    /// Read the target of a symbolic link.
255    ///
256    /// If this node is a symbolic link, returns the target path as a
257    /// `String`. The target is the raw path stored when the symlink was
258    /// created and is not resolved or canonicalized.
259    ///
260    /// # Default Implementation
261    ///
262    /// Returns `NotImplemented` for filesystem nodes that are not symbolic
263    /// links or for filesystems that do not support symlinks. Callers
264    /// should check `node_type() == NodeType::Symlink` before calling, or
265    /// handle the error.
266    ///
267    /// # Returns
268    /// - `Ok(String)`: The symlink target path.
269    /// - `Err(NotImplemented)`: This node is not a symlink or the filesystem
270    ///   does not support readlink.
271    /// - `Err(FsError(NotASymlink))`: The node exists but is not a symlink
272    ///   (used by BlockFS for type-checked readlink).
273    fn readlink(&self) -> Result<String, KernelError> {
274        Err(KernelError::NotImplemented {
275            feature: "readlink",
276        })
277    }
278
279    /// Change permissions on this node
280    fn chmod(&self, _permissions: Permissions) -> Result<(), KernelError> {
281        Err(KernelError::NotImplemented { feature: "chmod" })
282    }
283
284    /// Poll readiness for I/O multiplexing (poll/epoll).
285    ///
286    /// Returns a bitmask of ready events using POLL* constants:
287    /// - bit 0 (POLLIN=1): readable without blocking
288    /// - bit 2 (POLLOUT=4): writable without blocking
289    /// - bit 3 (POLLERR=8): error condition
290    /// - bit 4 (POLLHUP=16): hangup (peer closed)
291    ///
292    /// Default: regular files are always readable and writable.
293    /// Pipe nodes override this to check actual buffer state.
294    fn poll_readiness(&self) -> u16 {
295        // Regular files/dirs: always ready for read+write
296        0x0001 | 0x0004 // POLLIN | POLLOUT
297    }
298
299    /// Downcast to `&dyn core::any::Any` for type-specific operations.
300    ///
301    /// Used by syscall handlers that need to extract implementation-specific
302    /// state from a VfsNode (e.g., timerfd_settime needs the internal timer
303    /// ID from a TimerFdNode). Default returns `None`; only nodes that need
304    /// downcasting override this.
305    fn as_any(&self) -> Option<&dyn core::any::Any> {
306        None
307    }
308}
309
310/// Filesystem trait
311pub trait Filesystem: Send + Sync {
312    /// Get the root node of the filesystem
313    fn root(&self) -> Arc<dyn VfsNode>;
314
315    /// Get filesystem name
316    fn name(&self) -> &str;
317
318    /// Check if filesystem is read-only
319    fn is_readonly(&self) -> bool;
320
321    /// Sync filesystem to disk
322    fn sync(&self) -> Result<(), KernelError>;
323}
324
325/// Mount point information
326pub struct MountPoint {
327    pub path: String,
328    pub filesystem: Arc<dyn Filesystem>,
329}
330
331/// Virtual Filesystem Manager
332pub struct Vfs {
333    /// Root filesystem
334    root_fs: Option<Arc<dyn Filesystem>>,
335
336    /// Mount points
337    mounts: BTreeMap<String, Arc<dyn Filesystem>>,
338
339    /// Legacy global working directory (fallback only).
340    /// Per-process CWD is tracked in `process::cwd::ProcessCwd` and
341    /// `process::thread::ThreadFs`.  This field is retained for
342    /// kernel-context operations where no process is running.
343    cwd: String,
344}
345
346impl Vfs {
347    /// Create a new VFS instance
348    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    /// Mount the root filesystem
365    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    /// Mount a filesystem at the specified path
374    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    /// Mount a filesystem by type at the specified path
388    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    /// Replace the root filesystem (used for persistent BlockFS mount at boot).
410    ///
411    /// The previous root filesystem (if any) is dropped. Mount points under
412    /// `/dev` and `/proc` should be re-mounted after calling this.
413    pub fn swap_root(&mut self, fs: Arc<dyn Filesystem>) {
414        self.root_fs = Some(fs);
415    }
416
417    /// Unmount a filesystem at the specified path
418    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    /// Resolve a path to a VFS node, following symlinks (including the
426    /// final component).
427    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    /// Resolve a path to a VFS node without following the final symlink
432    /// component. Intermediate symlinks are still followed. Used by
433    /// `lstat()` and `readlink()`.
434    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    /// Resolve a path to a VFS node using an explicit cwd (per-thread FS
439    /// state).
440    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    /// Resolve a path to a VFS node using an explicit cwd, without
445    /// following the final symlink component.
446    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    /// Inner path resolution with configurable symlink behavior.
455    ///
456    /// - `follow_last`: if `true`, a symlink at the final component is
457    ///   resolved. If `false`, the symlink node itself is returned.
458    /// - `symlink_depth`: current nesting depth for loop detection. Returns
459    ///   `FsError::SymlinkLoop` when it exceeds `SYMLINK_MAX_DEPTH`.
460    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        // Normalize path
477        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        // Check if path is under a mount point
486        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        // Use root filesystem
494        self.traverse_path(root_fs.root(), &path, follow_last, symlink_depth)
495    }
496
497    /// Traverse a path from a starting node, with symlink resolution and
498    /// loop detection.
499    ///
500    /// When a path component resolves to a symlink node, its target is
501    /// read via `readlink()` and recursively resolved. For the **final**
502    /// component, symlink resolution is controlled by `follow_last`.
503    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        // Keep track of path components for parent traversal
511        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                // Go back to parent directory
526                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                // If at root, stay at root
536            } else {
537                // Move forward to child
538                node = node.lookup(component)?;
539
540                // Check if the resolved node is a symlink
541                if node.node_type() == NodeType::Symlink {
542                    // For the final component, only follow if requested
543                    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                        // Read the symlink target
550                        let target = node.readlink()?;
551
552                        // Resolve the target path recursively.
553                        // If the target is absolute, resolve from root.
554                        // If relative, resolve from the current directory
555                        // in the traversal (the parent of the symlink).
556                        if target.starts_with('/') {
557                            node = self.resolve_path_inner(
558                                &target,
559                                "/",
560                                // Intermediate symlinks (not the final
561                                // component of the *original* path) are
562                                // always followed. For the final component,
563                                // honour follow_last.
564                                !is_last || follow_last,
565                                symlink_depth,
566                            )?;
567                        } else {
568                            // Build the directory path of the current
569                            // traversal position (the parent of the
570                            // symlink) by collecting the path_stack.
571                            // The last entry on path_stack is the parent
572                            // directory (we haven't pushed the symlink
573                            // node yet).
574                            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    /// Get current working directory
592    pub fn get_cwd(&self) -> &str {
593        &self.cwd
594    }
595
596    /// Set current working directory
597    pub fn set_cwd(&mut self, path: String) -> Result<(), KernelError> {
598        // Verify the path exists and is a directory
599        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    /// Open a file
611    ///
612    /// Checks MAC policy before allowing access.
613    pub fn open(&self, path: &str, flags: OpenFlags) -> Result<Arc<dyn VfsNode>, KernelError> {
614        // Determine access type from flags
615        let access = if flags.write {
616            crate::security::AccessType::Write
617        } else {
618            crate::security::AccessType::Read
619        };
620
621        // Get current process PID for MAC check (0 = kernel context)
622        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    /// Create a directory
632    ///
633    /// Checks MAC policy (Write access to file domain) before creating.
634    pub fn mkdir(&self, path: &str, permissions: Permissions) -> Result<(), KernelError> {
635        // Strip trailing slashes (e.g., "/tmp/foo/" -> "/tmp/foo")
636        let path = path.trim_end_matches('/');
637        if path.is_empty() {
638            return Err(KernelError::FsError(crate::error::FsError::AlreadyExists));
639        }
640
641        // MAC check: creating a directory requires Write access
642        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        // Split path into parent and name
648        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        // Get parent directory
659        let parent = self.resolve_path(parent_path)?;
660
661        // Create directory in parent
662        parent.mkdir(name, permissions)?;
663        Ok(())
664    }
665
666    /// Remove a file or directory
667    pub fn unlink(&self, path: &str) -> Result<(), KernelError> {
668        // Split path into parent and name
669        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        // Get parent directory
680        let parent = self.resolve_path(parent_path)?;
681
682        // Remove from parent
683        parent.unlink(name)
684    }
685
686    /// List all mount points and their filesystem types.
687    ///
688    /// Returns a vector of `(path, fs_name, readonly)` tuples.
689    pub fn list_mounts(&self) -> Vec<(String, String, bool)> {
690        let mut result = Vec::new();
691
692        // Root filesystem
693        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        // Mounted filesystems
702        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    /// Sync all filesystems
710    pub fn sync(&self) -> Result<(), KernelError> {
711        // Sync root filesystem
712        if let Some(ref root) = self.root_fs {
713            root.sync()?;
714        }
715
716        // Sync all mounted filesystems
717        for fs in self.mounts.values() {
718            fs.sync()?;
719        }
720
721        Ok(())
722    }
723}
724
725/// Global VFS instance using OnceLock for safe initialization.
726static VFS_LOCK: crate::sync::once_lock::OnceLock<RwLock<Vfs>> =
727    crate::sync::once_lock::OnceLock::new();
728
729/// Get the VFS instance (unified for all architectures).
730///
731/// Panics if the VFS has not been initialized via [`init`].
732/// Prefer [`try_get_vfs`] in contexts where a panic is unacceptable.
733pub fn get_vfs() -> &'static RwLock<Vfs> {
734    VFS_LOCK
735        .get()
736        .expect("VFS not initialized: init() was not called")
737}
738
739/// Try to get the VFS instance without panicking
740pub fn try_get_vfs() -> Option<&'static RwLock<Vfs>> {
741    VFS_LOCK.get()
742}
743
744/// Initialize the VFS with a RAM filesystem as root
745pub 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    // Create and mount filesystems
764    #[cfg(feature = "alloc")]
765    {
766        println!("[VFS] Creating RAM filesystem...");
767
768        // Create a RAM filesystem as the root
769        let ramfs = ramfs::RamFs::new();
770
771        // Mount as root
772        {
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        // Create standard directories in root
781        {
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        // Create standard subdirectories
807        {
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                // /usr subdirectories
814                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                // /var subdirectories
823                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                // /home/root (root user home directory)
831                if let Ok(home) = root.lookup("home") {
832                    home.mkdir("root", Permissions::default()).ok();
833                }
834            }
835        }
836
837        // Populate /etc with basic configuration files
838        {
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                    // /etc/hostname
845                    if let Ok(f) = etc.create("hostname", Permissions::default()) {
846                        f.write(0, b"veridian\n").ok();
847                    }
848
849                    // /etc/os-release
850                    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                    // /etc/passwd (minimal)
859                    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                    // /etc/group (minimal)
864                    if let Ok(f) = etc.create("group", Permissions::read_only()) {
865                        f.write(0, b"root:x:0:root\n").ok();
866                    }
867
868                    // /etc/shells
869                    if let Ok(f) = etc.create("shells", Permissions::read_only()) {
870                        f.write(0, b"/bin/vsh\n").ok();
871                    }
872
873                    // /etc/motd (message of the day)
874                    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                    // /etc/veridian/session.conf (default desktop session config)
883                    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        // Create DevFS and mount at /dev
899        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        // Create ProcFS and mount at /proc
911        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
931/// Read the entire contents of a file into a Vec<u8>
932///
933/// This is a convenience function that opens a file, reads its entire
934/// contents into memory, and returns the data as a byte vector.
935///
936/// # Arguments
937/// * `path` - The filesystem path to the file
938///
939/// # Returns
940/// * `Ok(Vec<u8>)` - The file contents on success
941/// * `Err(&'static str)` - An error message on failure
942pub fn read_file(path: &str) -> Result<Vec<u8>, KernelError> {
943    let vfs = get_vfs().read();
944
945    // Resolve the path to a VFS node
946    let node = vfs.resolve_path(path)?;
947
948    // Get file metadata to determine size
949    let metadata = node.metadata()?;
950
951    // Ensure it's a file, not a directory
952    if metadata.node_type != NodeType::File {
953        return Err(KernelError::FsError(crate::error::FsError::NotAFile));
954    }
955
956    // Allocate buffer for file contents
957    let size = metadata.size;
958    let mut buffer = vec![0u8; size];
959
960    // Read the entire file
961    let bytes_read = node.read(0, &mut buffer)?;
962
963    // Truncate to actual bytes read (in case file changed)
964    buffer.truncate(bytes_read);
965
966    Ok(buffer)
967}
968
969/// Write data to a file, creating it if it doesn't exist
970///
971/// # Arguments
972/// * `path` - The filesystem path to the file
973/// * `data` - The data to write
974///
975/// # Returns
976/// * `Ok(usize)` - The number of bytes written on success
977/// * `Err(&'static str)` - An error message on failure
978pub fn write_file(path: &str, data: &[u8]) -> Result<usize, KernelError> {
979    let vfs = get_vfs().read();
980
981    // Try to resolve the path first
982    let node = match vfs.resolve_path(path) {
983        Ok(node) => node,
984        Err(_) => {
985            // File doesn't exist, try to create it
986            // Split path into parent directory and filename
987            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            // Get parent directory
998            let parent = vfs.resolve_path(parent_path)?;
999
1000            // Create the file
1001            parent.create(filename, Permissions::default())?
1002        }
1003    };
1004
1005    // Truncate the file first
1006    node.truncate(0)?;
1007
1008    // Write the data
1009    node.write(0, data)
1010}
1011
1012/// Check if a file exists
1013pub fn file_exists(path: &str) -> bool {
1014    let vfs = get_vfs().read();
1015    vfs.resolve_path(path).is_ok()
1016}
1017
1018/// Get file size without reading contents
1019pub 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
1026/// Copy a file from one location to another
1027pub 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
1032/// Append data to a file
1033pub 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    // Write at the end of the file
1040    node.write(current_size, data)
1041}
1042
1043#[cfg(test)]
1044mod tests {
1045    use super::*;
1046
1047    /// Helper: create a Vfs with a ramfs root filesystem already mounted.
1048    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    // --- Permissions tests ---
1056
1057    #[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    // --- Vfs construction tests ---
1120
1121    #[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    // --- Mount tests ---
1134
1135    #[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    // --- Unmount tests ---
1194
1195    #[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    // --- mount_by_type tests ---
1217
1218    #[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    // --- Path resolution tests ---
1258
1259    #[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        // Create directory via the root node
1290        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        // "." should be ignored in path traversal
1318        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        // /parent/child/.. should resolve to /parent
1330        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        // Going up from root should stay at root
1340        let result = vfs.resolve_path("/../..");
1341        assert!(result.is_ok());
1342        assert_eq!(result.unwrap().node_type(), NodeType::Directory);
1343    }
1344
1345    // --- mkdir and unlink tests ---
1346
1347    #[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        // Verify it exists
1354        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        // Should no longer exist
1375        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    // --- set_cwd tests ---
1386
1387    #[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    // --- sync tests ---
1413
1414    #[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()); // No root, but should not error
1426    }
1427
1428    // --- NodeType tests ---
1429
1430    #[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}