kernel/fs/mod.rs
1//! Virtual File System (VFS) Module - Version 2 Architecture
2//!
3//! This module provides a modern Virtual File System implementation based on VFS v2
4//! architecture, supporting per-task isolated filesystems, containerization, and
5//! advanced mount operations including bind mounts and overlay filesystems.
6//!
7//! # VFS v2 Architecture Overview
8//!
9//! The VFS v2 architecture provides a clean separation of concerns with three main
10//! components inspired by modern operating systems:
11//!
12//! ## Core Components
13//!
14//! - **VfsEntry**: Path hierarchy cache (similar to Linux dentry)
15//! - Represents "names" and "links" in the filesystem hierarchy
16//! - Provides fast path resolution with weak reference-based caching
17//! - Manages parent-child relationships in the VFS tree
18//!
19//! - **VfsNode**: File entity interface (similar to Linux inode/BSD vnode)
20//! - Abstract representation of files, directories, and special files
21//! - Provides metadata access and type information
22//! - Enables clean downcasting for filesystem-specific operations
23//!
24//! - **FileSystemOperations**: Unified driver API for filesystem implementations
25//! - Consolidated interface for all filesystem operations (lookup, create, etc.)
26//! - Clean separation between VFS core and filesystem drivers
27//! - Supports both simple and complex filesystem types
28//!
29//! ## Key Infrastructure
30//!
31//! - **VfsManager**: Main VFS management structure supporting isolation and sharing
32//! - **MountTree**: Hierarchical mount tree with support for bind mounts and overlays
33//! - **FileSystemDriverManager**: Global singleton for driver registration (VFS v1 compatibility)
34//! - **MountPoint**: Associates filesystem instances with mount paths and manages mount relationships
35//!
36//! ## VfsManager Distribution and Isolation
37//!
38//! - **Per-Task VfsManager**: Each task can have its own isolated `VfsManager` instance
39//! stored as `Option<Arc<VfsManager>>` in the task structure
40//! - **Shared Filesystems**: Multiple VfsManager instances can share underlying filesystem
41//! objects while maintaining independent mount points
42//! - **Global Fallback**: Tasks without their own VFS use the global VfsManager instance
43//!
44//! ## Advanced Mount Operations
45//!
46//! VFS v2 provides comprehensive mount functionality for flexible filesystem composition:
47//!
48//! ### Basic Filesystem Mounting
49//! ```rust
50//! let vfs = VfsManager::new();
51//!
52//! // Create and mount a tmpfs
53//! let tmpfs = TmpFS::new(1024 * 1024); // 1MB limit
54//! vfs.mount(tmpfs, "/tmp", 0)?;
55//!
56//! // Mount with specific options
57//! vfs.mount_with_options(filesystem, "/mnt/data", &mount_options)?;
58//! ```
59//!
60//! ### Bind Mount Operations
61//! ```rust
62//! // Basic bind mount - mount a directory at another location
63//! vfs.bind_mount("/source/dir", "/target/dir")?;
64//!
65//! // Cross-VFS bind mount for container isolation
66//! let host_vfs = Arc::new(host_vfs_manager);
67//! container_vfs.bind_mount_from(host_vfs, "/host/data", "/container/data")?;
68//! ```
69//!
70//! ### Overlay Filesystem Support
71//! ```rust
72//! // Create overlay combining multiple layers
73//! let overlay = OverlayFS::new(
74//! Some((upper_mount, upper_entry)), // Upper layer (writable)
75//! vec![(lower_mount, lower_entry)], // Lower layers (read-only)
76//! "system_overlay".to_string()
77//! )?;
78//! vfs.mount(overlay, "/merged", 0)?;
79//! ```
80//!
81//! ## Available Filesystem Types
82//!
83//! VFS v2 includes several built-in filesystem drivers:
84//!
85//! - **TmpFS**: Memory-based temporary filesystem with optional size limits
86//! - **CpioFS**: Read-only CPIO archive filesystem for initramfs
87//! - **OverlayFS**: Union/overlay filesystem combining multiple layers
88//! - **InitramFS**: Special handling for initial ramdisk mounting
89//!
90//! ## Usage Patterns
91//!
92//! ### Container Isolation with Namespaces
93//! ```rust
94//! // Create isolated VfsManager for container
95//! let container_vfs = VfsManager::new();
96//!
97//! // Mount container root filesystem
98//! let container_fs = TmpFS::new(512 * 1024 * 1024); // 512MB
99//! container_vfs.mount(container_fs, "/", 0)?;
100//!
101//! // Bind mount host resources selectively
102//! let host_vfs = get_global_vfs();
103//! container_vfs.bind_mount_from(&host_vfs, "/host/shared", "/shared")?;
104//!
105//! // Assign isolated namespace to task
106//! task.vfs = Some(Arc::new(container_vfs));
107//! ```
108//!
109//! ### Shared VFS Access Patterns
110//!
111//! VFS v2 supports multiple sharing patterns for different use cases:
112//!
113//! #### Full VFS Sharing via Arc
114//! ```rust
115//! // Share entire VfsManager instance including mount points
116//! let shared_vfs = Arc::new(vfs_manager);
117//! let task_vfs = Arc::clone(&shared_vfs);
118//!
119//! // All mount operations affect the shared mount tree
120//! shared_vfs.mount(tmpfs, "/tmp", 0)?; // Visible to all references
121//!
122//! // Useful for:
123//! // - Fork-like behavior where child inherits parent's filesystem view
124//! // - Thread-like sharing where all threads see the same mount points
125//! // - System-wide mount operations
126//! ```
127//!
128//! #### Selective Resource Sharing via Bind Mounts
129//! ```rust
130//! // Each container has isolated filesystem but shares specific directories
131//! let container1_vfs = VfsManager::new();
132//! let container2_vfs = VfsManager::new();
133//!
134//! // Both containers share a common data directory
135//! let host_vfs = get_global_vfs();
136//! container1_vfs.bind_mount_from(&host_vfs, "/host/shared", "/data")?;
137//! container2_vfs.bind_mount_from(&host_vfs, "/host/shared", "/data")?;
138//! ```
139//!
140//! ## System Call Interface
141//!
142//! VFS v2 provides system calls that operate within each task's
143//! VFS namespace:
144//!
145//! - File operations: `open()`, `read()`, `write()`, `close()`, `lseek()`
146//! - Directory operations: `mkdir()`, `readdir()`
147//! - Mount operations: `mount()`, `umount()`, `pivot_root()`
148//!
149//! ## Performance Characteristics
150//!
151//! VFS v2 is designed for performance with:
152//!
153//! - **Path Resolution Caching**: VfsEntry provides fast lookup of recently accessed paths
154//! - **Weak Reference Cleanup**: Automatic cleanup of expired cache entries
155//! - **Mount Boundary Optimization**: Efficient crossing of mount points during path resolution
156//! - **Lock Granularity**: Fine-grained locking to minimize contention
157//!
158//! ## Migration from VFS v1
159//!
160//! VFS v2 maintains compatibility with existing code while providing improved APIs.
161//! The old interfaces are deprecated but still functional for transition purposes.
162//!
163//! This architecture enables flexible deployment scenarios from simple shared filesystems
164//! to complete filesystem isolation with selective resource sharing for containerized
165//! applications, all while maintaining high performance and POSIX compatibility.
166
167pub mod vfs_v2;
168pub use vfs_v2::*;
169pub mod params;
170pub use params::*;
171pub use vfs_v2::manager::VfsManager;
172
173// Re-export syscalls for backward compatibility
174pub mod syscall {
175 pub use super::vfs_v2::syscall::*;
176}
177
178// Re-export file capability types for VFS compatibility
179pub use crate::object::capability::file::{SeekFrom, FileObject};
180
181use alloc::{boxed::Box, collections::BTreeMap, format, string::{String, ToString}, sync::Arc, vec::Vec};
182use crate::{device::{block::{BlockDevice}, DeviceType}, vm::vmem::MemoryArea};
183
184use spin::RwLock;
185use ::core::fmt;
186
187extern crate alloc;
188
189pub const MAX_PATH_LENGTH: usize = 1024;
190
191#[derive(Debug, Clone, Copy, PartialEq)]
192pub enum FileSystemErrorKind {
193 NotFound,
194 NoSpace,
195 PermissionDenied,
196 IoError,
197 InvalidData,
198 InvalidPath,
199 AlreadyExists,
200 NotADirectory,
201 NotAFile,
202 IsADirectory,
203 ReadOnly,
204 DeviceError,
205 NotSupported,
206 BrokenFileSystem,
207 Busy,
208 DirectoryNotEmpty,
209 InvalidOperation,
210 CrossDevice,
211 FileExists,
212}
213
214#[derive(Clone)]
215pub struct FileSystemError {
216 pub kind: FileSystemErrorKind,
217 pub message: String,
218}
219
220impl FileSystemError {
221 pub fn new(kind: FileSystemErrorKind, message: impl Into<String>) -> Self {
222 Self {
223 kind,
224 message: message.into(),
225 }
226 }
227}
228
229impl fmt::Debug for FileSystemError {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 write!(f, "FileSystemError {{ kind: {:?}, message: {} }}", self.kind, self.message)
232 }
233}
234
235/// Information about device files in the filesystem
236///
237/// Scarlet uses a simplified device identification system based on unique device IDs
238/// rather than the traditional Unix major/minor number pairs. This provides:
239///
240/// - **Simplified Management**: Single ID instead of major/minor pair reduces complexity
241/// - **Unified Namespace**: All devices share a common ID space regardless of type
242/// - **Dynamic Allocation**: Device IDs can be dynamically assigned without conflicts
243/// - **Type Safety**: Device type is explicitly specified alongside the ID
244///
245/// # Architecture
246///
247/// Each device in Scarlet is uniquely identified by:
248/// - `device_id`: A unique identifier within the system's device namespace
249/// - `device_type`: Explicit type classification (Character, Block, etc.)
250///
251/// This differs from traditional Unix systems where:
252/// - Major numbers identify device drivers
253/// - Minor numbers identify specific devices within a driver
254///
255/// # Examples
256///
257/// ```rust
258/// // Character device for terminal
259/// let tty_device = DeviceFileInfo {
260/// device_id: 1,
261/// device_type: DeviceType::Char,
262/// };
263///
264/// // Block device for storage
265/// let disk_device = DeviceFileInfo {
266/// device_id: 100,
267/// device_type: DeviceType::Block,
268/// };
269/// ```
270#[derive(Debug, Clone, Copy, PartialEq)]
271pub struct DeviceFileInfo {
272 pub device_id: usize,
273 pub device_type: DeviceType,
274}
275
276#[derive(Debug, Clone, PartialEq)]
277pub enum FileType {
278 RegularFile,
279 Directory,
280 CharDevice(DeviceFileInfo),
281 BlockDevice(DeviceFileInfo),
282 Pipe,
283 SymbolicLink(String),
284 Socket,
285 Unknown,
286}
287
288#[derive(Debug, Clone, Copy)]
289pub struct FilePermission {
290 pub read: bool,
291 pub write: bool,
292 pub execute: bool,
293}
294
295#[derive(Debug, Clone)]
296pub struct FileMetadata {
297 pub file_type: FileType,
298 pub size: usize,
299 pub permissions: FilePermission,
300 pub created_time: u64,
301 pub modified_time: u64,
302 pub accessed_time: u64,
303 /// Unique file identifier within the filesystem
304 /// Used for hard link management - multiple directory entries
305 /// can share the same file_id to point to the same file data
306 pub file_id: u64,
307 /// Number of hard links pointing to this file
308 /// File data is only deleted when link_count reaches zero
309 pub link_count: u32,
310}
311
312/// Structure representing a directory entry (internal representation)
313#[derive(Debug, Clone)]
314pub struct DirectoryEntryInternal {
315 pub name: String,
316 pub file_type: FileType,
317 pub size: usize,
318 /// Unique file identifier - same as the file_id in FileMetadata
319 /// Multiple directory entries with the same file_id represent hard links
320 pub file_id: u64,
321 pub metadata: Option<FileMetadata>,
322}
323
324/// Binary representation of directory entry for system call interface
325/// This structure has a fixed layout for efficient copying between kernel and user space
326#[repr(C)]
327#[derive(Debug, Clone, Copy)]
328pub struct DirectoryEntry {
329 /// Unique file identifier
330 pub file_id: u64,
331 /// File size in bytes
332 pub size: u64,
333 /// File type as a byte value
334 pub file_type: u8,
335 /// Length of the file name
336 pub name_len: u8,
337 /// Reserved bytes for alignment
338 pub _reserved: [u8; 6],
339 /// File name (null-terminated, max 255 characters)
340 pub name: [u8; 256],
341}
342
343impl DirectoryEntry {
344 /// Create a DirectoryEntry from internal representation
345 pub fn from_internal(internal: &DirectoryEntryInternal) -> Self {
346 let file_type_byte = match internal.file_type {
347 FileType::RegularFile => 0u8,
348 FileType::Directory => 1u8,
349 FileType::SymbolicLink(_) => 2u8,
350 FileType::CharDevice(_) => 3u8,
351 FileType::BlockDevice(_) => 4u8,
352 FileType::Pipe => 5u8,
353 FileType::Socket => 6u8,
354 FileType::Unknown => 7u8,
355 };
356
357 let name_bytes = internal.name.as_bytes();
358 let mut name_array = [0u8; 256];
359 let copy_len = ::core::cmp::min(name_bytes.len(), 255); // Reserve 1 byte for null terminator
360 name_array[..copy_len].copy_from_slice(&name_bytes[..copy_len]);
361 name_array[copy_len] = 0; // Null terminator
362
363 Self {
364 file_id: internal.file_id,
365 size: internal.size as u64,
366 file_type: file_type_byte,
367 name_len: copy_len as u8,
368 _reserved: [0; 6],
369 name: name_array,
370 }
371 }
372
373 /// Get the name as a string
374 pub fn name_str(&self) -> Result<&str, ::core::str::Utf8Error> {
375 let name_bytes = &self.name[..self.name_len as usize];
376 ::core::str::from_utf8(name_bytes)
377 }
378
379 /// Get the actual size of this entry
380 pub fn entry_size(&self) -> usize {
381 // Fixed size of the entry structure
382 ::core::mem::size_of::<Self>() as usize
383 }
384
385 /// Parse a DirectoryEntry from raw bytes
386 pub fn parse(data: &[u8]) -> Option<Self> {
387 if data.len() < ::core::mem::size_of::<Self>() {
388 return None;
389 }
390
391 // Safety: We've checked the size above
392 let entry = unsafe {
393 ::core::ptr::read(data.as_ptr() as *const Self)
394 };
395
396 // Basic validation
397 if entry.name_len as usize > 255 {
398 return None;
399 }
400
401 Some(entry)
402 }
403}
404
405/// Structure representing a directory
406pub struct Directory {
407 pub path: String,
408}
409
410impl Directory {
411 pub fn open(path: String) -> Self {
412 Self {
413 path,
414 }
415 }
416}
417
418/// Enum defining the type of file system
419#[derive(Debug, Clone, Copy, PartialEq)]
420pub enum FileSystemType {
421 /// File system that operates on block devices (disk-based)
422 Block,
423 /// File system that operates on memory regions (RAM-based)
424 Memory,
425 /// File system that can operate on both block devices and memory regions
426 Hybrid,
427 /// Special or virtual file systems (e.g., procfs, sysfs)
428 Virtual,
429 /// Device file system (e.g., /dev)
430 Device,
431}
432
433/// Trait for file system drivers
434///
435/// This trait is used to create file systems from block devices or memory areas.
436/// It is not intended to be used directly by the VFS manager.
437/// Instead, the VFS manager will use the appropriate creation method based on the source.
438pub trait FileSystemDriver: Send + Sync {
439 /// Get the name of the file system driver
440 fn name(&self) -> &'static str;
441
442 /// Get the type of the file system
443 fn filesystem_type(&self) -> FileSystemType;
444
445 /// Create a file system from a block device
446 ///
447 /// When implementing this method, ensure that the file system driver can handle block device-based creation.
448 /// If the driver does not support this, return an appropriate error.
449 ///
450 /// # Arguments
451 ///
452 /// * `_block_device` - The block device to use for creating the file system
453 /// * `_block_size` - The block size of the device
454 ///
455 fn create_from_block(&self, _block_device: Box<dyn BlockDevice>, _block_size: usize) -> Result<Arc<dyn crate::fs::vfs_v2::core::FileSystemOperations>, FileSystemError> {
456 if self.filesystem_type() == FileSystemType::Memory || self.filesystem_type() == FileSystemType::Virtual {
457 return Err(FileSystemError {
458 kind: FileSystemErrorKind::NotSupported,
459 message: "This file system driver does not support block device-based creation".to_string(),
460 });
461 }
462
463 Err(FileSystemError {
464 kind: FileSystemErrorKind::NotSupported,
465 message: "create_from_block() not implemented for this file system driver".to_string(),
466 })
467 }
468
469 /// Create a file system from a memory area
470 ///
471 /// When implementing this method, ensure that the file system driver can handle memory-based creation.
472 /// If the driver does not support this, return an appropriate error.
473 ///
474 /// # Notes
475 ///
476 /// File system drivers must validate the provided MemoryArea to ensure it is valid.
477 /// If the MemoryArea is invalid, the driver should return an appropriate error.
478 ///
479 /// # Arguments
480 ///
481 /// * `_memory_area` - The memory area to use for creating the file system
482 ///
483 /// # Returns
484 ///
485 /// * `Result<Arc<dyn FileSystemOperations>, FileSystemError>` - The created file system
486 ///
487 fn create_from_memory(&self, _memory_area: &crate::vm::vmem::MemoryArea) -> Result<Arc<dyn crate::fs::vfs_v2::core::FileSystemOperations>, FileSystemError> {
488 if self.filesystem_type() == FileSystemType::Block {
489 return Err(FileSystemError {
490 kind: FileSystemErrorKind::NotSupported,
491 message: "This file system driver does not support memory-based creation".to_string(),
492 });
493 }
494
495 Err(FileSystemError {
496 kind: FileSystemErrorKind::NotSupported,
497 message: "create_from_memory() not implemented for this file system driver".to_string(),
498 })
499 }
500
501 fn create(&self) -> Result<Arc<dyn crate::fs::vfs_v2::core::FileSystemOperations>, FileSystemError> {
502 // Default implementation that can be overridden by specific drivers
503 // This is a convenience method for drivers that do not need to handle block or memory creation
504 Err(FileSystemError {
505 kind: FileSystemErrorKind::NotSupported,
506 message: "create() not implemented for this file system driver".to_string(),
507 })
508 }
509
510 /// Create a file system with option string
511 ///
512 /// This method creates a filesystem instance based on an option string, which
513 /// is typically passed from the mount() system call. The option string format
514 /// is filesystem-specific and should be parsed by the individual driver.
515 ///
516 /// # Arguments
517 ///
518 /// * `options` - Option string containing filesystem-specific parameters
519 ///
520 /// # Returns
521 ///
522 /// * `Result<Arc<dyn FileSystemOperations>, FileSystemError>` - The created file system
523 ///
524 /// # Note
525 ///
526 /// This method allows the filesystem driver to handle its own option parsing,
527 /// keeping the mount syscall generic and delegating filesystem-specific logic
528 /// to the appropriate driver.
529 fn create_from_option_string(&self, options: &str) -> Result<Arc<dyn crate::fs::vfs_v2::core::FileSystemOperations>, FileSystemError> {
530 let _ = options; // Suppress unused parameter warning
531 // Default implementation falls back to create()
532 self.create()
533 }
534
535 /// Create a file system with structured parameters
536 ///
537 /// This method creates file systems using type-safe structured parameters
538 /// that implement the FileSystemParams trait. This approach replaces the
539 /// old BTreeMap<String, String> approach with better type safety.
540 ///
541 /// # Arguments
542 ///
543 /// * `params` - Structured parameter implementing FileSystemParams
544 ///
545 /// # Returns
546 ///
547 /// * `Result<Arc<dyn FileSystemOperations>, FileSystemError>` - The created file system
548 ///
549 /// # Note
550 ///
551 /// This method uses dynamic dispatch for parameter handling to support
552 /// future dynamic filesystem module loading while maintaining type safety.
553 ///
554 fn create_from_params(&self, params: &dyn crate::fs::params::FileSystemParams) -> Result<Arc<dyn crate::fs::vfs_v2::core::FileSystemOperations>, FileSystemError> {
555 // Default implementation falls back to create()
556 let _ = params; // Suppress unused parameter warning
557 self.create()
558 }
559}
560
561/// Singleton for global access to the FileSystemDriverManager
562static mut FS_DRIVER_MANAGER: Option<FileSystemDriverManager> = None;
563
564/// Global filesystem driver manager singleton
565///
566/// Provides global access to the FileSystemDriverManager instance.
567/// This function ensures thread-safe initialization of the singleton
568/// and returns a mutable reference for driver registration and filesystem creation.
569///
570/// # Returns
571///
572/// Mutable reference to the global FileSystemDriverManager instance
573///
574/// # Thread Safety
575///
576/// This function is marked as unsafe due to static mutable access, but
577/// the returned manager uses internal synchronization for thread safety.
578#[allow(static_mut_refs)]
579pub fn get_fs_driver_manager() -> &'static mut FileSystemDriverManager {
580 unsafe {
581 if FS_DRIVER_MANAGER.is_none() {
582 FS_DRIVER_MANAGER = Some(FileSystemDriverManager::new());
583 }
584 FS_DRIVER_MANAGER.as_mut().unwrap()
585 }
586}
587
588/// Global filesystem driver manager singleton
589///
590/// Provides global access to the FileSystemDriverManager instance.
591/// This function ensures thread-safe initialization of the singleton
592/// and returns a mutable reference for driver registration and filesystem creation.
593///
594/// # Returns
595///
596/// Mutable reference to the global FileSystemDriverManager instance
597///
598/// # Thread Safety
599///
600/// This function is marked as unsafe due to static mutable access, but
601/// Filesystem driver manager for centralized driver registration and management
602///
603/// The FileSystemDriverManager provides a centralized system for managing filesystem
604/// drivers in the kernel. It separates driver management responsibilities from individual
605/// VfsManager instances, enabling shared driver access across multiple VFS namespaces.
606///
607/// # Features
608///
609/// - **Driver Registration**: Register filesystem drivers for system-wide use
610/// - **Type-Safe Creation**: Create filesystems with structured parameter validation
611/// - **Multi-Source Support**: Support for block device, memory, and virtual filesystems
612/// - **Thread Safety**: All operations are thread-safe using RwLock protection
613/// - **Future Extensibility**: Designed for dynamic filesystem module loading
614///
615/// # Architecture
616///
617/// The manager maintains a registry of drivers identified by name, with each driver
618/// implementing the FileSystemDriver trait. Drivers specify their supported source
619/// types (block, memory, virtual) and provide creation methods for each type.
620///
621/// # Usage
622///
623/// ```rust
624/// // Register a filesystem driver
625/// let manager = get_fs_driver_manager();
626/// manager.register_driver(Box::new(MyFSDriver));
627///
628/// // Create filesystem from block device
629/// let device = get_block_device();
630/// let fs = manager.create_from_block("myfs", device, 512)?;
631///
632/// // Create filesystem with structured parameters
633/// let params = MyFSParams::new();
634/// let fs = manager.create_with_params("myfs", ¶ms)?;
635/// ```
636pub struct FileSystemDriverManager {
637 /// Registered file system drivers indexed by name
638 drivers: RwLock<BTreeMap<String, Box<dyn FileSystemDriver>>>,
639}
640
641impl FileSystemDriverManager {
642 /// Create a new filesystem driver manager
643 ///
644 /// Initializes an empty driver manager with no registered drivers.
645 /// Drivers must be registered using register_driver() before they
646 /// can be used to create filesystems.
647 ///
648 /// # Returns
649 ///
650 /// A new FileSystemDriverManager instance
651 pub fn new() -> Self {
652 Self {
653 drivers: RwLock::new(BTreeMap::new()),
654 }
655 }
656
657 /// Register a filesystem driver
658 ///
659 /// Adds a new filesystem driver to the manager's registry. The driver
660 /// will be indexed by its name() method return value. If a driver with
661 /// the same name already exists, it will be replaced.
662 ///
663 /// # Arguments
664 ///
665 /// * `driver` - The filesystem driver to register, implementing FileSystemDriver trait
666 ///
667 /// # Example
668 ///
669 /// ```rust
670 /// let manager = get_fs_driver_manager();
671 /// manager.register_driver(Box::new(MyFileSystemDriver));
672 /// ```
673 pub fn register_driver(&mut self, driver: Box<dyn FileSystemDriver>) {
674 self.drivers.write().insert(driver.name().to_string(), driver);
675 }
676
677 /// Get a list of registered driver names
678 ///
679 /// Returns the names of all currently registered filesystem drivers.
680 /// This is useful for debugging and system introspection.
681 ///
682 /// # Returns
683 ///
684 /// Vector of driver names in alphabetical order
685 pub fn list_drivers(&self) -> Vec<String> {
686 self.drivers.read().keys().cloned().collect()
687 }
688
689 /// Check if a driver with the specified name is registered
690 ///
691 /// Performs a quick lookup to determine if a named driver exists
692 /// in the registry without attempting to use it.
693 ///
694 /// # Arguments
695 ///
696 /// * `driver_name` - The name of the driver to check for
697 ///
698 /// # Returns
699 ///
700 /// `true` if the driver is registered, `false` otherwise
701 pub fn has_driver(&self, driver_name: &str) -> bool {
702 self.drivers.read().contains_key(driver_name)
703 }
704
705 /// Create a filesystem from a block device
706 ///
707 /// Creates a new filesystem instance using the specified driver and block device.
708 /// The driver must support block device-based filesystem creation. This method
709 /// validates that the driver supports block devices before attempting creation.
710 ///
711 /// # Arguments
712 ///
713 /// * `driver_name` - The name of the registered driver to use
714 /// * `block_device` - The block device that will store the filesystem data
715 /// * `block_size` - The block size for I/O operations (typically 512, 1024, or 4096 bytes)
716 ///
717 /// # Returns
718 ///
719 /// * `Ok(Arc<dyn FileSystemOperations>)` - Successfully created filesystem instance
720 /// * `Err(FileSystemError)` - If driver not found, doesn't support block devices, or creation fails
721 ///
722 /// # Errors
723 ///
724 /// - `NotFound` - Driver with the specified name is not registered
725 /// - `NotSupported` - Driver doesn't support block device-based filesystems
726 /// - Driver-specific errors during filesystem creation
727 ///
728 /// # Example
729 ///
730 /// ```rust
731 /// let device = get_block_device();
732 /// let fs = manager.create_from_block("ext4", device, 4096)?;
733 /// ```
734 pub fn create_from_block(
735 &self,
736 driver_name: &str,
737 block_device: Box<dyn BlockDevice>,
738 block_size: usize,
739 ) -> Result<Arc<dyn crate::fs::vfs_v2::core::FileSystemOperations>, FileSystemError> {
740 let binding = self.drivers.read();
741 let driver = binding.get(driver_name).ok_or(FileSystemError {
742 kind: FileSystemErrorKind::NotFound,
743 message: format!("File system driver '{}' not found", driver_name),
744 })?;
745
746 if driver.filesystem_type() == FileSystemType::Memory || driver.filesystem_type() == FileSystemType::Virtual {
747 return Err(FileSystemError {
748 kind: FileSystemErrorKind::NotSupported,
749 message: format!("File system driver '{}' does not support block devices", driver_name),
750 });
751 }
752
753 driver.create_from_block(block_device, block_size)
754 }
755
756 /// Create a filesystem from a memory area
757 ///
758 /// Creates a new filesystem instance using the specified driver and memory region.
759 /// This is typically used for RAM-based filesystems like tmpfs or for mounting
760 /// filesystem images stored in memory (e.g., initramfs).
761 ///
762 /// # Arguments
763 ///
764 /// * `driver_name` - The name of the registered driver to use
765 /// * `memory_area` - The memory region containing filesystem data or available for use
766 ///
767 /// # Returns
768 ///
769 /// * `Ok(Arc<dyn FileSystemOperations>)` - Successfully created filesystem instance
770 /// * `Err(FileSystemError)` - If driver not found, doesn't support memory-based creation, or creation fails
771 ///
772 /// # Errors
773 ///
774 /// - `NotFound` - Driver with the specified name is not registered
775 /// - `NotSupported` - Driver only supports block device-based filesystems
776 /// - Driver-specific errors during filesystem creation
777 ///
778 /// # Example
779 ///
780 /// ```rust
781 /// let memory_area = MemoryArea::new(addr, size);
782 /// let fs = manager.create_from_memory("cpiofs", &memory_area)?;
783 /// ```
784 pub fn create_from_memory(
785 &self,
786 driver_name: &str,
787 memory_area: &MemoryArea,
788 ) -> Result<Arc<dyn crate::fs::vfs_v2::core::FileSystemOperations>, FileSystemError> {
789 let binding = self.drivers.read();
790 let driver = binding.get(driver_name).ok_or(FileSystemError {
791 kind: FileSystemErrorKind::NotFound,
792 message: format!("File system driver '{}' not found", driver_name),
793 })?;
794
795 if driver.filesystem_type() == FileSystemType::Block {
796 return Err(FileSystemError {
797 kind: FileSystemErrorKind::NotSupported,
798 message: format!("File system driver '{}' does not support memory-based filesystems", driver_name),
799 });
800 }
801
802 driver.create_from_memory(memory_area)
803 }
804
805 /// Create a filesystem with structured parameters
806 ///
807 /// This method creates filesystems using type-safe structured parameters that
808 /// implement the FileSystemParams trait. This approach replaces the old BTreeMap<String, String>
809 /// configuration method with better type safety and validation.
810 ///
811 /// The method uses dynamic dispatch to handle different parameter types, enabling
812 /// future dynamic filesystem module loading while maintaining type safety at the
813 /// driver level.
814 ///
815 /// # Arguments
816 ///
817 /// * `driver_name` - The name of the registered driver to use
818 /// * `params` - Parameter structure implementing FileSystemParams
819 ///
820 /// # Returns
821 ///
822 /// * `Ok(Arc<dyn FileSystemOperations>)` - Successfully created filesystem instance
823 /// * `Err(FileSystemError)` - If driver not found, parameters invalid, or creation fails
824 ///
825 /// # Errors
826 ///
827 /// - `NotFound` - Driver with the specified name is not registered
828 /// - `NotSupported` - Driver doesn't support the provided parameter type
829 /// - Driver-specific parameter validation errors
830 ///
831 /// # Example
832 ///
833 /// ```rust
834 /// use crate::fs::params::TmpFSParams;
835 ///
836 /// let params = TmpFSParams::new(1048576, 0); // 1MB limit
837 /// let fs = manager.create_with_params("tmpfs", ¶ms)?;
838 /// ```
839 ///
840 /// # Note
841 ///
842 /// This method uses dynamic dispatch for parameter handling to support
843 /// future dynamic filesystem module loading while maintaining type safety.
844 pub fn create_from_params(
845 &self,
846 driver_name: &str,
847 params: &dyn crate::fs::params::FileSystemParams
848 ) -> Result<Arc<dyn crate::fs::vfs_v2::core::FileSystemOperations>, FileSystemError> {
849 let binding = self.drivers.read();
850 let driver = binding.get(driver_name)
851 .ok_or_else(|| FileSystemError {
852 kind: FileSystemErrorKind::NotFound,
853 message: format!("File system driver '{}' not found", driver_name),
854 })?;
855 driver.create_from_params(params)
856 }
857
858 /// Create a filesystem from option string
859 ///
860 /// Creates a new filesystem instance using the specified driver and option string.
861 /// This method delegates option parsing to the individual filesystem driver,
862 /// allowing each driver to handle its own specific option format.
863 ///
864 /// # Arguments
865 ///
866 /// * `driver_name` - The name of the registered driver to use
867 /// * `options` - Option string containing filesystem-specific parameters
868 ///
869 /// # Returns
870 ///
871 /// * `Ok(Arc<dyn FileSystemOperations>)` - Successfully created filesystem instance
872 /// * `Err(FileSystemError)` - If driver not found or creation fails
873 ///
874 /// # Errors
875 ///
876 /// - `NotFound` - Driver with the specified name is not registered
877 /// - Driver-specific option parsing or creation errors
878 ///
879 /// # Example
880 ///
881 /// ```rust
882 /// let fs = manager.create_from_option_string("tmpfs", "size=64M")?;
883 /// let fs = manager.create_from_option_string("overlay", "upperdir=/upper,lowerdir=/lower1:/lower2")?;
884 /// ```
885 pub fn create_from_option_string(
886 &self,
887 driver_name: &str,
888 options: &str,
889 ) -> Result<Arc<dyn crate::fs::vfs_v2::core::FileSystemOperations>, FileSystemError> {
890 let binding = self.drivers.read();
891 let driver = binding.get(driver_name)
892 .ok_or_else(|| FileSystemError {
893 kind: FileSystemErrorKind::NotFound,
894 message: format!("File system driver '{}' not found", driver_name),
895 })?;
896
897 driver.create_from_option_string(options)
898 }
899
900 /// Get filesystem driver information by name
901 ///
902 /// Retrieves the filesystem type supported by a registered driver.
903 /// This is useful for validating driver capabilities before attempting
904 /// to create filesystems.
905 ///
906 /// # Arguments
907 ///
908 /// * `driver_name` - The name of the driver to query
909 ///
910 /// # Returns
911 ///
912 /// * `Some(FileSystemType)` - The filesystem type if driver exists
913 /// * `None` - If no driver with the specified name is registered
914 ///
915 /// # Example
916 ///
917 /// ```rust
918 /// if let Some(fs_type) = manager.get_driver_type("tmpfs") {
919 /// match fs_type {
920 /// FileSystemType::Virtual => println!("TmpFS is a virtual filesystem"),
921 /// _ => println!("Unexpected filesystem type"),
922 /// }
923 /// }
924 /// ```
925 pub fn get_driver_type(&self, driver_name: &str) -> Option<FileSystemType> {
926 self.drivers.read().get(driver_name).map(|driver| driver.filesystem_type())
927 }
928}
929
930impl Default for FileSystemDriverManager {
931 fn default() -> Self {
932 Self::new()
933 }
934}