kernel/fs/
mount_tree.rs

1//! Mount Tree Implementation
2//!
3//! This module provides a Trie-based mount point management system
4//! for efficient path resolution and hierarchical mount point organization.
5
6use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
7use super::*;
8
9/// Mount point management using Trie structure
10/// 
11/// MountTree provides efficient hierarchical mount point management using a Trie
12/// data structure. This enables O(log k) path resolution where k is the path depth,
13/// making filesystem operations scale well with complex mount hierarchies.
14/// 
15/// # Features
16/// 
17/// - **Efficient Path Resolution**: Trie-based lookup for fast mount point discovery
18/// - **Bind Mount Support**: Advanced bind mounting with cross-VFS capability
19/// - **Security**: Enhanced path normalization preventing directory traversal attacks
20/// - **Caching**: Optional path caching for frequently accessed mount points
21/// - **Thread Safety**: All operations are thread-safe using RwLock protection
22/// 
23/// # Architecture
24/// 
25/// The mount tree consists of:
26/// - Root node representing the filesystem root "/"
27/// - Internal nodes for directory components
28/// - Leaf nodes containing actual mount points
29/// - Path cache for performance optimization
30/// 
31/// # Usage
32/// 
33/// ```rust
34/// let mut mount_tree = MountTree::new();
35/// 
36/// // Mount a filesystem
37/// mount_tree.mount("/mnt/data", mount_point)?;
38/// 
39/// // Resolve a path to its mount point
40/// let (mount_node, relative_path) = mount_tree.resolve("/mnt/data/file.txt")?;
41/// ```
42#[derive(Clone)]
43pub struct MountTree {
44    root: Arc<MountNode>,
45    /// Cache for fast lookup
46    path_cache: BTreeMap<String, Arc<MountPoint>>,
47}
48
49/// Mount tree node representing a single component in the filesystem hierarchy
50/// 
51/// Each MountNode represents a directory component in the filesystem path.
52/// Nodes can optionally contain mount points and have child nodes for
53/// subdirectories. The tree structure enables efficient path traversal
54/// and mount point resolution.
55/// 
56/// # Thread Safety
57/// 
58/// All fields are protected by RwLock to ensure thread-safe access in
59/// a multi-threaded kernel environment.
60pub struct MountNode {
61    /// Path component
62    #[allow(dead_code)]
63    pub component: RwLock<String>,
64    /// Mount information if this node is a mount point
65    mount_point: RwLock<Option<Arc<MountPoint>>>,
66    /// Child nodes
67    children: RwLock<BTreeMap<String, Arc<MountNode>>>,
68}
69
70impl MountNode {
71    /// Create a new mount node with the specified path component
72    /// 
73    /// # Arguments
74    /// 
75    /// * `component` - The path component name for this node
76    /// 
77    /// # Returns
78    /// 
79    /// A new MountNode instance with the given component name
80    fn new(component: String) -> Self {
81        Self {
82            component: RwLock::new(component),
83            mount_point: RwLock::new(None),
84            children: RwLock::new(BTreeMap::new()),
85        }
86    }
87
88    /// Get the mount point associated with this node
89    /// 
90    /// # Returns
91    /// * `Ok(Arc<MountPoint>)` - The mount point if it exists.
92    /// * `Err(FileSystemError)` - If no mount point is found.
93    /// 
94    pub fn get_mount_point(&self) -> Result<Arc<MountPoint>> {
95        let mount_guard = self.mount_point.read();
96        if let Some(mount_point) = &*mount_guard {
97            Ok(mount_point.clone())
98        } else {
99            Err(FileSystemError {
100                kind: FileSystemErrorKind::NotFound,
101                message: "No mount point found".to_string(),
102            })
103        }
104    }
105
106    /// Resolve path within this mount node and its children (transparent resolution)
107    /// 
108    /// This method resolves the given path components starting from this node.
109    /// For bind mounts, it recursively resolves through the source mount tree
110    /// to find the deepest actual mount that handles the requested path.
111    /// 
112    /// This is an internal method that operates on Arc<MountNode>
113    /// 
114    /// # Arguments
115    /// * `self_arc` - Arc reference to this node
116    /// * `components` - The path components to resolve.
117    /// * `depth` - Current recursion depth to prevent infinite loops.
118    /// 
119    /// # Returns
120    /// * `Ok(Some((Arc<MountNode>, String)))` - A tuple containing the resolved mount node and the relative path.
121    /// * `Ok(None)` - If this node is the final target (self-resolution).
122    /// * `Err(FileSystemError)` - If the path is invalid or no mount point is found.
123    /// 
124    fn resolve_internal(self_arc: Arc<MountNode>, components: &[String], depth: usize) -> Result<Option<(Arc<MountNode>, String)>> {
125        // Prevent infinite recursion in bind mount chains
126        if depth > 32 {
127            return Err(FileSystemError {
128                kind: FileSystemErrorKind::NotSupported,
129                message: "Too many bind mount redirections".to_string(),
130            });
131        }
132
133        // crate::println!("Resolving internal mount point for path: {}, depth: {}", components.join("/"), depth);
134
135        // If no components left, check if this node is a mount point
136        if components.is_empty() {
137            // crate::println!("No components left, checking if this node is a mount point");
138            let mount_guard = self_arc.mount_point.read();
139            if mount_guard.is_some() {
140                // This node is a mount point and is the target
141                return Ok(None);
142            } else {
143                // No mount point at this location
144                return Err(FileSystemError {
145                    kind: FileSystemErrorKind::NotFound,
146                    message: "No mount point found".to_string(),
147                });
148            }
149        }
150
151        // Start with self
152        let mut current_node = self_arc.clone();
153        let mut best_match_node: Option<Arc<MountNode>> = None;
154        let mut match_depth = 0;
155
156        // Check if current node is a mount point
157        {
158            let mount_guard = current_node.mount_point.read();
159            if mount_guard.is_some() {
160                best_match_node = Some(current_node.clone());
161                match_depth = 0;
162
163                // crate::println!("Current node is a mount point: {}", current_node.component.read().as_str());
164            }
165        }
166        
167        // Traverse components to find the deepest mount point
168        for (depth_idx, component) in components.iter().enumerate() {
169            // Move to next node
170            let next_node = {
171                let children_guard = current_node.children.read();
172                if let Some(child) = children_guard.get(component) {
173                    child.clone()
174                } else {
175                    break;
176                }
177            };
178            current_node = next_node;
179            
180            // Check if the moved-to node is a mount point
181            {
182                let mount_guard = current_node.mount_point.read();
183                if mount_guard.is_some() {
184                    best_match_node = Some(current_node.clone());
185                    match_depth = depth_idx + 1; // +1 for depth after movement
186                }
187            }
188        }
189        
190        let resolved_node = best_match_node.ok_or(FileSystemError {
191            kind: FileSystemErrorKind::NotFound,
192            message: "No mount point found in this subtree".to_string(),
193        })?;
194        
195        // Build relative path
196        let relative_components = &components[match_depth..];
197        let relative_path = if relative_components.is_empty() {
198            "/".to_string()
199        } else {
200            format!("/{}", relative_components.join("/"))
201        };
202
203        // Check if this is a bind mount and needs further resolution
204        let mount_point = resolved_node.get_mount_point()?;
205        match &mount_point.mount_type {
206            MountType::Bind { source_mount_node, source_relative_path, .. } => {
207                // Construct the full source path
208                let full_source_path = match (relative_path.as_str(), source_relative_path.as_str()) {
209                    ("/", _) => source_relative_path.clone(),
210                    (_, "/") => relative_path.clone(),
211                    (rel, src) => {
212                        let src_trimmed = src.trim_end_matches('/');
213                        let rel_trimmed = rel.trim_start_matches('/');
214                        format!("{}/{}", src_trimmed, rel_trimmed)
215                    }
216                };
217
218                // Split the full source path into components
219                let source_components: Vec<String> = if full_source_path == "/" {
220                    Vec::new()
221                } else {
222                    full_source_path.trim_start_matches('/')
223                        .split('/')
224                        .filter(|s| !s.is_empty())
225                        .map(|s| s.to_string())
226                        .collect()
227                };
228                
229                // Recursively resolve through the source mount node
230                let result = MountNode::resolve_internal(source_mount_node.clone(), &source_components, depth + 1)?;
231                let (final_node, final_relative_path) = match result {
232                    Some((node, path)) => (node, path),
233                    None => {
234                        // If None, use the source mount node itself
235                        (source_mount_node.clone(), "/".to_string())
236                    }
237                };
238                
239                // Verify that the final node is not another bind mount to the same location
240                // to prevent infinite loops
241                let final_mount_point = final_node.get_mount_point()?;
242                match &final_mount_point.mount_type {
243                    MountType::Bind { .. } => {
244                        // If we still have a bind mount, check if it's different from where we started
245                        if Arc::ptr_eq(&final_node, &resolved_node) {
246                            return Err(FileSystemError {
247                                kind: FileSystemErrorKind::NotSupported,
248                                message: "Circular bind mount detected".to_string(),
249                            });
250                        }
251                    }
252                    _ => {}
253                }
254                
255                Ok(Some((final_node, final_relative_path)))
256            }
257            _ => {
258                // Regular mount or overlay - return as-is
259                Ok(Some((resolved_node, relative_path)))
260            }
261        }
262    }
263
264    /// Resolve path within this mount node and its children (non-transparent resolution)
265    /// 
266    /// This method resolves the given path components starting from this node without
267    /// resolving through bind mounts. This is useful for mount management operations
268    /// where you need to work with the bind mount node itself.
269    /// 
270    /// This is an internal method that operates on Arc<MountNode>
271    /// 
272    /// # Arguments
273    /// * `self_arc` - Arc reference to this node
274    /// * `components` - The path components to resolve.
275    /// 
276    /// # Returns
277    /// * `Ok(Some((Arc<MountNode>, String)))` - A tuple containing the mount node and the relative path.
278    /// * `Ok(None)` - If this node is the final target (self-resolution).
279    /// * `Err(FileSystemError)` - If the path is invalid or no mount point is found.
280    /// 
281    fn resolve_non_transparent_internal(self_arc: Arc<MountNode>, components: &[String]) -> Result<Option<(Arc<MountNode>, String)>> {
282        // If no components left, check if this node is a mount point
283        if components.is_empty() {
284            let mount_guard = self_arc.mount_point.read();
285            if mount_guard.is_some() {
286                // This node is a mount point and is the target
287                return Ok(None);
288            } else {
289                // No mount point at this location
290                return Err(FileSystemError {
291                    kind: FileSystemErrorKind::NotFound,
292                    message: "No mount point found".to_string(),
293                });
294            }
295        }
296
297        // Start with self
298        let mut current_node = self_arc.clone();
299        let mut best_match_node: Option<Arc<MountNode>> = None;
300        let mut match_depth = 0;
301        
302        // Check if current node is a mount point
303        {
304            let mount_guard = current_node.mount_point.read();
305            if mount_guard.is_some() {
306                best_match_node = Some(current_node.clone());
307                match_depth = 0;
308            }
309        }
310        
311        // Traverse components to find the deepest mount point
312        for (depth, component) in components.iter().enumerate() {
313            // Move to next node
314            let next_node = {
315                let children_guard = current_node.children.read();
316                if let Some(child) = children_guard.get(component) {
317                    child.clone()
318                } else {
319                    break;
320                }
321            };
322            current_node = next_node;
323            
324            // Check if the moved-to node is a mount point
325            {
326                let mount_guard = current_node.mount_point.read();
327                if mount_guard.is_some() {
328                    best_match_node = Some(current_node.clone());
329                    match_depth = depth + 1; // +1 for depth after movement
330                }
331            }
332        }
333        
334        let resolved_node = best_match_node.ok_or(FileSystemError {
335            kind: FileSystemErrorKind::NotFound,
336            message: "No mount point found in this subtree".to_string(),
337        })?;
338        
339        // Build relative path
340        let relative_components = &components[match_depth..];
341        let relative_path = if relative_components.is_empty() {
342            "/".to_string()
343        } else {
344            format!("/{}", relative_components.join("/"))
345        };
346        
347        // Return the mount node without resolving bind mounts
348        Ok(Some((resolved_node, relative_path)))
349    }
350}
351
352/// Extended mount point information
353/// 
354/// MountPoint contains comprehensive information about a mounted filesystem,
355/// including metadata, mount options, and relationship information for
356/// hierarchical mount management.
357/// 
358/// # Features
359/// 
360/// - **Filesystem Integration**: Direct reference to the mounted filesystem
361/// - **Mount Hierarchy**: Parent/child relationships for mount tree management
362/// - **Security Options**: Configurable mount options for access control
363/// - **Bind Mount Support**: Resolves bind mount chains to actual filesystems
364/// - **Metadata Tracking**: Mount time and filesystem identification
365/// 
366/// # Thread Safety
367/// 
368/// MountPoint is designed to be shared safely between threads using Arc
369/// wrapper when stored in the mount tree.
370#[derive(Clone)]
371pub struct MountPoint {
372    /// Absolute mount path in the filesystem hierarchy
373    pub path: String,
374    /// Reference to the actual filesystem implementation
375    pub fs: super::FileSystemRef,
376    /// VfsManager-assigned filesystem identifier
377    pub fs_id: usize,
378    /// Type of mount (regular, bind, overlay)
379    pub mount_type: MountType,
380    /// Security and behavior options for this mount
381    pub mount_options: MountOptions,
382    /// Parent mount path (None for root mount)
383    pub parent: Option<String>,
384    /// List of child mount paths
385    pub children: Vec<String>,
386    /// Timestamp when this mount was created
387    pub mount_time: u64,
388}
389
390impl MountPoint {
391    /// Resolve filesystem and internal path from MountPoint
392    /// 
393    /// This method resolves bind mount chains to find the actual filesystem
394    /// that handles the requested path. For regular mounts, it returns the
395    /// filesystem directly. For bind mounts, it recursively follows the
396    /// bind chain to the source filesystem.
397    /// 
398    /// # Arguments
399    /// 
400    /// * `relative_path` - Path relative to this mount point
401    /// 
402    /// # Returns
403    /// 
404    /// * `Ok((FileSystemRef, String))` - The actual filesystem and the resolved path within it
405    /// * `Err(FileSystemError)` - If bind mount resolution fails or exceeds recursion limit
406    /// 
407    /// # Note
408    /// 
409    /// This method only supports Regular, Tmpfs, and Overlay mounts.
410    /// Bind mounts are resolved transparently to their source filesystems.
411    pub fn resolve_fs(&self, relative_path: &str) -> Result<(super::FileSystemRef, String)> {
412        self.resolve_fs_with_depth(relative_path, 0)
413    }
414    
415    /// Internal method for bind mount resolution with recursion depth tracking
416    /// 
417    /// This method prevents infinite recursion in circular bind mount chains
418    /// by limiting the maximum recursion depth to 32 levels.
419    /// 
420    /// # Arguments
421    /// 
422    /// * `relative_path` - Path relative to this mount point
423    /// * `depth` - Current recursion depth for loop detection
424    /// 
425    /// # Returns
426    /// 
427    /// * `Ok((FileSystemRef, String))` - The actual filesystem and resolved path
428    /// * `Err(FileSystemError)` - If recursion limit exceeded or resolution fails
429    fn resolve_fs_with_depth(&self, relative_path: &str, depth: usize) -> Result<(super::FileSystemRef, String)> {
430        // Prevent circular references
431        if depth > 32 {
432            return Err(FileSystemError {
433                kind: FileSystemErrorKind::NotSupported,
434                message: "Too many bind mount redirections".to_string(),
435            });
436        }
437        
438        match &self.mount_type {
439            MountType::Regular | MountType::Overlay { .. } => {
440                // Regular mount: return filesystem as-is
441                Ok((self.fs.clone(), relative_path.to_string()))
442            }
443            
444            MountType::Bind { source_mount_node, source_relative_path, .. } => {
445                // Combine paths
446                let full_source_path = match (relative_path, source_relative_path.as_str()) {
447                    ("/", _) => source_relative_path.clone(),
448                    (_, "/") => relative_path.to_string().clone(),
449                    (rel, src) => {
450                        let src_trimmed = src.trim_end_matches('/');
451                        let rel_trimmed = rel.trim_start_matches('/');
452                        format!("{}/{}", src_trimmed, rel_trimmed)
453                    }
454                };
455                
456                // Recursively resolve with source MountNode
457                let source_mount_point = source_mount_node.get_mount_point()?;
458                source_mount_point.resolve_fs_with_depth(&full_source_path, depth + 1)
459            }
460        }
461    }
462}
463
464/// Mount type classification for different mount strategies
465/// 
466/// This enum defines the various mount types supported by the VFS system,
467/// each with different behaviors and resource handling approaches.
468#[derive(Clone)]
469pub enum MountType {
470    /// Regular filesystem mount
471    /// 
472    /// Standard mount where the filesystem directly handles all operations
473    /// at the mount point. This is the most common mount type.
474    Regular,
475    
476    /// Bind mount - maps one directory tree to another location
477    /// 
478    /// Bind mounts allow the same filesystem content to be accessible
479    /// from multiple mount points. They support:
480    /// - Cross-VFS sharing for container resource sharing
481    /// - Read-only restrictions for security
482    /// - Shared propagation for namespace management
483    Bind {
484        /// Source mount node that provides the actual filesystem
485        source_mount_node: Arc<MountNode>,
486        /// Relative path within the source filesystem
487        source_relative_path: String,
488        /// Type of bind mount (read-only, read-write, shared)
489        bind_type: BindType,
490    },
491    
492    /// Overlay filesystem mount
493    /// 
494    /// Combines multiple filesystem layers into a unified view,
495    /// typically used for container images and copy-on-write scenarios.
496    Overlay {
497        /// Lower filesystem layers (read-only)
498        lower_layers: Vec<String>,
499        /// Upper layer for writes
500        upper_layer: String,
501        /// Working directory for overlay operations
502        work_dir: String,
503    },
504}
505
506/// Bind mount type specifying access and propagation behavior
507/// 
508/// Different bind types provide various levels of access control
509/// and mount propagation for container and namespace isolation.
510#[derive(Clone, Copy, PartialEq, Eq)]
511pub enum BindType {
512    /// Read-only bind mount - prevents write operations
513    ReadOnly,
514    /// Read-write bind mount - allows full access
515    ReadWrite,
516    /// Shared bind mount - propagates mount events to other namespaces
517    Shared,
518}
519
520/// Mount options controlling filesystem behavior and security
521/// 
522/// These options provide fine-grained control over filesystem access
523/// and can be used to enhance security in containerized environments.
524#[derive(Clone)]
525pub struct MountOptions {
526    /// Prevent write operations on this mount
527    pub read_only: bool,
528    /// Disable execution of binaries on this mount
529    pub no_exec: bool,
530    /// Disable set-uid/set-gid bits on this mount
531    pub no_suid: bool,
532    /// Disable device file access on this mount
533    pub no_dev: bool,
534    /// Force synchronous I/O operations
535    pub sync: bool,
536}
537
538impl Default for MountOptions {
539    fn default() -> Self {
540        Self {
541            read_only: false,
542            no_exec: false,
543            no_suid: false,
544            no_dev: false,
545            sync: false,
546        }
547    }
548}
549
550impl MountTree {
551    /// Create a new empty mount tree
552    /// 
553    /// Initializes a new mount tree with an empty root node and no cached paths.
554    /// This creates the foundation for a new filesystem namespace.
555    /// 
556    /// # Returns
557    /// 
558    /// A new MountTree instance ready for mount operations
559    pub fn new() -> Self {
560        Self {
561            root: Arc::new(MountNode::new("".to_string())),
562            path_cache: BTreeMap::new(),
563        }
564    }
565    
566    /// Add mount point (VfsManager interface)
567    /// 
568    /// This method provides the primary interface for VfsManager to add new
569    /// mount points to the tree. It normalizes the path and delegates to
570    /// the internal insert method.
571    /// 
572    /// # Arguments
573    /// 
574    /// * `path` - Absolute path where the filesystem should be mounted
575    /// * `mount_point` - MountPoint structure containing mount information
576    /// 
577    /// # Returns
578    /// 
579    /// * `Ok(())` - Mount operation succeeded
580    /// * `Err(FileSystemError)` - If path is invalid or mount point already exists
581    pub fn mount(&mut self, path: &str, mount_point: MountPoint) -> Result<()> {
582        self.insert(path, mount_point)
583    }
584    
585    /// Internal method to add mount point to the tree
586    /// 
587    /// This method handles the actual insertion logic, creating intermediate
588    /// nodes as needed and validating that mount points don't conflict.
589    /// 
590    /// # Arguments
591    /// 
592    /// * `path` - Normalized absolute path for the mount
593    /// * `mount_point` - MountPoint structure to insert
594    /// 
595    /// # Returns
596    /// 
597    /// * `Ok(())` - Mount point successfully added
598    /// * `Err(FileSystemError)` - If mount point already exists at the path
599    pub fn insert(&mut self, path: &str, mount_point: MountPoint) -> Result<()> {
600        let normalized = Self::normalize_path(path)?;
601        let components = self.split_path(&normalized);
602        
603        // Traverse path using Trie structure
604        let mut current_arc = self.root.clone();
605        for component in &components {
606            let next_arc = {
607                let mut children = current_arc.children.write();
608                children.entry(component.clone())
609                    .or_insert_with(|| Arc::new(MountNode::new(component.clone())))
610                    .clone()
611            };
612            current_arc = next_arc;
613        }
614        
615        // Return error if mount point already exists
616        if current_arc.mount_point.read().is_some() {
617            return Err(FileSystemError {
618                kind: FileSystemErrorKind::AlreadyExists,
619                message: format!("Mount point {} already exists", path),
620            });
621        }
622        
623        // Set mount point
624        let mount_point_arc = Arc::new(mount_point);
625        *current_arc.mount_point.write() = Some(mount_point_arc.clone());
626        self.path_cache.insert(normalized, mount_point_arc);
627        
628        Ok(())
629    }
630    
631    /// Find mount point by path (transparent resolution - resolves through bind mounts)
632    /// 
633    /// This method resolves the given path to its corresponding mount point.
634    /// For bind mounts, it recursively resolves through the source mount tree
635    /// to find the deepest actual mount that handles the requested path.
636    /// 
637    /// # Arguments
638    /// * `path` - The absolute path to resolve.
639    /// 
640    /// # Returns
641    /// * `Ok((Arc<MountNode>, String))` - A tuple containing the resolved mount node and the relative path.
642    /// * `Err(FileSystemError)` - If the path is invalid or no mount point is found.
643    /// 
644    pub fn resolve(&self, path: &str) -> Result<(Arc<MountNode>, String)> {
645        let normalized = Self::normalize_path(path)?;
646        let components = self.split_path(&normalized);
647        
648        let result = MountNode::resolve_internal(self.root.clone(), &components, 0)?;
649        match result {
650            Some((node, path)) => Ok((node, path)),
651            None => {
652                // If None, use the root node itself with empty path
653                Ok((self.root.clone(), "/".to_string()))
654            }
655        }
656    }
657
658    /// Find mount point by path (non-transparent resolution - stops at bind mount nodes)
659    /// 
660    /// This method resolves the given path to its corresponding mount point without
661    /// resolving through bind mounts. This is useful for mount management operations
662    /// where you need to work with the bind mount node itself.
663    /// 
664    /// # Arguments
665    /// * `path` - The absolute path to resolve.
666    /// 
667    /// # Returns
668    /// * `Ok((Arc<MountNode>, String))` - A tuple containing the mount node and the relative path.
669    /// * `Err(FileSystemError)` - If the path is invalid or no mount point is found.
670    /// 
671    pub fn resolve_non_transparent(&self, path: &str) -> Result<(Arc<MountNode>, String)> {
672        let normalized = Self::normalize_path(path)?;
673        let components = self.split_path(&normalized);
674        
675        let result = MountNode::resolve_non_transparent_internal(self.root.clone(), &components)?;
676        match result {
677            Some((node, path)) => Ok((node, path)),
678            None => {
679                // If None, use the root node itself with empty path
680                Ok((self.root.clone(), String::new()))
681            }
682        }
683    }
684    
685    /// Remove mount point from the tree
686    /// 
687    /// Removes a mount point at the specified path and returns the removed
688    /// MountPoint for cleanup. This operation also removes the path from
689    /// the internal cache.
690    /// 
691    /// # Arguments
692    /// 
693    /// * `path` - Absolute path of the mount point to remove
694    /// 
695    /// # Returns
696    /// 
697    /// * `Ok(Arc<MountPoint>)` - The removed mount point
698    /// * `Err(FileSystemError)` - If no mount point exists at the path
699    pub fn remove(&mut self, path: &str) -> Result<Arc<MountPoint>> {
700        let normalized = Self::normalize_path(path)?;
701        let components = self.split_path(&normalized);
702        
703        // Traverse path to find node
704        let mut current_arc = self.root.clone();
705        for component in &components {
706            let next_arc = {
707                let children = current_arc.children.read();
708                children.get(component)
709                    .ok_or(FileSystemError {
710                        kind: FileSystemErrorKind::NotFound,
711                        message: format!("Mount point {} not found", path),
712                    })?
713                    .clone()
714            };
715            current_arc = next_arc;
716        }
717        
718        // Remove mount point
719        let mount_point = current_arc.mount_point.write()
720            .take()
721            .ok_or(FileSystemError {
722                kind: FileSystemErrorKind::NotFound,
723                message: format!("No mount point at {}", path),
724            })?;
725        
726        self.path_cache.remove(&normalized);
727        
728        Ok(mount_point)
729    }
730    
731    /// List all mount points in the tree
732    /// 
733    /// Returns a vector of all mount point paths currently registered
734    /// in the mount tree. This is useful for debugging and system
735    /// introspection.
736    /// 
737    /// # Returns
738    /// 
739    /// Vector of mount point paths in no particular order
740    pub fn list_all(&self) -> Vec<String> {
741        let mut paths = Vec::new();
742        self.collect_mount_paths(&self.root, String::new(), &mut paths);
743        paths
744    }
745    
746    /// Get number of mount points
747    /// 
748    /// Returns the total number of mount points currently registered
749    /// in this mount tree.
750    /// 
751    /// # Returns
752    /// 
753    /// Number of active mount points
754    pub fn len(&self) -> usize {
755        self.path_cache.len()
756    }
757    
758    /// Secure path normalization with directory traversal protection
759    /// 
760    /// This method normalizes filesystem paths by resolving "." and ".."
761    /// components while preventing directory traversal attacks that could
762    /// escape the filesystem root. It ensures all paths are absolute
763    /// and properly formatted.
764    /// 
765    /// # Arguments
766    /// 
767    /// * `path` - Input path to normalize
768    /// 
769    /// # Returns
770    /// 
771    /// * `Ok(String)` - Normalized absolute path
772    /// * `Err(FileSystemError)` - If path is not absolute or invalid
773    /// 
774    /// # Security
775    /// 
776    /// This method prevents:
777    /// - Relative path traversal (../../../etc/passwd)
778    /// - Root directory escape attempts
779    /// - Malformed path components
780    /// 
781    /// # Examples
782    /// 
783    /// ```rust
784    /// assert_eq!(MountTree::normalize_path("/a/b/../c")?, "/a/c");
785    /// assert_eq!(MountTree::normalize_path("/a/./b")?, "/a/b");
786    /// assert_eq!(MountTree::normalize_path("/../..")?, "/");
787    /// ```
788    pub fn normalize_path(path: &str) -> Result<String> {
789        if !path.starts_with('/') {
790            return Err(FileSystemError {
791                kind: FileSystemErrorKind::InvalidPath,
792                message: "Path must be absolute".to_string(),
793            });
794        }
795        
796        let mut normalized_components = Vec::new();
797        let components: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
798        
799        for component in components {
800            match component {
801                "." => continue,
802                ".." => {
803                    // Move to parent directory (cannot go above root)
804                    if !normalized_components.is_empty() {
805                        normalized_components.pop();
806                    }
807                }
808                comp => normalized_components.push(comp),
809            }
810        }
811        
812        if normalized_components.is_empty() {
813            Ok("/".to_string())
814        } else {
815            Ok(format!("/{}", normalized_components.join("/")))
816        }
817    }
818    
819    /// Split normalized path into components
820    /// 
821    /// Converts a normalized path string into a vector of path components
822    /// for tree traversal. Root path "/" becomes an empty vector.
823    /// 
824    /// # Arguments
825    /// 
826    /// * `path` - Normalized absolute path
827    /// 
828    /// # Returns
829    /// 
830    /// Vector of path components, empty for root path
831    fn split_path(&self, path: &str) -> Vec<String> {
832        if path == "/" {
833            return Vec::new();
834        }
835        path.trim_start_matches('/')
836            .split('/')
837            .filter(|s| !s.is_empty())
838            .map(|s| s.to_string())
839            .collect()
840    }
841    
842    /// Recursively collect mount paths from tree nodes
843    /// 
844    /// Internal method for traversing the mount tree and collecting
845    /// all mount point paths for the list_all() operation.
846    /// 
847    /// # Arguments
848    /// 
849    /// * `node` - Current node being examined
850    /// * `current_path` - Path accumulated up to this node
851    /// * `paths` - Vector to collect found mount paths
852    fn collect_mount_paths(&self, node: &MountNode, current_path: String, paths: &mut Vec<String>) {
853        // Check if this node has a mount point
854        let mount_guard = node.mount_point.read();
855        if mount_guard.is_some() {
856            let path = if current_path.is_empty() { "/".to_string() } else { current_path.clone() };
857            paths.push(path);
858        }
859        // Guard is dropped here
860        
861        // Iterate through children
862        let children_guard = node.children.read();
863        for (component, child) in children_guard.iter() {
864            let child_path = if current_path.is_empty() {
865                format!("/{}", component)
866            } else {
867                format!("{}/{}", current_path, component)
868            };
869            self.collect_mount_paths(child, child_path, paths);
870        }
871        // Guard is dropped here
872    }
873}