kernel/fs/mod.rs
1//! Virtual File System (VFS) module.
2//!
3//! This module provides a flexible Virtual File System implementation that supports
4//! per-task isolated filesystems, containerization, and bind mount functionality.
5//!
6//! # Architecture Overview
7//!
8//! The VFS architecture has evolved to support containerization, process isolation,
9//! and advanced mount operations including bind mounts:
10//!
11//! ## VfsManager Distribution
12//!
13//! - **Per-Task VfsManager**: Each task can have its own isolated `VfsManager` instance
14//! stored as `Option<Arc<VfsManager>>` in the task structure
15//! - **Shared Filesystems**: Multiple VfsManager instances can share underlying filesystem
16//! objects while maintaining independent mount points
17//! - **Bind Mounts**: Support for mounting directories from one location to another,
18//! including cross-VFS bind mounting for container orchestration
19//!
20//! ## Key Components
21//!
22//! - `VfsManager`: Main VFS management structure supporting both isolation and sharing
23//! - `FileSystemDriverManager`: Global singleton for filesystem driver registration
24//! - `VirtualFileSystem`: Trait combining filesystem and file operation interfaces
25//! - `MountPoint`: Associates filesystem instances with mount paths
26//! - `MountTree`: Hierarchical mount tree structure supporting bind mounts
27//!
28//! ## Bind Mount Functionality
29//!
30//! The VFS provides comprehensive bind mount support for flexible directory mapping:
31//!
32//! ### Basic Bind Mounts
33//! ```rust
34//! let mut vfs = VfsManager::new();
35//! // Mount a directory at another location
36//! vfs.bind_mount("/source/dir", "/target/dir", false)?;
37//! ```
38//!
39//! ### Read-Only Bind Mounts
40//! ```rust
41//! // Create read-only bind mount for security
42//! vfs.bind_mount("/source/dir", "/readonly/dir", true)?;
43//! ```
44//!
45//! ### Cross-VFS Bind Mounts
46//! ```rust
47//! // Share directories between isolated VFS instances
48//! let host_vfs = Arc::new(vfs_manager);
49//! container_vfs.bind_mount_from(&host_vfs, "/host/data", "/container/data", false)?;
50//! ```
51//!
52
53//! ### Thread-Safe Access
54//! Bind mount operations are thread-safe and can be called from system call context:
55//! ```rust
56//! // Use shared reference method for system calls
57//! vfs_arc.bind_mount_shared_ref("/source", "/target", false)?;
58//! ```
59//!
60//! ## Usage Patterns
61//!
62//! ### Container Isolation with Bind Mounts
63//! ```rust
64//! // Create isolated VfsManager for container
65//! let mut container_vfs = VfsManager::new();
66//! container_vfs.mount(fs_id, "/");
67//!
68//! // Bind mount host resources into container
69//! let host_vfs = Arc::new(host_vfs_manager);
70//! container_vfs.bind_mount_from(&host_vfs, "/host/shared", "/shared", true)?;
71//!
72//! // Assign to task
73//! task.vfs = Some(Arc::new(container_vfs));
74//! ```
75//!
76//! ### Shared Filesystem Access
77//!
78//! The VFS supports two distinct patterns for sharing filesystem resources:
79//!
80//! #### VFS Sharing via Arc
81//! ```rust
82//! // Share entire VfsManager instance including mount points
83//! let shared_vfs = Arc::new(original_vfs);
84//! let task_vfs = Arc::clone(&shared_vfs);
85//!
86//! // All mount operations affect the shared mount tree
87//! shared_vfs.mount(tmpfs_id, "/tmp")?; // Visible to all references
88//!
89//! // Useful for:
90//! // - Fork-like behavior where child inherits parent's full filesystem view
91//! // - Thread-like sharing where all threads see the same mount points
92//! // - System-wide mount operations
93//! ```
94//!
95//! The design enables flexible deployment scenarios from simple shared filesystems
96//! to complete filesystem isolation with selective resource sharing for containerized
97//! applications through bind mounts.
98
99pub mod drivers;
100pub mod syscall;
101pub mod helper;
102pub mod tmpfs;
103pub mod params;
104pub mod mount_tree;
105
106use alloc::{boxed::Box, collections::BTreeMap, format, string::{String, ToString}, sync::Arc, vec::Vec};
107use alloc::vec;
108use core::fmt;
109use crate::{device::{block::{request::{BlockIORequest, BlockIORequestType}, BlockDevice}, DeviceType}, task::Task, vm::vmem::MemoryArea};
110
111use spin::{Mutex, RwLock};
112use mount_tree::{MountTree, MountPoint as TreeMountPoint, MountType, MountOptions};
113
114extern crate alloc;
115
116pub const MAX_PATH_LENGTH: usize = 1024;
117
118#[derive(Debug, Clone, Copy, PartialEq)]
119pub enum FileSystemErrorKind {
120 NotFound,
121 NoSpace,
122 PermissionDenied,
123 IoError,
124 InvalidData,
125 InvalidPath,
126 AlreadyExists,
127 NotADirectory,
128 NotAFile,
129 ReadOnly,
130 DeviceError,
131 NotSupported,
132 BrokenFileSystem,
133 Busy,
134}
135
136pub struct FileSystemError {
137 pub kind: FileSystemErrorKind,
138 pub message: String,
139}
140
141impl fmt::Debug for FileSystemError {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 write!(f, "FileSystemError {{ kind: {:?}, message: {} }}", self.kind, self.message)
144 }
145}
146
147/// Result type for file system operations
148pub type Result<T> = core::result::Result<T, FileSystemError>;
149
150/// Information about device files in the filesystem
151///
152/// Scarlet uses a simplified device identification system based on unique device IDs
153/// rather than the traditional Unix major/minor number pairs. This provides:
154///
155/// - **Simplified Management**: Single ID instead of major/minor pair reduces complexity
156/// - **Unified Namespace**: All devices share a common ID space regardless of type
157/// - **Dynamic Allocation**: Device IDs can be dynamically assigned without conflicts
158/// - **Type Safety**: Device type is explicitly specified alongside the ID
159///
160/// # Architecture
161///
162/// Each device in Scarlet is uniquely identified by:
163/// - `device_id`: A unique identifier within the system's device namespace
164/// - `device_type`: Explicit type classification (Character, Block, etc.)
165///
166/// This differs from traditional Unix systems where:
167/// - Major numbers identify device drivers
168/// - Minor numbers identify specific devices within a driver
169///
170/// # Examples
171///
172/// ```rust
173/// // Character device for terminal
174/// let tty_device = DeviceFileInfo {
175/// device_id: 1,
176/// device_type: DeviceType::Char,
177/// };
178///
179/// // Block device for storage
180/// let disk_device = DeviceFileInfo {
181/// device_id: 100,
182/// device_type: DeviceType::Block,
183/// };
184/// ```
185#[derive(Debug, Clone, Copy, PartialEq)]
186pub struct DeviceFileInfo {
187 pub device_id: usize,
188 pub device_type: DeviceType,
189}
190
191#[derive(Debug, Clone, Copy, PartialEq)]
192pub enum FileType {
193 RegularFile,
194 Directory,
195 CharDevice(DeviceFileInfo),
196 BlockDevice(DeviceFileInfo),
197 Pipe,
198 SymbolicLink,
199 Socket,
200 Unknown,
201}
202
203#[derive(Debug, Clone, Copy)]
204pub struct FilePermission {
205 pub read: bool,
206 pub write: bool,
207 pub execute: bool,
208}
209
210#[derive(Debug, Clone)]
211pub struct FileMetadata {
212 pub file_type: FileType,
213 pub size: usize,
214 pub permissions: FilePermission,
215 pub created_time: u64,
216 pub modified_time: u64,
217 pub accessed_time: u64,
218}
219
220#[derive(Clone)]
221pub struct File {
222 // pub path: String,
223 handle: Arc<dyn FileHandle>,
224}
225impl File {
226 /// Open a file using a specific VFS manager
227 ///
228 /// # Arguments
229 ///
230 /// * `path` - The path to the file
231 /// * `manager` - The VFS manager to use
232 ///
233 /// # Returns
234 ///
235 /// * `Result<File>` - The opened file object
236 ///
237 pub fn open_with_manager(path: String, manager: &VfsManager) -> Result<Self> {
238 manager.open(&path, 0)
239 }
240
241 /// Read data from the file
242 ///
243 /// # Arguments
244 ///
245 /// * `buffer` - The buffer to read data into
246 ///
247 /// # Returns
248 ///
249 /// * `Result<usize>` - The number of bytes read
250 ///
251 pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
252 self.handle.read(buffer)
253 }
254
255 /// Write data to the file
256 ///
257 /// # Arguments
258 ///
259 /// * `buffer` - The buffer containing data to write
260 ///
261 /// # Returns
262 ///
263 /// * `Result<usize>` - The number of bytes written
264 ///
265 pub fn write(&mut self, buffer: &[u8]) -> Result<usize> {
266 self.handle.write(buffer)
267 }
268
269 /// Change the position within the file
270 pub fn seek(&mut self, whence: SeekFrom) -> Result<u64> {
271 self.handle.seek(whence)
272 }
273
274 /// Get the metadata of the file
275 pub fn metadata(&self) -> Result<FileMetadata> {
276 self.handle.metadata()
277 }
278
279 /// Get the size of the file
280 pub fn size(&self) -> Result<usize> {
281 let metadata = self.metadata()?;
282 Ok(metadata.size)
283 }
284
285 /// Read the entire contents of the file
286 pub fn read_all(&mut self) -> Result<Vec<u8>> {
287 let size = self.size()?;
288 let mut buffer = vec![0u8; size];
289
290 self.seek(SeekFrom::Start(0))?;
291 let read_bytes = self.read(&mut buffer)?;
292
293 if read_bytes != size {
294 buffer.truncate(read_bytes);
295 }
296
297 Ok(buffer)
298 }
299}
300
301impl Drop for File {
302 fn drop(&mut self) {
303 self.handle.release().unwrap();
304 }
305}
306/// Structure representing a directory entry
307#[derive(Debug, Clone)]
308pub struct DirectoryEntry {
309 pub name: String,
310 pub file_type: FileType,
311 pub size: usize,
312 pub metadata: Option<FileMetadata>,
313}
314
315/// Structure representing a directory
316pub struct Directory<'a> {
317 pub path: String,
318 #[allow(dead_code)]
319 manager_ref: ManagerRef<'a>,
320}
321
322impl<'a> Directory<'a> {
323 pub fn open(path: String) -> Self {
324 Self {
325 path,
326 manager_ref: ManagerRef::Global,
327 }
328 }
329
330 pub fn open_with_manager(path: String, manager: &'a mut VfsManager) -> Self {
331 Self {
332 path,
333 manager_ref: ManagerRef::Local(manager),
334 }
335 }
336}
337
338pub enum SeekFrom {
339 Start(u64),
340 Current(i64),
341 End(i64),
342}
343
344/// Trait for file handlers
345pub trait FileHandle: Send + Sync {
346 /// Read from the file
347 fn read(&self, buffer: &mut [u8]) -> Result<usize>;
348
349 /// Write to the file
350 fn write(&self, buffer: &[u8]) -> Result<usize>;
351
352 /// Move the position within the file
353 fn seek(&self, whence: SeekFrom) -> Result<u64>;
354
355 /// Release the file resource
356 fn release(&self) -> Result<()>;
357
358 /// Get the metadata
359 fn metadata(&self) -> Result<FileMetadata>;
360}
361
362/// Trait defining basic file system operations
363pub trait FileSystem: Send + Sync {
364 /// Mount operation
365 fn mount(&mut self, mount_point: &str) -> Result<()>;
366
367 /// Unmount operation
368 fn unmount(&mut self) -> Result<()>;
369
370 /// Get the name of the file system
371 fn name(&self) -> &str;
372}
373
374/// Trait defining file operations
375pub trait FileOperations: Send + Sync {
376 /// Open a file
377 fn open(&self, path: &str, flags: u32) -> Result<Arc<dyn FileHandle>>;
378
379 /// Read directory entries
380 fn read_dir(&self, path: &str) -> Result<Vec<DirectoryEntry>>;
381
382 /// Create a file with the specified type.
383 ///
384 /// # Arguments
385 ///
386 /// * `path` - The path to the file to create.
387 /// * `file_type` - The type of file to create. This can be a regular file, a device file, or other supported types.
388 ///
389 /// # Behavior
390 ///
391 /// - **Regular Files**: These are standard files used for storing data. They are created in the filesystem and can be read from or written to using standard file operations.
392 /// - **Device Files**: These represent hardware devices and are typically used for interacting with device drivers. Creating a device file may involve additional steps, such as associating the file with a specific device driver or hardware resource.
393 ///
394 /// # Side Effects
395 ///
396 /// - Creating a device file may require elevated permissions or specific system configurations.
397 /// - If a file already exists at the specified path, the function will return an error of type `FileSystemErrorKind::AlreadyExists`.
398 ///
399 /// # Returns
400 ///
401 /// * `Result<()>` - `Ok` if the file was created successfully, or an error if the operation failed. Errors may include `PermissionDenied`, `InvalidPath`, or `DeviceError` for device files.
402 fn create_file(&self, path: &str, file_type: FileType) -> Result<()>;
403
404 /// Create a directory
405 fn create_dir(&self, path: &str) -> Result<()>;
406
407 /// Remove a file/directory
408 fn remove(&self, path: &str) -> Result<()>;
409
410 /// Get the metadata
411 fn metadata(&self, path: &str) -> Result<FileMetadata>;
412
413 /// Get the root directory of the file system
414 fn root_dir(&self) -> Result<Directory>;
415}
416
417/// Trait combining the complete VFS interface
418pub trait VirtualFileSystem: FileSystem + FileOperations {}
419
420// Automatically implement VirtualFileSystem if both FileSystem and FileOperations are implemented
421impl<T: FileSystem + FileOperations> VirtualFileSystem for T {}
422
423/// Enum defining the type of file system
424#[derive(Debug, Clone, Copy, PartialEq)]
425pub enum FileSystemType {
426 /// File system that operates on block devices (disk-based)
427 Block,
428 /// File system that operates on memory regions (RAM-based)
429 Memory,
430 /// File system that can operate on both block devices and memory regions
431 Hybrid,
432 /// Special or virtual file systems (e.g., procfs, sysfs)
433 Virtual,
434 /// Device file system (e.g., /dev)
435 Device,
436}
437
438/// Trait for file system drivers
439///
440/// This trait is used to create file systems from block devices or memory areas.
441/// It is not intended to be used directly by the VFS manager.
442/// Instead, the VFS manager will use the appropriate creation method based on the source.
443pub trait FileSystemDriver: Send + Sync {
444 /// Get the name of the file system driver
445 fn name(&self) -> &'static str;
446
447 /// Get the type of the file system
448 fn filesystem_type(&self) -> FileSystemType;
449
450 /// Create a file system from a block device
451 ///
452 /// When implementing this method, ensure that the file system driver can handle block device-based creation.
453 /// If the driver does not support this, return an appropriate error.
454 ///
455 /// # Arguments
456 ///
457 /// * `_block_device` - The block device to use for creating the file system
458 /// * `_block_size` - The block size of the device
459 ///
460 fn create_from_block(&self, _block_device: Box<dyn BlockDevice>, _block_size: usize) -> Result<Box<dyn VirtualFileSystem>> {
461 if self.filesystem_type() == FileSystemType::Memory || self.filesystem_type() == FileSystemType::Virtual {
462 return Err(FileSystemError {
463 kind: FileSystemErrorKind::NotSupported,
464 message: "This file system driver does not support block device-based creation".to_string(),
465 });
466 }
467
468 Err(FileSystemError {
469 kind: FileSystemErrorKind::NotSupported,
470 message: "create_from_block() not implemented for this file system driver".to_string(),
471 })
472 }
473
474 /// Create a file system from a memory area
475 ///
476 /// When implementing this method, ensure that the file system driver can handle memory-based creation.
477 /// If the driver does not support this, return an appropriate error.
478 ///
479 /// # Notes
480 ///
481 /// File system drivers must validate the provided MemoryArea to ensure it is valid.
482 /// If the MemoryArea is invalid, the driver should return an appropriate error.
483 ///
484 /// # Arguments
485 ///
486 /// * `_memory_area` - The memory area to use for creating the file system
487 ///
488 /// # Returns
489 ///
490 /// * `Result<Box<dyn VirtualFileSystem>>` - The created file system
491 ///
492 fn create_from_memory(&self, _memory_area: &crate::vm::vmem::MemoryArea) -> Result<Box<dyn VirtualFileSystem>> {
493 if self.filesystem_type() == FileSystemType::Block {
494 return Err(FileSystemError {
495 kind: FileSystemErrorKind::NotSupported,
496 message: "This file system driver does not support memory-based creation".to_string(),
497 });
498 }
499
500 Err(FileSystemError {
501 kind: FileSystemErrorKind::NotSupported,
502 message: "create_from_memory() not implemented for this file system driver".to_string(),
503 })
504 }
505
506 fn create(&self) -> Result<Box<dyn VirtualFileSystem>> {
507 // Default implementation that can be overridden by specific drivers
508 // This is a convenience method for drivers that do not need to handle block or memory creation
509 Err(FileSystemError {
510 kind: FileSystemErrorKind::NotSupported,
511 message: "create() not implemented for this file system driver".to_string(),
512 })
513 }
514
515 /// Create a file system with structured parameters
516 ///
517 /// This method creates file systems using type-safe structured parameters
518 /// that implement the FileSystemParams trait. This approach replaces the
519 /// old BTreeMap<String, String> approach with better type safety.
520 ///
521 /// # Arguments
522 ///
523 /// * `params` - Structured parameter implementing FileSystemParams
524 ///
525 /// # Returns
526 ///
527 /// * `Result<Box<dyn VirtualFileSystem>>` - The created file system
528 ///
529 /// # Note
530 ///
531 /// This method uses dynamic dispatch for parameter handling to support
532 /// future dynamic filesystem module loading while maintaining type safety.
533 ///
534 fn create_with_params(&self, params: &dyn crate::fs::params::FileSystemParams) -> Result<Box<dyn VirtualFileSystem>> {
535 // Default implementation falls back to create()
536 let _ = params; // Suppress unused parameter warning
537 self.create()
538 }
539}
540
541// Singleton for global access to the FileSystemDriverManager
542static mut FS_DRIVER_MANAGER: Option<FileSystemDriverManager> = None;
543
544/// Global filesystem driver manager singleton
545///
546/// Provides global access to the FileSystemDriverManager instance.
547/// This function ensures thread-safe initialization of the singleton
548/// and returns a mutable reference for driver registration and filesystem creation.
549///
550/// # Returns
551///
552/// Mutable reference to the global FileSystemDriverManager instance
553///
554/// # Thread Safety
555///
556/// This function is marked as unsafe due to static mutable access, but
557/// the returned manager uses internal synchronization for thread safety.
558#[allow(static_mut_refs)]
559pub fn get_fs_driver_manager() -> &'static mut FileSystemDriverManager {
560 unsafe {
561 if FS_DRIVER_MANAGER.is_none() {
562 FS_DRIVER_MANAGER = Some(FileSystemDriverManager::new());
563 }
564 FS_DRIVER_MANAGER.as_mut().unwrap()
565 }
566}
567
568/// Global filesystem driver manager singleton
569///
570/// Provides global access to the FileSystemDriverManager instance.
571/// This function ensures thread-safe initialization of the singleton
572/// and returns a mutable reference for driver registration and filesystem creation.
573///
574/// # Returns
575///
576/// Mutable reference to the global FileSystemDriverManager instance
577///
578/// # Thread Safety
579///
580/// This function is marked as unsafe due to static mutable access, but
581/// Filesystem driver manager for centralized driver registration and management
582///
583/// The FileSystemDriverManager provides a centralized system for managing filesystem
584/// drivers in the kernel. It separates driver management responsibilities from individual
585/// VfsManager instances, enabling shared driver access across multiple VFS namespaces.
586///
587/// # Features
588///
589/// - **Driver Registration**: Register filesystem drivers for system-wide use
590/// - **Type-Safe Creation**: Create filesystems with structured parameter validation
591/// - **Multi-Source Support**: Support for block device, memory, and virtual filesystems
592/// - **Thread Safety**: All operations are thread-safe using RwLock protection
593/// - **Future Extensibility**: Designed for dynamic filesystem module loading
594///
595/// # Architecture
596///
597/// The manager maintains a registry of drivers identified by name, with each driver
598/// implementing the FileSystemDriver trait. Drivers specify their supported source
599/// types (block, memory, virtual) and provide creation methods for each type.
600///
601/// # Usage
602///
603/// ```rust
604/// // Register a filesystem driver
605/// let manager = get_fs_driver_manager();
606/// manager.register_driver(Box::new(MyFSDriver));
607///
608/// // Create filesystem from block device
609/// let device = get_block_device();
610/// let fs = manager.create_from_block("myfs", device, 512)?;
611///
612/// // Create filesystem with structured parameters
613/// let params = MyFSParams::new();
614/// let fs = manager.create_with_params("myfs", ¶ms)?;
615/// ```
616pub struct FileSystemDriverManager {
617 /// Registered file system drivers indexed by name
618 drivers: RwLock<BTreeMap<String, Box<dyn FileSystemDriver>>>,
619}
620
621impl FileSystemDriverManager {
622 /// Create a new filesystem driver manager
623 ///
624 /// Initializes an empty driver manager with no registered drivers.
625 /// Drivers must be registered using register_driver() before they
626 /// can be used to create filesystems.
627 ///
628 /// # Returns
629 ///
630 /// A new FileSystemDriverManager instance
631 pub fn new() -> Self {
632 Self {
633 drivers: RwLock::new(BTreeMap::new()),
634 }
635 }
636
637 /// Register a filesystem driver
638 ///
639 /// Adds a new filesystem driver to the manager's registry. The driver
640 /// will be indexed by its name() method return value. If a driver with
641 /// the same name already exists, it will be replaced.
642 ///
643 /// # Arguments
644 ///
645 /// * `driver` - The filesystem driver to register, implementing FileSystemDriver trait
646 ///
647 /// # Example
648 ///
649 /// ```rust
650 /// let manager = get_fs_driver_manager();
651 /// manager.register_driver(Box::new(MyFileSystemDriver));
652 /// ```
653 pub fn register_driver(&mut self, driver: Box<dyn FileSystemDriver>) {
654 self.drivers.write().insert(driver.name().to_string(), driver);
655 }
656
657 /// Get a list of registered driver names
658 ///
659 /// Returns the names of all currently registered filesystem drivers.
660 /// This is useful for debugging and system introspection.
661 ///
662 /// # Returns
663 ///
664 /// Vector of driver names in alphabetical order
665 pub fn list_drivers(&self) -> Vec<String> {
666 self.drivers.read().keys().cloned().collect()
667 }
668
669 /// Check if a driver with the specified name is registered
670 ///
671 /// Performs a quick lookup to determine if a named driver exists
672 /// in the registry without attempting to use it.
673 ///
674 /// # Arguments
675 ///
676 /// * `driver_name` - The name of the driver to check for
677 ///
678 /// # Returns
679 ///
680 /// `true` if the driver is registered, `false` otherwise
681 pub fn has_driver(&self, driver_name: &str) -> bool {
682 self.drivers.read().contains_key(driver_name)
683 }
684
685 /// Create a filesystem from a block device
686 ///
687 /// Creates a new filesystem instance using the specified driver and block device.
688 /// The driver must support block device-based filesystem creation. This method
689 /// validates that the driver supports block devices before attempting creation.
690 ///
691 /// # Arguments
692 ///
693 /// * `driver_name` - The name of the registered driver to use
694 /// * `block_device` - The block device that will store the filesystem data
695 /// * `block_size` - The block size for I/O operations (typically 512, 1024, or 4096 bytes)
696 ///
697 /// # Returns
698 ///
699 /// * `Ok(Box<dyn VirtualFileSystem>)` - Successfully created filesystem instance
700 /// * `Err(FileSystemError)` - If driver not found, doesn't support block devices, or creation fails
701 ///
702 /// # Errors
703 ///
704 /// - `NotFound` - Driver with the specified name is not registered
705 /// - `NotSupported` - Driver doesn't support block device-based filesystems
706 /// - Driver-specific errors during filesystem creation
707 ///
708 /// # Example
709 ///
710 /// ```rust
711 /// let device = get_block_device();
712 /// let fs = manager.create_from_block("ext4", device, 4096)?;
713 /// ```
714 pub fn create_from_block(
715 &self,
716 driver_name: &str,
717 block_device: Box<dyn BlockDevice>,
718 block_size: usize,
719 ) -> Result<Box<dyn VirtualFileSystem>> {
720 let binding = self.drivers.read();
721 let driver = binding.get(driver_name).ok_or(FileSystemError {
722 kind: FileSystemErrorKind::NotFound,
723 message: format!("File system driver '{}' not found", driver_name),
724 })?;
725
726 if driver.filesystem_type() == FileSystemType::Memory || driver.filesystem_type() == FileSystemType::Virtual {
727 return Err(FileSystemError {
728 kind: FileSystemErrorKind::NotSupported,
729 message: format!("File system driver '{}' does not support block devices", driver_name),
730 });
731 }
732
733 driver.create_from_block(block_device, block_size)
734 }
735
736 /// Create a filesystem from a memory area
737 ///
738 /// Creates a new filesystem instance using the specified driver and memory region.
739 /// This is typically used for RAM-based filesystems like tmpfs or for mounting
740 /// filesystem images stored in memory (e.g., initramfs).
741 ///
742 /// # Arguments
743 ///
744 /// * `driver_name` - The name of the registered driver to use
745 /// * `memory_area` - The memory region containing filesystem data or available for use
746 ///
747 /// # Returns
748 ///
749 /// * `Ok(Box<dyn VirtualFileSystem>)` - Successfully created filesystem instance
750 /// * `Err(FileSystemError)` - If driver not found, doesn't support memory-based creation, or creation fails
751 ///
752 /// # Errors
753 ///
754 /// - `NotFound` - Driver with the specified name is not registered
755 /// - `NotSupported` - Driver only supports block device-based filesystems
756 /// - Driver-specific errors during filesystem creation
757 ///
758 /// # Example
759 ///
760 /// ```rust
761 /// let memory_area = MemoryArea::new(addr, size);
762 /// let fs = manager.create_from_memory("cpiofs", &memory_area)?;
763 /// ```
764 pub fn create_from_memory(
765 &self,
766 driver_name: &str,
767 memory_area: &MemoryArea,
768 ) -> Result<Box<dyn VirtualFileSystem>> {
769 let binding = self.drivers.read();
770 let driver = binding.get(driver_name).ok_or(FileSystemError {
771 kind: FileSystemErrorKind::NotFound,
772 message: format!("File system driver '{}' not found", driver_name),
773 })?;
774
775 if driver.filesystem_type() == FileSystemType::Block {
776 return Err(FileSystemError {
777 kind: FileSystemErrorKind::NotSupported,
778 message: format!("File system driver '{}' does not support memory-based filesystems", driver_name),
779 });
780 }
781
782 driver.create_from_memory(memory_area)
783 }
784
785 /// Create a filesystem with structured parameters
786 ///
787 /// This method creates filesystems using type-safe structured parameters that
788 /// implement the FileSystemParams trait. This approach replaces the old BTreeMap<String, String>
789 /// configuration method with better type safety and validation.
790 ///
791 /// The method uses dynamic dispatch to handle different parameter types, enabling
792 /// future dynamic filesystem module loading while maintaining type safety at the
793 /// driver level.
794 ///
795 /// # Arguments
796 ///
797 /// * `driver_name` - The name of the registered driver to use
798 /// * `params` - Parameter structure implementing FileSystemParams trait
799 ///
800 /// # Returns
801 ///
802 /// * `Ok(Box<dyn VirtualFileSystem>)` - Successfully created filesystem instance
803 /// * `Err(FileSystemError)` - If driver not found, parameters invalid, or creation fails
804 ///
805 /// # Errors
806 ///
807 /// - `NotFound` - Driver with the specified name is not registered
808 /// - `NotSupported` - Driver doesn't support the provided parameter type
809 /// - Driver-specific parameter validation errors
810 ///
811 /// # Example
812 ///
813 /// ```rust
814 /// use crate::fs::params::TmpFSParams;
815 ///
816 /// let params = TmpFSParams::new(1048576, 0); // 1MB limit
817 /// let fs = manager.create_with_params("tmpfs", ¶ms)?;
818 /// ```
819 ///
820 /// # Note
821 ///
822 /// This method uses dynamic dispatch for parameter handling to support
823 /// future dynamic filesystem module loading while maintaining type safety.
824 pub fn create_with_params(
825 &self,
826 driver_name: &str,
827 params: &dyn crate::fs::params::FileSystemParams
828 ) -> Result<Box<dyn VirtualFileSystem>> {
829 let binding = self.drivers.read();
830 let driver = binding.get(driver_name)
831 .ok_or_else(|| FileSystemError {
832 kind: FileSystemErrorKind::NotFound,
833 message: format!("File system driver '{}' not found", driver_name),
834 })?;
835
836 // Use dynamic dispatch for structured parameters
837 driver.create_with_params(params)
838 }
839
840 /// Get filesystem driver information by name
841 ///
842 /// Retrieves the filesystem type supported by a registered driver.
843 /// This is useful for validating driver capabilities before attempting
844 /// to create filesystems.
845 ///
846 /// # Arguments
847 ///
848 /// * `driver_name` - The name of the driver to query
849 ///
850 /// # Returns
851 ///
852 /// * `Some(FileSystemType)` - The filesystem type if driver exists
853 /// * `None` - If no driver with the specified name is registered
854 ///
855 /// # Example
856 ///
857 /// ```rust
858 /// if let Some(fs_type) = manager.get_driver_type("tmpfs") {
859 /// match fs_type {
860 /// FileSystemType::Virtual => println!("TmpFS is a virtual filesystem"),
861 /// _ => println!("Unexpected filesystem type"),
862 /// }
863 /// }
864 /// ```
865 pub fn get_driver_type(&self, driver_name: &str) -> Option<FileSystemType> {
866 self.drivers.read().get(driver_name).map(|driver| driver.filesystem_type())
867 }
868}
869
870impl Default for FileSystemDriverManager {
871 fn default() -> Self {
872 Self::new()
873 }
874}
875
876pub type FileSystemRef = Arc<RwLock<Box<dyn VirtualFileSystem>>>;
877
878pub enum ManagerRef<'a> {
879 Global, // Use the global manager
880 Local(&'a mut VfsManager), // Use a specific manager
881}
882
883
884/// VFS manager for per-task or shared filesystem management.
885///
886/// `VfsManager` provides flexible virtual filesystem management supporting both
887/// process isolation and filesystem sharing scenarios.
888///
889/// # Architecture
890///
891/// Each `VfsManager` instance maintains:
892/// - Independent mount point namespace using hierarchical MountTree
893/// - Reference-counted filesystem objects that can be shared between managers
894/// - Thread-safe operations via RwLock protection
895/// - Security-enhanced path resolution with protection against directory traversal
896///
897/// # Usage Scenarios
898///
899/// ## 1. Container Isolation
900/// Each container gets its own `VfsManager` with completely isolated mount points:
901/// ```rust
902/// let mut container_vfs = VfsManager::new();
903/// let fs_index = container_vfs.register_fs(container_fs);
904/// container_vfs.mount(fs_index, "/");
905/// task.vfs = Some(Arc::new(container_vfs));
906/// ```
907///
908/// ## 2. Shared Filesystem Access
909/// Multiple tasks can share VfsManager objects using Arc:
910/// ```rust
911/// let shared_vfs = Arc::new(original_vfs); // Shares filesystem objects and mount points
912/// let fs_index = shared_vfs.register_fs(shared_fs);
913/// shared_vfs.mount(fs_index, "/mnt/shared"); // Shared mount points
914/// ```
915///
916/// # Performance Improvements
917///
918/// The new MountTree implementation provides:
919/// - O(log k) path resolution where k is path depth
920/// - Efficient mount point hierarchy management
921/// - Security-enhanced path normalization
922/// - Reduced memory usage through Trie structure
923///
924/// # Thread Safety
925///
926/// All internal data structures use RwLock for thread-safe concurrent access.
927/// VfsManager can be shared between threads using Arc for cases requiring
928/// shared filesystem access across multiple tasks.
929pub struct VfsManager {
930 filesystems: RwLock<BTreeMap<usize, FileSystemRef>>,
931 mount_tree: RwLock<MountTree>,
932 next_fs_id: RwLock<usize>,
933}
934
935impl VfsManager {
936 /// Create a new VFS manager instance
937 ///
938 /// This method creates a new VfsManager with empty filesystem registry
939 /// and mount tree. Each VfsManager instance provides an isolated
940 /// filesystem namespace, making it suitable for containerization and
941 /// process isolation scenarios.
942 ///
943 /// # Returns
944 ///
945 /// * `Self` - A new VfsManager instance ready for filesystem registration and mounting
946 ///
947 /// # Examples
948 ///
949 /// ```rust
950 /// // Create isolated VFS for a container
951 /// let container_vfs = VfsManager::new();
952 ///
953 /// // Create shared VFS for multiple tasks
954 /// let shared_vfs = Arc::new(VfsManager::new());
955 /// ```
956 pub fn new() -> Self {
957 Self {
958 filesystems: RwLock::new(BTreeMap::new()),
959 mount_tree: RwLock::new(MountTree::new()),
960 next_fs_id: RwLock::new(1), // Start from 1 to avoid zero ID
961 }
962 }
963
964 /// Register a filesystem with the VFS manager
965 ///
966 /// This method adds a filesystem instance to the VfsManager's registry,
967 /// assigning it a unique ID for future operations. The filesystem remains
968 /// available for mounting until it's actually mounted on a mount point.
969 ///
970 /// # Arguments
971 ///
972 /// * `fs` - The filesystem instance to register (must implement VirtualFileSystem)
973 ///
974 /// # Returns
975 ///
976 /// * `usize` - Unique filesystem ID for use in mount operations
977 ///
978 /// # Thread Safety
979 ///
980 /// This method is thread-safe and can be called concurrently from multiple threads.
981 ///
982 /// # Examples
983 ///
984 /// ```rust
985 /// // Register a block-based filesystem
986 /// let device = Box::new(SomeBlockDevice::new());
987 /// let fs = Box::new(SomeFileSystem::new("myfs", device, 512));
988 /// let fs_id = vfs_manager.register_fs(fs);
989 ///
990 /// // Later mount the filesystem
991 /// vfs_manager.mount(fs_id, "/mnt")?;
992 /// ```
993 pub fn register_fs(&mut self, fs: Box<dyn VirtualFileSystem>) -> usize {
994 let mut next_fs_id = self.next_fs_id.write();
995 let fs_id = *next_fs_id;
996 *next_fs_id += 1;
997
998 // Do not set ID on filesystem - VfsManager manages it
999 let fs_ref = Arc::new(RwLock::new(fs));
1000 self.filesystems.write().insert(fs_id, fs_ref);
1001
1002 fs_id
1003 }
1004
1005 /// Create and register a block device-based filesystem
1006 ///
1007 /// This convenience method combines filesystem creation and registration in a single
1008 /// operation. It uses the global FileSystemDriverManager to create a filesystem
1009 /// from the specified block device and automatically registers it with this VfsManager.
1010 ///
1011 /// # Arguments
1012 ///
1013 /// * `driver_name` - The name of the registered filesystem driver to use
1014 /// * `block_device` - The block device that will store the filesystem data
1015 /// * `block_size` - The block size for I/O operations (typically 512, 1024, or 4096 bytes)
1016 ///
1017 /// # Returns
1018 ///
1019 /// * `Ok(usize)` - The filesystem ID assigned by this VfsManager
1020 /// * `Err(FileSystemError)` - If driver not found, creation fails, or registration fails
1021 ///
1022 /// # Example
1023 ///
1024 /// ```rust
1025 /// let device = get_block_device();
1026 /// let fs_id = vfs_manager.create_and_register_block_fs("ext4", device, 4096)?;
1027 /// vfs_manager.mount(fs_id, "/mnt")?;
1028 /// ```
1029 pub fn create_and_register_block_fs(
1030 &mut self,
1031 driver_name: &str,
1032 block_device: Box<dyn BlockDevice>,
1033 block_size: usize,
1034 ) -> Result<usize> {
1035
1036 // Create the file system using the driver manager
1037 let fs = get_fs_driver_manager().create_from_block(driver_name, block_device, block_size)?;
1038
1039 Ok(self.register_fs(fs))
1040 }
1041
1042 /// Create and register a memory-based filesystem
1043 ///
1044 /// This convenience method combines filesystem creation and registration in a single
1045 /// operation for memory-based filesystems like tmpfs or initramfs. It uses the global
1046 /// FileSystemDriverManager to create a filesystem and automatically registers it.
1047 ///
1048 /// # Arguments
1049 ///
1050 /// * `driver_name` - The name of the registered filesystem driver to use
1051 /// * `memory_area` - The memory region containing filesystem data or available for use
1052 ///
1053 /// # Returns
1054 ///
1055 /// * `Ok(usize)` - The filesystem ID assigned by this VfsManager
1056 /// * `Err(FileSystemError)` - If driver not found, creation fails, or registration fails
1057 ///
1058 /// # Example
1059 ///
1060 /// ```rust
1061 /// let memory_area = MemoryArea::new(initramfs_addr, initramfs_size);
1062 /// let fs_id = vfs_manager.create_and_register_memory_fs("cpiofs", &memory_area)?;
1063 /// vfs_manager.mount(fs_id, "/")?;
1064 /// ```
1065 pub fn create_and_register_memory_fs(
1066 &mut self,
1067 driver_name: &str,
1068 memory_area: &crate::vm::vmem::MemoryArea,
1069 ) -> Result<usize> {
1070
1071 // Create the file system using the driver manager
1072 let fs = get_fs_driver_manager().create_from_memory(driver_name, memory_area)?;
1073
1074 Ok(self.register_fs(fs))
1075 }
1076
1077 /// Create and register a file system with structured parameters
1078 ///
1079 /// This method allows creating file systems with structured configuration
1080 /// parameters. It uses dynamic dispatch to handle different parameter types,
1081 /// enabling future dynamic filesystem module loading.
1082 ///
1083 /// # Arguments
1084 ///
1085 /// * `driver_name` - The name of the file system driver
1086 /// * `params` - Parameter structure implementing FileSystemParams
1087 ///
1088 /// # Returns
1089 ///
1090 /// * `Result<usize>` - The ID of the registered file system
1091 ///
1092 /// # Errors
1093 ///
1094 /// * `FileSystemError` - If the driver is not found or if the file system cannot be created
1095 ///
1096 /// # Example
1097 ///
1098 /// ```rust
1099 /// use crate::fs::params::TmpFSParams;
1100 ///
1101 /// let params = TmpFSParams::with_memory_limit(1048576); // 1MB limit
1102 /// let fs_id = manager.create_and_register_fs_with_params("tmpfs", ¶ms)?;
1103 /// ```
1104 pub fn create_and_register_fs_with_params(
1105 &mut self,
1106 driver_name: &str,
1107 params: &dyn crate::fs::params::FileSystemParams,
1108 ) -> Result<usize> {
1109
1110 // Create the file system using the driver manager with structured parameters
1111 let fs = get_fs_driver_manager().create_with_params(driver_name, params)?;
1112
1113 Ok(self.register_fs(fs))
1114 }
1115
1116 /// Mount a file system at a specified mount point
1117 ///
1118 /// # Arguments
1119 ///
1120 /// * `fs_id` - The ID of the file system to mount
1121 /// * `mount_point` - The mount point for the file system
1122 ///
1123 /// # Returns
1124 ///
1125 /// * `Result<()>` - Ok if the mount was successful, Err if there was an error
1126 ///
1127 pub fn mount(&mut self, fs_id: usize, mount_point: &str) -> Result<()> {
1128 let mut filesystems = self.filesystems.write();
1129 // Remove the file system from available pool using BTreeMap
1130 let fs = filesystems.remove(&fs_id)
1131 .ok_or(FileSystemError {
1132 kind: FileSystemErrorKind::NotFound,
1133 message: format!("File system with ID {} not found", fs_id),
1134 })?;
1135
1136 {
1137 let mut fs_write = fs.write();
1138
1139 // Perform the mount operation
1140 fs_write.mount(mount_point)?;
1141 }
1142
1143 // Create mount point entry with enhanced metadata
1144 let mount_point_entry = TreeMountPoint {
1145 path: mount_point.to_string(),
1146 fs: fs.clone(),
1147 fs_id, // Store VfsManager's ID in mount point
1148 mount_type: MountType::Regular,
1149 mount_options: MountOptions::default(),
1150 parent: None,
1151 children: Vec::new(),
1152 mount_time: 0, // TODO: Get actual timestamp
1153 };
1154
1155 // Register with MountTree
1156 self.mount_tree.write().mount(mount_point, mount_point_entry)?;
1157
1158 Ok(())
1159 }
1160
1161 /// Unmount a file system from a specified mount point
1162 ///
1163 /// # Arguments
1164 ///
1165 /// * `mount_point` - The mount point to unmount
1166 ///
1167 /// # Returns
1168 ///
1169 /// * `Result<()>` - Ok if the unmount was successful, Err if there was an error
1170 ///
1171 pub fn unmount(&mut self, mount_point: &str) -> Result<()> {
1172 // Remove the mount point from MountTree
1173 let mp = self.mount_tree.write().remove(mount_point)?;
1174
1175 match &mp.mount_type {
1176 mount_tree::MountType::Bind { .. } => {
1177 // Bind mounts do not need to unmount the underlying filesystem
1178 // They are just references to existing filesystems
1179 },
1180 _ => {
1181 // For regular mounts, we need to call unmount on the filesystem
1182 let mut fs_write = mp.fs.write();
1183 fs_write.unmount()?;
1184
1185 // Return the file system to the registration list using stored fs_id
1186 self.filesystems.write().insert(mp.fs_id, mp.fs.clone());
1187 }
1188 }
1189
1190
1191 Ok(())
1192 }
1193
1194 /// Bind mount a source path to a target path
1195 ///
1196 /// This creates a bind mount where the target path will provide access to the same
1197 /// content as the source path. The bind mount can be read-only or read-write.
1198 ///
1199 /// # Arguments
1200 ///
1201 /// * `source_path` - The source path to bind from
1202 /// * `target_path` - The target mount point where the source will be accessible
1203 /// * `read_only` - Whether the bind mount should be read-only
1204 ///
1205 /// # Returns
1206 ///
1207 /// * `Result<()>` - Ok if the bind mount was successful, Err otherwise
1208 ///
1209 /// # Example
1210 ///
1211 /// ```rust
1212 /// // Bind mount /mnt/source to /mnt/target as read-only
1213 /// vfs_manager.bind_mount("/mnt/source", "/mnt/target", true)?;
1214 /// ```
1215 pub fn bind_mount(&mut self, source_path: &str, target_path: &str, read_only: bool) -> Result<()> {
1216 let normalized_source = Self::normalize_path(source_path);
1217 let normalized_target = Self::normalize_path(target_path);
1218
1219 // Get the source MountNode
1220 let mount_tree = self.mount_tree.read();
1221 let (source_mount_node, source_relative_path) = mount_tree.resolve(&normalized_source)?;
1222 drop(mount_tree);
1223
1224 // Get the source filesystem (for caching)
1225 let source_mount_point = source_mount_node.get_mount_point()?;
1226 let source_fs = source_mount_point.fs.clone();
1227
1228 // Create the bind mount point
1229 let bind_mount_point = mount_tree::MountPoint {
1230 path: normalized_target.clone(),
1231 fs: source_fs,
1232 fs_id: 0, // Special ID for bind mounts
1233 mount_type: mount_tree::MountType::Bind {
1234 source_mount_node,
1235 source_relative_path,
1236 bind_type: if read_only { mount_tree::BindType::ReadOnly } else { mount_tree::BindType::ReadWrite },
1237 },
1238 mount_options: mount_tree::MountOptions {
1239 read_only,
1240 ..Default::default()
1241 },
1242 parent: None,
1243 children: Vec::new(),
1244 mount_time: 0, // TODO: actual timestamp
1245 };
1246
1247 // Insert the bind mount into the MountTree
1248 self.mount_tree.write().insert(&normalized_target, bind_mount_point)?;
1249
1250 Ok(())
1251 }
1252
1253 /// Bind mount from another VFS manager
1254 ///
1255 /// This creates a bind mount where the target path in this VFS manager
1256 /// will provide access to content from a different VFS manager instance.
1257 /// This is useful for sharing filesystem content between containers.
1258 ///
1259 /// # Arguments
1260 ///
1261 /// * `source_vfs` - The source VFS manager containing the source path
1262 /// * `source_path` - The source path in the source VFS manager
1263 /// * `target_path` - The target mount point in this VFS manager
1264 /// * `read_only` - Whether the bind mount should be read-only
1265 ///
1266 /// # Returns
1267 ///
1268 /// * `Result<()>` - Ok if the bind mount was successful, Err otherwise
1269 ///
1270 /// # Example
1271 ///
1272 /// ```rust
1273 /// // Bind mount /data from host_vfs to /mnt/shared in container_vfs
1274 /// container_vfs.bind_mount_from(&host_vfs, "/data", "/mnt/shared", false)?;
1275 /// ```
1276 pub fn bind_mount_from(
1277 &mut self,
1278 source_vfs: &Arc<VfsManager>,
1279 source_path: &str,
1280 target_path: &str,
1281 read_only: bool
1282 ) -> Result<()> {
1283 let normalized_source = Self::normalize_path(source_path);
1284 let normalized_target = Self::normalize_path(target_path);
1285
1286 // Get MountNode from source VFS
1287 let source_mount_tree = source_vfs.mount_tree.read();
1288 let (source_mount_node, source_relative_path) = source_mount_tree.resolve(&normalized_source)?;
1289 drop(source_mount_tree);
1290
1291 // Get the source filesystem
1292 let source_mount_point = source_mount_node.get_mount_point()?;
1293 let source_fs = source_mount_point.fs.clone();
1294
1295 // Create the bind mount point
1296 let bind_mount_point = mount_tree::MountPoint {
1297 path: normalized_target.clone(),
1298 fs: source_fs,
1299 fs_id: 0,
1300 mount_type: mount_tree::MountType::Bind {
1301 source_mount_node,
1302 source_relative_path,
1303 bind_type: if read_only { mount_tree::BindType::ReadOnly } else { mount_tree::BindType::ReadWrite },
1304 },
1305 mount_options: mount_tree::MountOptions {
1306 read_only,
1307 ..Default::default()
1308 },
1309 parent: None,
1310 children: Vec::new(),
1311 mount_time: 0,
1312 };
1313
1314 // Insert the bind mount into the MountTree
1315 self.mount_tree.write().insert(&normalized_target, bind_mount_point)?;
1316
1317 Ok(())
1318 }
1319
1320 /// Create a shared bind mount
1321 ///
1322 /// This creates a shared bind mount where changes to mount propagation
1323 /// will be shared between the source and target. This is useful for
1324 /// scenarios where you want mount events to propagate between namespaces.
1325 ///
1326 /// # Arguments
1327 ///
1328 /// * `source_path` - The source path to bind from
1329 /// * `target_path` - The target mount point
1330 ///
1331 /// # Returns
1332 ///
1333 /// * `Result<()>` - Ok if the shared bind mount was successful, Err otherwise
1334 pub fn bind_mount_shared(&mut self, source_path: &str, target_path: &str) -> Result<()> {
1335 // Normalize the source path to prevent directory traversal
1336 let normalized_source_path = Self::normalize_path(source_path);
1337
1338 // Resolve the source path to get the mount node and relative path within that mount
1339 let (source_mount_node, source_relative_path) = self.mount_tree.read().resolve(&normalized_source_path)?;
1340
1341 let mount_point_entry = TreeMountPoint {
1342 path: target_path.to_string(),
1343 fs: source_mount_node.get_mount_point()?.fs.clone(),
1344 fs_id: 0, // Special ID for bind mounts
1345 mount_type: MountType::Bind {
1346 source_mount_node,
1347 source_relative_path,
1348 bind_type: mount_tree::BindType::Shared,
1349 },
1350 mount_options: MountOptions::default(),
1351 parent: None,
1352 children: Vec::new(),
1353 mount_time: 0, // TODO: Get actual timestamp
1354 };
1355
1356 self.mount_tree.write().mount(target_path, mount_point_entry)?;
1357
1358 Ok(())
1359 }
1360
1361 /// Thread-safe bind mount for use from system calls
1362 ///
1363 /// This method can be called on a shared VfsManager (Arc<VfsManager>)
1364 /// from system call context where &mut self is not available.
1365 ///
1366 /// # Arguments
1367 ///
1368 /// * `source_path` - The source path to bind from
1369 /// * `target_path` - The target mount point where the source will be accessible
1370 /// * `read_only` - Whether the bind mount should be read-only
1371 ///
1372 /// # Returns
1373 ///
1374 /// * `Result<()>` - Ok if the bind mount was successful, Err otherwise
1375 pub fn bind_mount_shared_ref(&self, source_path: &str, target_path: &str, read_only: bool) -> Result<()> {
1376 // Normalize the source path to prevent directory traversal
1377 let normalized_source_path = Self::normalize_path(source_path);
1378
1379 // Resolve the source path to get the mount node and relative path within that mount
1380 let (source_mount_node, source_relative_path) = self.mount_tree.read().resolve(&normalized_source_path)?;
1381
1382 // Create a bind mount point entry
1383 let bind_type = if read_only {
1384 mount_tree::BindType::ReadOnly
1385 } else {
1386 mount_tree::BindType::ReadWrite
1387 };
1388
1389 let mount_point_entry = TreeMountPoint {
1390 path: target_path.to_string(),
1391 fs: source_mount_node.get_mount_point()?.fs.clone(),
1392 fs_id: 0, // Special ID for bind mounts - they don't consume fs_id
1393 mount_type: MountType::Bind {
1394 source_mount_node,
1395 source_relative_path,
1396 bind_type,
1397 },
1398 mount_options: MountOptions {
1399 read_only,
1400 ..Default::default()
1401 },
1402 parent: None,
1403 children: Vec::new(),
1404 mount_time: 0, // TODO: Get actual timestamp
1405 };
1406
1407 // Register with MountTree
1408 self.mount_tree.write().mount(target_path, mount_point_entry)?;
1409
1410 Ok(())
1411 }
1412
1413 /// Check if a path is a bind mount
1414 ///
1415 /// # Arguments
1416 ///
1417 /// * `path` - The path to check
1418 ///
1419 /// # Returns
1420 ///
1421 /// * `bool` - True if the path is a bind mount, false otherwise
1422 pub fn is_bind_mount(&self, path: &str) -> bool {
1423 // Use non-transparent resolution to check the mount node itself
1424 if let Ok((mount_node, _)) = self.mount_tree.read().resolve_non_transparent(path) {
1425 if let Ok(mount_point) = mount_node.get_mount_point() {
1426 matches!(mount_point.mount_type, MountType::Bind { .. })
1427 } else {
1428 false
1429 }
1430 } else {
1431 false
1432 }
1433 }
1434
1435 /// Normalize a path
1436 ///
1437 /// # Arguments
1438 ///
1439 /// * `path` - The path to normalize
1440 ///
1441 /// # Returns
1442 ///
1443 /// * `String` - The normalized path
1444 ///
1445 fn normalize_path(path: &str) -> String {
1446 // Remember if the path is absolute
1447 let is_absolute = path.starts_with('/');
1448
1449 // Decompose and normalize the path
1450 let mut components = Vec::new();
1451
1452 // Split the path into components and process them
1453 for component in path.split('/') {
1454 match component {
1455 "" => continue, // Skip empty components (consecutive slashes)
1456 "." => continue, // Ignore current directory
1457 ".." => {
1458 // For parent directory, remove the previous component
1459 // However, cannot go above root for absolute paths
1460 if !components.is_empty() && *components.last().unwrap() != ".." {
1461 components.pop();
1462 } else if !is_absolute {
1463 // Keep '..' for relative paths
1464 components.push("..");
1465 }
1466 },
1467 _ => components.push(component), // Normal directory name
1468 }
1469 }
1470
1471 // Construct the result
1472 let normalized = if is_absolute {
1473 // Add / to the beginning for absolute paths
1474 format!("/{}", components.join("/"))
1475 } else if components.is_empty() {
1476 // Current directory if the result is empty for a relative path
1477 ".".to_string()
1478 } else {
1479 // Normal relative path
1480 components.join("/")
1481 };
1482
1483 // Return root for empty path
1484 if normalized.is_empty() {
1485 "/".to_string()
1486 } else {
1487 normalized
1488 }
1489 }
1490
1491 /// Execute a function with the resolved file system and path
1492 ///
1493 /// # Arguments
1494 ///
1495 /// * `path` - The path to resolve
1496 /// * `f` - The function to execute with the resolved file system and path
1497 ///
1498 /// # Returns
1499 ///
1500 /// * `Result<T>` - The result of the function execution
1501 ///
1502 /// # Errors
1503 ///
1504 /// * `FileSystemError` - If no file system is mounted for the specified path
1505 ///
1506 fn with_resolve_path<F, T>(&self, path: &str, f: F) -> Result<T>
1507 where
1508 F: FnOnce(&FileSystemRef, &str) -> Result<T>
1509 {
1510 let (fs, relative_path) = self.resolve_path(path)?;
1511 f(&fs, &relative_path)
1512 }
1513
1514 /// Resolve the path to the file system and relative path
1515 ///
1516 /// This method performs path resolution within the VfsManager's mount tree,
1517 /// handling bind mounts, security validation, and path normalization.
1518 ///
1519 /// # Path Resolution Process
1520 ///
1521 /// 1. **Path Normalization**: Remove `.` and `..` components, validate against directory traversal
1522 /// 2. **Mount Point Lookup**: Find the most specific mount point for the given path
1523 /// 3. **Bind Mount Resolution**: Transparently handle bind mounts by resolving to source
1524 /// 4. **Relative Path Calculation**: Calculate the path relative to the filesystem root
1525 ///
1526 /// # Arguments
1527 ///
1528 /// * `path` - The absolute path to resolve (must start with `/`)
1529 ///
1530 /// # Returns
1531 ///
1532 /// * `Result<(FileSystemRef, String)>` - Tuple containing:
1533 /// - `FileSystemRef`: Arc-wrapped filesystem that handles this path
1534 /// - `String`: Path relative to the filesystem root (always starts with `/`)
1535 ///
1536 /// # Errors
1537 ///
1538 /// * `FileSystemErrorKind::NotFound` - No filesystem mounted for the path
1539 /// * `FileSystemErrorKind::InvalidPath` - Path validation failed (e.g., directory traversal attempt)
1540 ///
1541 /// # Examples
1542 ///
1543 /// ```rust
1544 /// // Mount filesystem at /mnt
1545 /// let fs_id = vfs.register_fs(filesystem);
1546 /// vfs.mount(fs_id, "/mnt")?;
1547 ///
1548 /// // Resolve paths
1549 /// let (fs, rel_path) = vfs.resolve_path("/mnt/dir/file.txt")?;
1550 /// assert_eq!(rel_path, "/dir/file.txt");
1551 ///
1552 /// // Bind mount example
1553 /// vfs.bind_mount("/mnt/data", "/data", false)?;
1554 /// let (fs2, rel_path2) = vfs.resolve_path("/data/file.txt")?;
1555 /// // fs2 points to the same filesystem as fs, rel_path2 is "/data/file.txt"
1556 /// ```
1557 ///
1558 /// # Security
1559 ///
1560 /// This method includes protection against directory traversal attacks:
1561 /// - Normalizes `..` and `.` components
1562 /// - Prevents escaping mount point boundaries
1563 /// - Validates all path components for security
1564 /// # Arguments
1565 ///
1566 /// * `path` - The path to resolve (must be absolute)
1567 ///
1568 /// # Returns
1569 ///
1570 /// * `Result<(FileSystemRef, String)>` - The resolved file system and relative path
1571 ///
1572 /// # Errors
1573 ///
1574 /// * `FileSystemError` - If no file system is mounted for the specified path
1575 ///
1576 fn resolve_path(&self, path: &str) -> Result<(FileSystemRef, String)> {
1577 // Check if the path is absolute
1578 if !path.starts_with('/') {
1579 return Err(FileSystemError {
1580 kind: FileSystemErrorKind::InvalidPath,
1581 message: format!("Path must be absolute: {}", path),
1582 });
1583 }
1584
1585 // Phase 1: Get MountNode and relative path from MountTree
1586 let mount_tree = self.mount_tree.read();
1587 let (mount_node, relative_path) = mount_tree.resolve(path)?;
1588 drop(mount_tree);
1589
1590 // Phase 2: Get MountPoint from MountNode
1591 let mount_point = mount_node.get_mount_point()?;
1592
1593 // Phase 3: Get filesystem and internal path from MountPoint
1594 mount_point.resolve_fs(&relative_path)
1595 }
1596
1597 /// Get absolute path from relative path and current working directory
1598 ///
1599 /// # Arguments
1600 /// Convert a relative path to an absolute path using the task's current working directory
1601 ///
1602 /// This method provides path resolution for system calls that accept relative paths.
1603 /// It combines the task's current working directory with the relative path to
1604 /// create an absolute path suitable for VFS operations.
1605 ///
1606 /// # Arguments
1607 ///
1608 /// * `task` - The task containing the current working directory
1609 /// * `path` - The relative path to convert (if already absolute, returns as-is)
1610 ///
1611 /// # Returns
1612 ///
1613 /// * `Result<String>` - The absolute path ready for VFS operations
1614 ///
1615 /// # Examples
1616 ///
1617 /// ```rust
1618 /// // If task cwd is "/home/user" and path is "documents/file.txt"
1619 /// let abs_path = VfsManager::to_absolute_path(&task, "documents/file.txt")?;
1620 /// assert_eq!(abs_path, "/home/user/documents/file.txt");
1621 ///
1622 /// // Absolute paths are returned unchanged
1623 /// let abs_path = VfsManager::to_absolute_path(&task, "/etc/config")?;
1624 /// assert_eq!(abs_path, "/etc/config");
1625 /// ```
1626 pub fn to_absolute_path(task: &Task, path: &str) -> Result<String> {
1627 if path.starts_with('/') {
1628 // If the path is already absolute, return it as is
1629 Ok(path.to_string())
1630 } else {
1631 let cwd = task.cwd.clone();
1632 if cwd.is_none() {
1633 return Err(FileSystemError {
1634 kind: FileSystemErrorKind::InvalidPath,
1635 message: "Current working directory is not set".to_string(),
1636 });
1637 }
1638 // Combine the current working directory and the relative path to create an absolute path
1639 let mut absolute_path = cwd.unwrap();
1640 if !absolute_path.ends_with('/') {
1641 absolute_path.push('/');
1642 }
1643 absolute_path.push_str(path);
1644 // Normalize and return the result
1645 Ok(Self::normalize_path(&absolute_path))
1646 }
1647 }
1648
1649 /// Open a file for reading/writing
1650 ///
1651 /// This method opens a file through the VFS layer, automatically resolving
1652 /// the path to the appropriate filesystem and handling mount points and
1653 /// bind mounts transparently.
1654 ///
1655 /// # Arguments
1656 ///
1657 /// * `path` - The absolute path to the file to open
1658 /// * `flags` - File open flags (read, write, create, etc.)
1659 ///
1660 /// # Returns
1661 ///
1662 /// * `Result<File>` - A file handle for performing I/O operations
1663 ///
1664 /// # Errors
1665 ///
1666 /// * `FileSystemError` - If the file cannot be opened or the path is invalid
1667 ///
1668 /// # Examples
1669 ///
1670 /// ```rust
1671 /// // Open an existing file for reading
1672 /// let file = vfs.open("/etc/config.txt", OpenFlags::RDONLY)?;
1673 ///
1674 /// // Create and open a new file for writing
1675 /// let file = vfs.open("/tmp/output.txt", OpenFlags::WRONLY | OpenFlags::CREATE)?;
1676 /// ```
1677 pub fn open(&self, path: &str, flags: u32) -> Result<File> {
1678 let handle = self.with_resolve_path(path, |fs, relative_path| fs.read().open(relative_path, flags));
1679 match handle {
1680 Ok(handle) => Ok(File { handle }),
1681 Err(e) => Err(e),
1682 }
1683 }
1684 /// Read directory entries
1685 ///
1686 /// This method reads all entries from a directory, returning a vector of
1687 /// directory entry structures containing file names, types, and metadata.
1688 ///
1689 /// # Arguments
1690 ///
1691 /// * `path` - The absolute path to the directory to read
1692 ///
1693 /// # Returns
1694 ///
1695 /// * `Result<Vec<DirectoryEntry>>` - Vector of directory entries
1696 ///
1697 /// # Errors
1698 ///
1699 /// * `FileSystemError` - If the directory cannot be read or doesn't exist
1700 ///
1701 /// # Examples
1702 ///
1703 /// ```rust
1704 /// // List files in a directory
1705 /// let entries = vfs.read_dir("/home/user")?;
1706 /// for entry in entries {
1707 /// println!("{}: {:?}", entry.name, entry.file_type);
1708 /// }
1709 /// ```
1710 pub fn read_dir(&self, path: &str) -> Result<Vec<DirectoryEntry>> {
1711 self.with_resolve_path(path, |fs, relative_path| fs.read().read_dir(relative_path))
1712 }
1713
1714 /// Create a file with specified type
1715 ///
1716 /// # Arguments
1717 ///
1718 /// * `path` - The path to the file to create
1719 /// * `file_type` - The type of file to create
1720 ///
1721 /// # Returns
1722 ///
1723 /// * `Result<()>` - Ok if the file was created successfully, Err otherwise
1724 pub fn create_file(&self, path: &str, file_type: FileType) -> Result<()> {
1725 self.with_resolve_path(path, |fs, relative_path| fs.read().create_file(relative_path, file_type))
1726 }
1727 /// Create a directory at the specified path
1728 ///
1729 /// This method creates a new directory in the filesystem, handling
1730 /// parent directory creation if necessary (depending on filesystem implementation).
1731 ///
1732 /// # Arguments
1733 ///
1734 /// * `path` - The absolute path where the directory should be created
1735 ///
1736 /// # Returns
1737 ///
1738 /// * `Result<()>` - Ok if the directory was created successfully
1739 ///
1740 /// # Errors
1741 ///
1742 /// * `FileSystemError` - If the directory cannot be created or already exists
1743 ///
1744 /// # Examples
1745 ///
1746 /// ```rust
1747 /// // Create a new directory
1748 /// vfs.create_dir("/tmp/new_directory")?;
1749 ///
1750 /// // Create nested directories (if supported by filesystem)
1751 /// vfs.create_dir("/tmp/path/to/directory")?;
1752 /// ```
1753 pub fn create_dir(&self, path: &str) -> Result<()> {
1754 self.with_resolve_path(path, |fs, relative_path| fs.read().create_dir(relative_path))
1755 }
1756 /// Remove a file or directory
1757 ///
1758 /// This method removes a file or directory from the filesystem.
1759 /// For directories, the behavior depends on the filesystem implementation
1760 /// (some may require the directory to be empty).
1761 ///
1762 /// # Arguments
1763 ///
1764 /// * `path` - The absolute path to the file or directory to remove
1765 ///
1766 /// # Returns
1767 ///
1768 /// * `Result<()>` - Ok if the item was removed successfully
1769 ///
1770 /// # Errors
1771 ///
1772 /// * `FileSystemError` - If the item cannot be removed or doesn't exist
1773 ///
1774 /// # Examples
1775 ///
1776 /// ```rust
1777 /// // Remove a file
1778 /// vfs.remove("/tmp/old_file.txt")?;
1779 ///
1780 /// // Remove a directory
1781 /// vfs.remove("/tmp/empty_directory")?;
1782 /// ```
1783 pub fn remove(&self, path: &str) -> Result<()> {
1784 self.with_resolve_path(path, |fs, relative_path| fs.read().remove(relative_path))
1785 }
1786 /// Get file or directory metadata
1787 ///
1788 /// This method retrieves metadata information about a file or directory,
1789 /// including file type, size, permissions, and timestamps.
1790 ///
1791 /// # Arguments
1792 ///
1793 /// * `path` - The absolute path to the file or directory
1794 ///
1795 /// # Returns
1796 ///
1797 /// * `Result<FileMetadata>` - Metadata structure containing file information
1798 ///
1799 /// # Errors
1800 ///
1801 /// * `FileSystemError` - If the file doesn't exist or metadata cannot be retrieved
1802 ///
1803 /// # Examples
1804 ///
1805 /// ```rust
1806 /// // Get file metadata
1807 /// let metadata = vfs.metadata("/etc/config.txt")?;
1808 /// println!("File size: {} bytes", metadata.size);
1809 /// println!("File type: {:?}", metadata.file_type);
1810 /// ```
1811 pub fn metadata(&self, path: &str) -> Result<FileMetadata> {
1812 self.with_resolve_path(path, |fs, relative_path| fs.read().metadata(relative_path))
1813 }
1814
1815 /// Create a regular file
1816 ///
1817 /// This method creates a new regular file at the specified path.
1818 /// It's a convenience method that creates a file with FileType::RegularFile.
1819 ///
1820 /// # Arguments
1821 ///
1822 /// * `path` - The absolute path where the file should be created
1823 ///
1824 /// # Returns
1825 ///
1826 /// * `Result<()>` - Ok if the file was created successfully
1827 ///
1828 /// # Errors
1829 ///
1830 /// * `FileSystemError` - If the file cannot be created or already exists
1831 ///
1832 /// # Examples
1833 ///
1834 /// ```rust
1835 /// // Create a new regular file
1836 /// vfs.create_regular_file("/tmp/new_file.txt")?;
1837 /// ```
1838 pub fn create_regular_file(&self, path: &str) -> Result<()> {
1839 self.with_resolve_path(path, |fs, relative_path| fs.read().create_file(relative_path, FileType::RegularFile))
1840 }
1841
1842 /// Create a character device file
1843 ///
1844 /// This method creates a character device file in the filesystem.
1845 /// Character devices provide unbuffered access to hardware devices
1846 /// and are accessed through character-based I/O operations.
1847 ///
1848 /// In Scarlet's device architecture, devices are identified by a unique
1849 /// device ID rather than traditional major/minor number pairs, providing
1850 /// a simplified and unified device identification system.
1851 ///
1852 /// # Arguments
1853 ///
1854 /// * `path` - The absolute path where the character device file should be created
1855 /// * `device_info` - Device information including unique device ID and type
1856 ///
1857 /// # Returns
1858 ///
1859 /// * `Result<()>` - Ok if the device file was created successfully
1860 ///
1861 /// # Errors
1862 ///
1863 /// * `FileSystemError` - If the device file cannot be created
1864 ///
1865 /// # Examples
1866 ///
1867 /// ```rust
1868 /// // Create a character device file for /dev/tty
1869 /// let device_info = DeviceFileInfo {
1870 /// device_id: 1,
1871 /// device_type: DeviceType::Char,
1872 /// };
1873 /// vfs.create_char_device("/dev/tty", device_info)?;
1874 /// ```
1875 pub fn create_char_device(&self, path: &str, device_info: DeviceFileInfo) -> Result<()> {
1876 self.create_file(path, FileType::CharDevice(device_info))
1877 }
1878
1879 /// Create a block device file
1880 ///
1881 /// This method creates a block device file in the filesystem.
1882 /// Block devices provide buffered access to hardware devices
1883 /// and are accessed through block-based I/O operations.
1884 ///
1885 /// In Scarlet's device architecture, devices are identified by a unique
1886 /// device ID rather than traditional major/minor number pairs, enabling
1887 /// simplified device management and registration.
1888 ///
1889 /// # Arguments
1890 ///
1891 /// * `path` - The absolute path where the block device file should be created
1892 /// * `device_info` - Device information including unique device ID and type
1893 ///
1894 /// # Returns
1895 ///
1896 /// * `Result<()>` - Ok if the device file was created successfully
1897 ///
1898 /// # Errors
1899 ///
1900 /// * `FileSystemError` - If the device file cannot be created
1901 ///
1902 /// # Examples
1903 ///
1904 /// ```rust
1905 /// // Create a block device file for /dev/sda
1906 /// let device_info = DeviceFileInfo {
1907 /// device_id: 8,
1908 /// device_type: DeviceType::Block,
1909 /// };
1910 /// vfs.create_block_device("/dev/sda", device_info)?;
1911 /// ```
1912 pub fn create_block_device(&self, path: &str, device_info: DeviceFileInfo) -> Result<()> {
1913 self.create_file(path, FileType::BlockDevice(device_info))
1914 }
1915
1916 /// Create a named pipe (FIFO)
1917 ///
1918 /// This method creates a named pipe in the filesystem, which provides
1919 /// inter-process communication through a FIFO queue mechanism.
1920 ///
1921 /// # Arguments
1922 ///
1923 /// * `path` - The absolute path where the pipe should be created
1924 ///
1925 /// # Returns
1926 ///
1927 /// * `Result<()>` - Ok if the pipe was created successfully
1928 ///
1929 /// # Errors
1930 ///
1931 /// * `FileSystemError` - If the pipe cannot be created
1932 ///
1933 /// # Examples
1934 ///
1935 /// ```rust
1936 /// // Create a named pipe for IPC
1937 /// vfs.create_pipe("/tmp/my_pipe")?;
1938 /// ```
1939 pub fn create_pipe(&self, path: &str) -> Result<()> {
1940 self.create_file(path, FileType::Pipe)
1941 }
1942
1943 /// Create a symbolic link
1944 ///
1945 /// This method creates a symbolic link (symlink) in the filesystem.
1946 /// A symbolic link is a file that contains a reference to another file or directory.
1947 ///
1948 /// # Arguments
1949 ///
1950 /// * `path` - The absolute path where the symbolic link should be created
1951 ///
1952 /// # Returns
1953 ///
1954 /// * `Result<()>` - Ok if the symbolic link was created successfully
1955 ///
1956 /// # Errors
1957 ///
1958 /// * `FileSystemError` - If the symbolic link cannot be created
1959 ///
1960 /// # Examples
1961 ///
1962 /// ```rust
1963 /// // Create a symbolic link
1964 /// vfs.create_symlink("/tmp/link_to_file")?;
1965 /// ```
1966 pub fn create_symlink(&self, path: &str) -> Result<()> {
1967 self.create_file(path, FileType::SymbolicLink)
1968 }
1969
1970 /// Create a socket file
1971 ///
1972 /// This method creates a Unix domain socket file in the filesystem.
1973 /// Socket files provide local inter-process communication endpoints.
1974 ///
1975 /// # Arguments
1976 ///
1977 /// * `path` - The absolute path where the socket file should be created
1978 ///
1979 /// # Returns
1980 ///
1981 /// * `Result<()>` - Ok if the socket file was created successfully
1982 ///
1983 /// # Errors
1984 ///
1985 /// * `FileSystemError` - If the socket file cannot be created
1986 ///
1987 /// # Examples
1988 ///
1989 /// ```rust
1990 /// // Create a Unix domain socket
1991 /// vfs.create_socket("/tmp/my_socket")?;
1992 /// ```
1993 pub fn create_socket(&self, path: &str) -> Result<()> {
1994 self.create_file(path, FileType::Socket)
1995 }
1996
1997 /// Create a device file of any type
1998 ///
1999 /// This is a convenience method that automatically determines the appropriate
2000 /// FileType based on the DeviceType in the DeviceFileInfo.
2001 ///
2002 /// # Arguments
2003 ///
2004 /// * `path` - The path to the device file to create
2005 /// * `device_info` - Information about the device including its type
2006 ///
2007 /// # Returns
2008 ///
2009 /// * `Result<()>` - Ok if the device file was created successfully, Err otherwise
2010 ///
2011 /// # Example
2012 ///
2013 /// ```rust
2014 /// use crate::device::{DeviceType, DeviceFileInfo};
2015 ///
2016 /// let device_info = DeviceFileInfo {
2017 /// device_id: 1,
2018 /// device_type: DeviceType::Char,
2019 /// };
2020 ///
2021 /// vfs_manager.create_device_file("/dev/tty0", device_info)?;
2022 /// ```
2023 pub fn create_device_file(&self, path: &str, device_info: DeviceFileInfo) -> Result<()> {
2024 match device_info.device_type {
2025 crate::device::DeviceType::Char => {
2026 self.create_file(path, FileType::CharDevice(device_info))
2027 },
2028 crate::device::DeviceType::Block => {
2029 self.create_file(path, FileType::BlockDevice(device_info))
2030 },
2031 _ => {
2032 Err(FileSystemError {
2033 kind: FileSystemErrorKind::NotSupported,
2034 message: "Unsupported device type for file creation".to_string(),
2035 })
2036 },
2037 }
2038 }
2039
2040 /// Get the number of mount points
2041 pub fn mount_count(&self) -> usize {
2042 self.mount_tree.read().len()
2043 }
2044
2045 /// Check if a specific mount point exists
2046 pub fn has_mount_point(&self, path: &str) -> bool {
2047 self.mount_tree.read().resolve(path).is_ok()
2048 }
2049
2050 /// List all mount points
2051 pub fn list_mount_points(&self) -> Vec<String> {
2052 self.mount_tree.read().list_all()
2053 }
2054}
2055
2056
2057/// Template for a basic block device-based file system implementation
2058///
2059/// `GenericFileSystem` provides a foundation for implementing filesystems
2060/// that operate on block devices. It handles common filesystem operations
2061/// including mounting, block I/O, and basic filesystem state management.
2062///
2063/// This is primarily used as a base for filesystem drivers and testing,
2064/// not intended for direct use in production filesystems.
2065///
2066/// # Architecture
2067///
2068/// - **Block Device Integration**: Direct interface with block devices for storage
2069/// - **Mount State Management**: Tracks filesystem mount status and mount points
2070/// - **Thread-Safe Block I/O**: Mutex-protected access to the underlying block device
2071/// - **Extensible Design**: Can be extended by specific filesystem implementations
2072///
2073/// # Usage
2074///
2075/// ```rust
2076/// // Create a generic filesystem on a block device
2077/// let block_device = Box::new(SomeBlockDevice::new());
2078/// let fs = GenericFileSystem::new("myfs", block_device, 512);
2079///
2080/// // Register with VFS
2081/// let fs_id = vfs_manager.register_fs(Box::new(fs));
2082/// vfs_manager.mount(fs_id, "/mnt")?;
2083/// ```
2084pub struct GenericFileSystem {
2085 /// Name of the filesystem instance
2086 name: &'static str,
2087 /// Block device for storage operations (mutex-protected for thread safety)
2088 #[allow(dead_code)]
2089 block_device: Mutex<Box<dyn BlockDevice>>,
2090 /// Block size for I/O operations
2091 #[allow(dead_code)]
2092 block_size: usize,
2093 /// Mount status of the filesystem
2094 mounted: bool,
2095 /// Current mount point path
2096 mount_point: String,
2097}
2098
2099impl GenericFileSystem {
2100 /// Create a new generic filesystem instance
2101 ///
2102 /// This method initializes a new filesystem instance that operates on a block device.
2103 /// The filesystem starts in an unmounted state and can be mounted later through
2104 /// the VFS layer.
2105 ///
2106 /// # Arguments
2107 ///
2108 /// * `name` - A static string identifier for this filesystem instance
2109 /// * `block_device` - The block device that will provide storage for this filesystem
2110 /// * `block_size` - The block size to use for I/O operations (typically 512, 1024, 4096)
2111 ///
2112 /// # Returns
2113 ///
2114 /// * `Self` - A new GenericFileSystem instance ready for registration
2115 ///
2116 /// # Examples
2117 ///
2118 /// ```rust
2119 /// let device = Box::new(SomeBlockDevice::new());
2120 /// let fs = GenericFileSystem::new("myfs", device, 512);
2121 /// ```
2122 pub fn new(name: &'static str, block_device: Box<dyn BlockDevice>, block_size: usize) -> Self {
2123 Self {
2124 name,
2125 block_device: Mutex::new(block_device),
2126 block_size,
2127 mounted: false,
2128 mount_point: String::new(),
2129 }
2130 }
2131
2132 /// Internal method for reading blocks from the underlying block device
2133 ///
2134 /// This method provides a low-level interface for reading data blocks
2135 /// from the filesystem's block device. It handles device locking and
2136 /// error conversion for filesystem operations.
2137 ///
2138 /// # Arguments
2139 ///
2140 /// * `block_idx` - The index of the block to read
2141 /// * `buffer` - Buffer to store the read data
2142 ///
2143 /// # Returns
2144 ///
2145 /// * `Result<()>` - Ok if the block was read successfully
2146 #[allow(dead_code)]
2147 fn read_block_internal(&self, block_idx: usize, buffer: &mut [u8]) -> Result<()> {
2148 let mut device = self.block_device.lock();
2149
2150 // Create the request
2151
2152 let request = Box::new(BlockIORequest {
2153 request_type: BlockIORequestType::Read,
2154 sector: block_idx,
2155 sector_count: 1,
2156 head: 0,
2157 cylinder: 0,
2158 buffer: vec![0; self.block_size],
2159 });
2160
2161 // Send the request
2162 device.enqueue_request(request);
2163
2164 // Get the result
2165 let results = device.process_requests();
2166
2167 if results.len() != 1 {
2168 return Err(FileSystemError {
2169 kind: FileSystemErrorKind::IoError,
2170 message: format!("Failed to process block request for block index {}", block_idx), // Updated
2171 });
2172 }
2173
2174 match &results[0].result {
2175 Ok(_) => {
2176 // Copy the data to the buffer
2177 let request = &results[0].request;
2178 buffer.copy_from_slice(&request.buffer);
2179 Ok(())
2180 },
2181 Err(msg) => Err(FileSystemError {
2182 kind: FileSystemErrorKind::IoError,
2183 message: msg.to_string(),
2184 }),
2185 }
2186 }
2187
2188 /// Internal method for writing blocks to the underlying block device
2189 ///
2190 /// This method provides a low-level interface for writing data blocks
2191 /// to the filesystem's block device. It handles device locking and
2192 /// error conversion for filesystem operations.
2193 ///
2194 /// # Arguments
2195 ///
2196 /// * `block_idx` - The index of the block to write
2197 /// * `buffer` - Buffer containing the data to write
2198 ///
2199 /// # Returns
2200 ///
2201 /// * `Result<()>` - Ok if the block was written successfully
2202 #[allow(dead_code)]
2203 fn write_block_internal(&self, block_idx: usize, buffer: &[u8]) -> Result<()> {
2204 let mut device = self.block_device.lock();
2205
2206 // Create the request
2207 let request = Box::new(BlockIORequest {
2208 request_type: BlockIORequestType::Write,
2209 sector: block_idx,
2210 sector_count: 1,
2211 head: 0,
2212 cylinder: 0,
2213 buffer: buffer.to_vec(),
2214 });
2215
2216 // Send the request
2217 device.enqueue_request(request);
2218
2219 // Get the result
2220 let results = device.process_requests();
2221
2222 if results.len() != 1 {
2223 return Err(FileSystemError {
2224 kind: FileSystemErrorKind::IoError,
2225 message: format!("Failed to process block write request for block index {}", block_idx), // Updated
2226 });
2227 }
2228
2229 match &results[0].result {
2230 Ok(_) => Ok(()),
2231 Err(msg) => Err(FileSystemError {
2232 kind: FileSystemErrorKind::IoError,
2233 message: msg.to_string(),
2234 }),
2235 }
2236 }
2237}
2238
2239impl FileSystem for GenericFileSystem {
2240 fn mount(&mut self, mount_point: &str) -> Result<()> {
2241 if self.mounted {
2242 return Err(FileSystemError {
2243 kind: FileSystemErrorKind::AlreadyExists,
2244 message: "File system already mounted".to_string(),
2245 });
2246 }
2247 self.mounted = true;
2248 self.mount_point = mount_point.to_string();
2249 Ok(())
2250 }
2251
2252 fn unmount(&mut self) -> Result<()> {
2253 if !self.mounted {
2254 return Err(FileSystemError {
2255 kind: FileSystemErrorKind::NotFound,
2256 message: "File system not mounted".to_string(),
2257 });
2258 }
2259 self.mounted = false;
2260 self.mount_point = String::new();
2261 Ok(())
2262 }
2263
2264 fn name(&self) -> &str {
2265 self.name
2266 }
2267}
2268
2269#[cfg(test)]
2270mod tests;
2271
2272#[cfg(test)]
2273pub mod testfs;