kernel/fs/vfs_v2/drivers/overlayfs/
mod.rs

1//! OverlayFS v2 - Overlay filesystem implementation for VFS v2
2//!
3//! This module provides a union/overlay view of multiple filesystems, allowing
4//! files and directories from multiple source filesystems to appear as a single
5//! unified filesystem hierarchy.
6//!
7//! ## Features
8//!
9//! - **Multi-layer support**: Combines an optional upper layer (read-write) with
10//!   multiple lower layers (read-only) in priority order
11//! - **Copy-up semantics**: Modifications to lower layer files are copied to the
12//!   upper layer before modification
13//! - **Whiteout support**: Files can be hidden or deleted from view using special
14//!   whiteout entries
15//! - **Mount point aware**: Handles crossing mount boundaries correctly when
16//!   resolving paths across layers
17//!
18//! ## Usage
19//!
20//! ```rust,no_run
21//! // Create overlay with upper and lower layers
22//! let overlay = OverlayFS::new(
23//!     Some((upper_mount, upper_entry)),  // Upper layer for writes
24//!     vec![(lower_mount, lower_entry)],  // Lower layers (read-only)
25//!     "my_overlay".to_string()
26//! )?;
27//! ```
28//!
29//! ## Cross-VFS Support
30//!
31//! - **Cross-VFS overlays supported**: Upper and lower layers can come from
32//!   different VFS managers, enabling flexible overlay configurations
33//! - **Seamless integration**: Mount points from different VFS managers are
34//!   unified transparently through the overlay interface
35//!
36//! ## Limitations
37//!
38//! - Upper layer is required for write operations
39//! - Whiteout files follow the `.wh.filename` convention
40
41use alloc::boxed::Box;
42use alloc::string::ToString;
43use alloc::{sync::Arc, string::String, vec::Vec, collections::BTreeSet, format};
44use spin::RwLock;
45use core::any::Any;
46
47use crate::driver_initcall;
48use crate::fs::vfs_v2::core::{VfsNode, FileSystemOperations, DirectoryEntryInternal, VfsEntry};
49use crate::fs::{get_fs_driver_manager, FileMetadata, FileObject, FilePermission, FileSystemDriver, FileSystemError, FileSystemErrorKind, FileType, SeekFrom, VfsManager};
50use crate::object::capability::{StreamOps, StreamError};
51use crate::fs::vfs_v2::mount_tree::MountPoint;
52use crate::vm::vmem::MemoryArea;
53
54/// OverlayFS implementation for VFS v2
55/// 
56/// This filesystem provides a unified view of multiple underlying filesystems
57/// by layering them on top of each other. Files and directories from all layers
58/// are merged, with the upper layer taking precedence for writes and the lower
59/// layers providing fallback content.
60///
61/// ## Layer Resolution
62/// 
63/// When resolving files or directories:
64/// 1. Check upper layer first (if present and not whiteout)
65/// 2. Check lower layers in priority order 
66/// 3. Return first match found
67///
68/// ## Write Operations
69///
70/// All write operations are performed on the upper layer. If a file exists
71/// only in lower layers, it is first copied to the upper layer (copy-up)
72/// before modification.
73#[derive(Clone)]
74pub struct OverlayFS {
75    /// Upper layer for write operations (may be None for read-only overlay)
76    upper: Option<(Arc<MountPoint>, Arc<VfsEntry>)>,
77    /// Lower layers (in priority order, highest priority first)
78    lower_layers: Vec<(Arc<MountPoint>, Arc<VfsEntry>)>,
79    /// Filesystem name
80    name: String,
81    /// Root node (composite of all layers)
82    root_node: Arc<OverlayNode>,
83}
84
85/// A composite node that represents a file/directory across overlay layers
86///
87/// OverlayNode serves as a virtual representation of a file or directory that
88/// may exist in one or more layers of the overlay filesystem. It handles the
89/// resolution of operations across these layers according to overlay semantics.
90///
91/// ## Design
92///
93/// Each OverlayNode represents a specific path in the overlay and delegates
94/// operations to the appropriate underlying filesystem layers. The node itself
95/// doesn't store file content but rather coordinates access to the real nodes
96/// in the upper and lower layers.
97pub struct OverlayNode {
98    /// Node name
99    name: String,
100    /// Reference to overlay filesystem
101    overlay_fs: RwLock<Option<Arc<OverlayFS>>>,
102    /// Path in the overlay
103    path: String,
104    /// File type (resolved from layers)
105    file_type: FileType,
106    /// File ID
107    file_id: u64,
108}
109
110impl OverlayNode {
111    pub fn new(name: String, path: String, file_type: FileType, file_id: u64) -> Arc<Self> {
112        Arc::new(Self {
113            name,
114            overlay_fs: RwLock::new(None),
115            path,
116            file_type,
117            file_id,
118        })
119    }
120
121    pub fn set_overlay_fs(&self, fs: Arc<OverlayFS>) {
122        *self.overlay_fs.write() = Some(fs);
123    }
124}
125
126impl Clone for OverlayNode {
127    fn clone(&self) -> Self {
128        let cloned = Self {
129            name: self.name.clone(),
130            overlay_fs: RwLock::new(None),
131            path: self.path.clone(),
132            file_type: self.file_type.clone(),
133            file_id: self.file_id,
134        };
135        
136        // Copy the overlay_fs reference if it exists
137        if let Some(fs) = self.overlay_fs.read().as_ref() {
138            *cloned.overlay_fs.write() = Some(Arc::clone(fs));
139        }
140        
141        cloned
142    }
143}
144
145impl VfsNode for OverlayNode {
146    fn id(&self) -> u64 {
147        self.file_id
148    }
149
150    fn filesystem(&self) -> Option<alloc::sync::Weak<dyn FileSystemOperations>> {
151        self.overlay_fs.read().as_ref().map(|fs| Arc::downgrade(fs) as alloc::sync::Weak<dyn FileSystemOperations>)
152    }
153
154    fn metadata(&self) -> Result<FileMetadata, FileSystemError> {
155        if let Some(ref fs) = *self.overlay_fs.read() {
156            fs.get_metadata_for_path(&self.path)
157        } else {
158            Err(FileSystemError::new(FileSystemErrorKind::NotSupported, "No filesystem reference"))
159        }
160    }
161
162    fn as_any(&self) -> &dyn Any {
163        self
164    }
165}
166
167impl OverlayFS {
168    /// Create a new OverlayFS instance with specified layers
169    ///
170    /// # Arguments
171    ///
172    /// * `upper` - Optional upper layer for write operations (mount point and entry)
173    /// * `lower_layers` - Vector of lower layers in priority order (highest priority first)
174    /// * `name` - Name identifier for this overlay filesystem
175    ///
176    /// # Returns
177    ///
178    /// Returns an Arc<OverlayFS> on success, or FileSystemError on failure
179    ///
180    /// # Example
181    ///
182    /// ```rust,no_run
183    /// let overlay = OverlayFS::new(
184    ///     Some((upper_mount, upper_entry)),  // Read-write upper layer
185    ///     vec![
186    ///         (layer1_mount, layer1_entry),   // Higher priority lower layer
187    ///         (layer2_mount, layer2_entry),   // Lower priority layer
188    ///     ],
189    ///     "system_overlay".to_string()
190    /// )?;
191    /// ```
192    pub fn new(
193        upper: Option<(Arc<MountPoint>, Arc<VfsEntry>)>,
194        lower_layers: Vec<(Arc<MountPoint>, Arc<VfsEntry>)>,
195        name: String
196    ) -> Result<Arc<Self>, FileSystemError> {
197        let root_node = OverlayNode::new("/".to_string(), "/".to_string(), FileType::Directory, 1);
198        let overlay = Arc::new(Self {
199            upper,
200            lower_layers,
201            name,
202            root_node: root_node.clone(),
203        });
204        root_node.set_overlay_fs(overlay.clone());
205        Ok(overlay)
206    }
207
208    /// Create a new OverlayFS from VFS paths
209    ///
210    /// This is a convenience method that resolves VFS paths to create an overlay.
211    /// This approach follows the "normal filesystem" pattern - create the overlay
212    /// instance, then mount it like any other filesystem.
213    ///
214    /// # Arguments
215    /// * `vfs_manager` - VFS manager to resolve paths in
216    /// * `upper_path` - Optional path for the upper (writable) layer
217    /// * `lower_paths` - Vector of paths for lower (read-only) layers
218    /// * `name` - Name for the overlay instance
219    ///
220    /// # Example
221    /// ```rust,no_run
222    /// // Create overlay from paths
223    /// let overlay = OverlayFS::new_from_paths(
224    ///     &vfs_manager,
225    ///     Some("/tmp/overlay"),           // Upper layer
226    ///     vec!["/system", "/base"],       // Lower layers
227    ///     "container_overlay"
228    /// )?;
229    /// 
230    /// // Mount like any other filesystem
231    /// vfs_manager.mount(overlay, "/merged", 0)?;
232    /// ```
233    pub fn new_from_paths(
234        vfs_manager: &crate::fs::vfs_v2::manager::VfsManager,
235        upper_path: Option<&str>,
236        lower_paths: Vec<&str>,
237        name: &str,
238    ) -> Result<Arc<Self>, FileSystemError> {
239        // Resolve upper layer if provided
240        let upper = if let Some(path) = upper_path {
241            let (entry, mount) = vfs_manager.mount_tree.resolve_path(path)?;
242            Some((mount, entry))
243        } else {
244            None
245        };
246
247        // Resolve lower layers
248        let mut lower_layers = Vec::new();
249        for path in lower_paths {
250            let (entry, mount) = vfs_manager.mount_tree.resolve_path(path)?;
251            lower_layers.push((mount, entry));
252        }
253
254        // Create overlay with resolved layers
255        Self::new(upper, lower_layers, name.to_string())
256    }
257
258    /// Create a new OverlayFS from paths across multiple VFS managers (Cross-VFS)
259    ///
260    /// This method enables true cross-VFS overlays where upper and lower layers
261    /// can come from completely different VFS manager instances. This is perfect
262    /// for container scenarios where the base system is in one VFS and the
263    /// container overlay is in another.
264    ///
265    /// # Arguments
266    /// * `upper_vfs_and_path` - Optional tuple of (vfs_manager, path) for upper layer
267    /// * `lower_vfs_and_paths` - Vector of (vfs_manager, path) tuples for lower layers
268    /// * `name` - Name for the overlay instance
269    ///
270    /// # Example
271    /// ```rust,no_run
272    /// // Cross-VFS overlay: base system from global VFS, overlay in container VFS
273    /// let base_vfs = get_global_vfs_manager();
274    /// let container_vfs = VfsManager::new();
275    /// 
276    /// let overlay = OverlayFS::new_from_paths_and_vfs(
277    ///     Some((&container_vfs, "/upper")),       // Upper in container VFS
278    ///     vec![
279    ///         (&base_vfs, "/system"),              // Base system from global VFS
280    ///         (&container_vfs, "/config"),         // Config from container VFS
281    ///     ],
282    ///     "cross_vfs_overlay"
283    /// )?;
284    /// 
285    /// // Mount in container VFS like any other filesystem
286    /// container_vfs.mount(overlay, "/merged", 0)?;
287    /// ```
288    pub fn new_from_paths_and_vfs(
289        upper_vfs_and_path: Option<(&Arc<VfsManager>, &str)>,
290        lower_vfs_and_paths: Vec<(&Arc<VfsManager>, &str)>,
291        name: &str,
292    ) -> Result<Arc<Self>, FileSystemError> {
293        // Resolve upper layer from its VFS
294        let upper = if let Some((upper_vfs, upper_path)) = upper_vfs_and_path {
295            let (entry, mount) = upper_vfs.mount_tree.resolve_path(upper_path)?;
296            Some((mount, entry))
297        } else {
298            None
299        };
300
301        // Resolve lower layers from their respective VFS managers
302        let mut lower_layers = Vec::new();
303        for (lower_vfs, lower_path) in lower_vfs_and_paths {
304            let (entry, mount) = lower_vfs.mount_tree.resolve_path(lower_path)?;
305            lower_layers.push((mount, entry));
306        }
307
308        // Create overlay - the internal implementation already supports cross-VFS!
309        Self::new(upper, lower_layers, name.to_string())
310    }
311
312    /// Get FileSystemOperations from MountPoint
313    /// 
314    /// Helper method to extract the filesystem operations from a mount point.
315    /// This is used internally to access the underlying filesystem operations
316    /// for each layer.
317    fn fs_from_mount(mount: &Arc<MountPoint>) -> Result<Arc<dyn FileSystemOperations>, FileSystemError> {
318        let filesystem = mount.root.node().filesystem()
319            .ok_or_else(|| FileSystemError::new(FileSystemErrorKind::BrokenFileSystem, "Mount point has no filesystem"))?;
320        
321        let fs_ops = filesystem.upgrade()
322            .ok_or_else(|| FileSystemError::new(FileSystemErrorKind::BrokenFileSystem, "Filesystem operations are no longer available"))?;
323        
324        Ok(fs_ops)
325    }
326
327    /// Get metadata for a path by checking layers in priority order
328    ///
329    /// This method implements the core overlay resolution logic:
330    /// 1. Check if the path is hidden by a whiteout file
331    /// 2. Check the upper layer first (if present)
332    /// 3. Fall back to lower layers in priority order
333    ///
334    /// # Arguments
335    ///
336    /// * `path` - The path to resolve within the overlay
337    ///
338    /// # Returns
339    ///
340    /// Returns FileMetadata for the first matching file found, or NotFound error
341    /// if the file doesn't exist in any layer or is hidden by whiteout.
342    fn get_metadata_for_path(&self, path: &str) -> Result<FileMetadata, FileSystemError> {
343        // Check for whiteout first
344        if self.is_whiteout(path) {
345            return Err(FileSystemError::new(FileSystemErrorKind::NotFound, "File is hidden by whiteout"));
346        }
347
348        // Check upper layer first
349        if let Some((ref upper_fs, ref upper_node)) = self.upper {
350            if let Ok(node) = self.resolve_in_layer(upper_fs, upper_node, path) {
351                return node.metadata();
352            }
353        }
354
355        // Check lower layers
356        for (lower_fs, lower_node) in &self.lower_layers {
357            if let Ok(node) = self.resolve_in_layer(lower_fs, lower_node, path) {
358                return node.metadata();
359            }
360        }
361
362        Err(FileSystemError::new(FileSystemErrorKind::NotFound, "File not found in any layer"))
363    }
364
365    /// Resolve a path in a specific layer, starting from the given node
366    ///
367    /// This method performs path resolution within a single overlay layer,
368    /// handling mount boundary crossings correctly. It walks down the path
369    /// components, following mount points as needed.
370    ///
371    /// # Arguments
372    ///
373    /// * `mount` - The mount point to start resolution from
374    /// * `entry` - The VFS entry to start resolution from  
375    /// * `path` - The path to resolve (relative to the entry)
376    ///
377    /// # Returns
378    ///
379    /// Returns the resolved VfsNode, or an error if the path cannot be resolved
380    /// in this layer.
381    fn resolve_in_layer(&self, mount: &Arc<MountPoint>, entry: &Arc<VfsEntry>, path: &str) -> Result<Arc<dyn VfsNode>, FileSystemError> {
382        let mut current_mount = mount.clone();
383        let mut current_node = entry.node();
384
385        let parts: Vec<&str> = path.trim_start_matches('/').split('/').filter(|s| !s.is_empty()).collect();
386        if parts.is_empty() {
387            return Ok(current_node);
388        }
389
390        for part in parts {
391            let current_fs = current_node.filesystem()
392                .and_then(|w| w.upgrade())
393                .ok_or_else(|| FileSystemError::new(FileSystemErrorKind::NotSupported, "Node has no filesystem"))?;
394            
395            let next_node = current_fs.lookup(&current_node, &part.to_string())?;
396
397            let child_mount_opt = current_mount.children.read().get(&next_node.id()).cloned();
398
399            if let Some(child_mount) = child_mount_opt {
400                current_mount = child_mount.clone();
401                current_node = child_mount.root.node();
402            } else {
403                current_node = next_node;
404            }
405        }
406
407        Ok(current_node)
408    }
409
410    /// Check if a file is hidden by a whiteout file
411    ///
412    /// Whiteout files are special files in the upper layer that indicate
413    /// a file from a lower layer should be hidden. They follow the naming
414    /// convention `.wh.filename` where `filename` is the name of the file
415    /// to be hidden.
416    ///
417    /// # Arguments
418    ///
419    /// * `path` - The path to check for whiteout
420    ///
421    /// # Returns
422    ///
423    /// Returns true if the file is hidden by a whiteout, false otherwise.
424    fn is_whiteout(&self, path: &str) -> bool {
425        if let Some((ref upper_fs, ref upper_node)) = self.upper {
426            let whiteout_name = format!(".wh.{}", 
427                path.split('/').last().unwrap_or(path));
428            let parent_path = if let Some(pos) = path.rfind('/') {
429                &path[..pos]
430            } else {
431                "/"
432            };
433            let whiteout_path = if parent_path == "/" {
434                format!("/{}", whiteout_name)
435            } else {
436                format!("{}/{}", parent_path, whiteout_name)
437            };
438            
439            self.resolve_in_layer(upper_fs, upper_node, &whiteout_path).is_ok()
440        } else {
441            false
442        }
443    }
444
445    /// Get upper layer, error if not available
446    ///
447    /// Returns the upper layer mount point and entry, or an error if the
448    /// overlay filesystem is read-only (no upper layer configured).
449    /// This is used by write operations that require an upper layer.
450    ///
451    /// # Returns
452    ///
453    /// Returns (MountPoint, VfsEntry) tuple for upper layer, or PermissionDenied
454    /// error if no upper layer is available.
455    fn get_upper_layer(&self) -> Result<(Arc<MountPoint>, Arc<VfsEntry>), FileSystemError> {
456        self.upper.as_ref().map(|fs| fs.clone()).ok_or_else(|| 
457            FileSystemError::new(FileSystemErrorKind::PermissionDenied, "Overlay is read-only (no upper layer)")
458        )
459    }
460
461    /// Create a whiteout file to hide a file from lower layers
462    fn create_whiteout(&self, path: &str) -> Result<(), FileSystemError> {
463        let upper = self.get_upper_layer()?;
464        let whiteout_name = format!(".wh.{}", 
465            path.split('/').last().unwrap_or(path));
466        let parent_path = if let Some(pos) = path.rfind('/') {
467            &path[..pos]
468        } else {
469            "/"
470        };
471        let whiteout_path = if parent_path == "/" {
472            format!("/{}", whiteout_name)
473        } else {
474            format!("{}/{}", parent_path, whiteout_name)
475        };
476        // Create parent directories if needed
477        self.ensure_parent_dirs(&whiteout_path)?;
478        let parent_node = self.resolve_in_layer(&upper.0, &upper.1, parent_path)?;
479        let fs = Self::fs_from_mount(&upper.0)?;
480        fs.create(&parent_node, &whiteout_name, FileType::RegularFile, 0o644)
481            .map(|_| ())
482    }
483
484    /// Perform copy-up operation: copy a file from lower layer to upper layer
485    fn copy_up(&self, path: &str) -> Result<(), FileSystemError> {
486        let upper = self.get_upper_layer()?;
487        let upper_fs = Self::fs_from_mount(&upper.0)?;
488        // Check if file already exists in upper layer
489        if self.resolve_in_layer(&upper.0, &upper.1, path).is_ok() {
490            return Ok(());
491        }
492        // Find the file in lower layers
493        for (lower_mount, lower_node) in &self.lower_layers {
494            if let Ok(lower_node) = self.resolve_in_layer(lower_mount, lower_node, path) {
495                let metadata = lower_node.metadata()?;
496                // Ensure parent directories exist in upper layer
497                self.ensure_parent_dirs(path)?;
498                let parent_path = if let Some(pos) = path.rfind('/') {
499                    &path[..pos]
500                } else {
501                    "/"
502                };
503                let filename = path.split('/').last().unwrap_or(path);
504                let parent_node = self.resolve_in_layer(&upper.0, &upper.1, parent_path)?;
505                match metadata.file_type {
506                    FileType::Directory => {
507                        upper_fs.create(&parent_node, &filename.to_string(), FileType::Directory, 0o755)?;
508                    }
509                    FileType::RegularFile => {
510                        // Create file and copy content
511                        let new_node = upper_fs.create(&parent_node, &filename.to_string(), FileType::RegularFile, 0o644)?;
512                        // Copy file content
513                        let lower_fs = Self::fs_from_mount(lower_mount)?;
514                        if let Ok(source_file) = lower_fs.open(&lower_node, 0) { // Read-only
515                            if let Ok(dest_file) = upper_fs.open(&new_node, 1) { // Write-only
516                                let _ = dest_file.seek(SeekFrom::Start(0));
517                                let mut buffer = [0u8; 4096];
518                                loop {
519                                    match source_file.read(&mut buffer) {
520                                        Ok(bytes_read) if bytes_read > 0 => {
521                                            if dest_file.write(&buffer[..bytes_read]).is_err() {
522                                                break;
523                                            }
524                                        }
525                                        _ => break,
526                                    }
527                                }
528                            }
529                        }
530                    }
531                    _ => {
532                        // For other file types, create a placeholder
533                        upper_fs.create(&parent_node, &filename.to_string(), metadata.file_type, 0o644)?;
534                    }
535                }
536                return Ok(());
537            }
538        }
539        Err(FileSystemError::new(FileSystemErrorKind::NotFound, "File not found for copy-up"))
540    }
541
542    /// Ensure parent directories exist in upper layer
543    fn ensure_parent_dirs(&self, path: &str) -> Result<(), FileSystemError> {
544        let upper = self.get_upper_layer()?;
545        let _upper_fs = Self::fs_from_mount(&upper.0)?;
546        let parent_path = if let Some(pos) = path.rfind('/') {
547            &path[..pos]
548        } else {
549            return Ok(());
550        };
551        if parent_path.is_empty() || parent_path == "/" {
552            return Ok(());
553        }
554        // Try to resolve parent - if it fails, create it
555        if self.resolve_in_layer(&upper.0, &upper.1, parent_path).is_err() {
556            self.ensure_parent_dirs(parent_path)?;
557            let grandparent_path = if let Some(pos) = parent_path.rfind('/') {
558                &parent_path[..pos]
559            } else {
560                "/"
561            };
562            let dirname = parent_path.split('/').last().unwrap_or(parent_path);
563            let grandparent_node = self.resolve_in_layer(&upper.0, &upper.1, if grandparent_path.is_empty() { "/" } else { grandparent_path })?;
564            let upper_fs = Self::fs_from_mount(&upper.0)?;
565            upper_fs.create(&grandparent_node, &dirname.to_string(), FileType::Directory, 0o755)?;
566        }
567        Ok(())
568    }
569
570    /// Check if file exists only in lower layers (not in upper)
571    fn file_exists_in_lower_only(&self, path: &str) -> bool {
572        // Check if exists in upper
573        if let Some((ref upper_fs, ref upper_node)) = self.upper {
574            if self.resolve_in_layer(upper_fs, upper_node, path).is_ok() {
575                return false;
576            }
577        }
578        
579        // Check if exists in any lower layer
580        for (lower_fs, lower_node) in &self.lower_layers {
581            if self.resolve_in_layer(lower_fs, lower_node, path).is_ok() {
582                return true;
583            }
584        }
585        
586        false
587    }
588
589    /// Create an OverlayFS from an option string
590    /// example: option = Some("upper=tmpfs,lower=cpiofs")
591    pub fn create_from_option_string(
592        _option: Option<&str>,
593        upper: Option<(Arc<MountPoint>, Arc<VfsEntry>)>,
594        lower_layers: Vec<(Arc<MountPoint>, Arc<VfsEntry>)>,
595    ) -> Arc<dyn FileSystemOperations> {
596        // Parse options if provided
597        let name = "overlayfs".to_string();
598        OverlayFS::new(upper, lower_layers, name).expect("Failed to create OverlayFS") as Arc<dyn FileSystemOperations>
599    }
600}
601
602impl FileSystemOperations for OverlayFS {
603    fn lookup(&self, parent_node: &Arc<dyn VfsNode>, name: &String) -> Result<Arc<dyn VfsNode>, FileSystemError> {
604        let overlay_parent = parent_node.as_any()
605            .downcast_ref::<OverlayNode>()
606            .ok_or_else(|| FileSystemError::new(FileSystemErrorKind::NotSupported, "Invalid node type for OverlayFS"))?;
607
608        let child_path = if overlay_parent.path == "/" {
609            format!("/{}", name)
610        } else {
611            format!("{}/{}", overlay_parent.path, name)
612        };
613
614        // Handle special directory entries
615        if name == "." {
616            return Ok(parent_node.clone());
617        }
618        if name == ".." {
619            let parent_path = if let Some(pos) = overlay_parent.path.rfind('/') {
620                if pos == 0 { "/" } else { &overlay_parent.path[..pos] }
621            } else {
622                "/"
623            };
624            let parent_name = parent_path.split('/').last().unwrap_or("/");
625            let node = OverlayNode::new(parent_name.to_string(), parent_path.to_string(), FileType::Directory, 0);
626            if let Some(ref fs) = *overlay_parent.overlay_fs.read() {
627                node.set_overlay_fs(Arc::clone(fs));
628            }
629            return Ok(node);
630        }
631
632        // Check for whiteout
633        if self.is_whiteout(&child_path) {
634            return Err(FileSystemError::new(FileSystemErrorKind::NotFound, "File is hidden by whiteout"));
635        }
636
637        // Try upper layer first
638        if let Some((ref upper_fs, ref upper_node)) = self.upper {
639            if let Ok(_) = self.resolve_in_layer(upper_fs, upper_node, &child_path) {
640                let metadata = self.get_metadata_for_path(&child_path)?;
641                let node = OverlayNode::new(name.clone(), child_path.clone(), metadata.file_type, metadata.file_id);
642                if let Some(ref fs) = *overlay_parent.overlay_fs.read() {
643                    node.set_overlay_fs(Arc::clone(fs));
644                }
645                return Ok(node);
646            }
647        }
648
649        // Try lower layers
650        for (lower_fs, lower_node) in &self.lower_layers {
651            if let Ok(_) = self.resolve_in_layer(lower_fs, lower_node, &child_path) {
652                let metadata = self.get_metadata_for_path(&child_path)?;
653                let node = OverlayNode::new(name.clone(), child_path.clone(), metadata.file_type, metadata.file_id);
654                if let Some(ref fs) = *overlay_parent.overlay_fs.read() {
655                    node.set_overlay_fs(Arc::clone(fs));
656                }
657                return Ok(node);
658            }
659        }
660
661        Err(FileSystemError::new(FileSystemErrorKind::NotFound, "File not found"))
662    }
663
664    fn open(&self, overlay_node: &Arc<dyn VfsNode>, flags: u32) -> Result<Arc<dyn FileObject>, FileSystemError> {
665        // Downcast to OverlayNode
666        let overlay_node_ref = overlay_node.as_any()
667            .downcast_ref::<OverlayNode>()
668            .ok_or_else(|| FileSystemError::new(FileSystemErrorKind::NotSupported, "Invalid node type for OverlayFS"))?;
669        
670        
671        // Get metadata using path instead of node metadata to avoid filesystem reference issues
672        let metadata = self.get_metadata_for_path(&overlay_node_ref.path)?;
673        
674        // If this is a directory, return OverlayDirectoryObject
675        if metadata.file_type == FileType::Directory {
676            return Ok(Arc::new(OverlayDirectoryObject::new(
677                Arc::new(self.clone()),
678                overlay_node_ref.path.clone()
679            )));
680        }
681        
682        // Check if this is a write operation
683        let is_write_operation = (flags & 0x3) != 0; // O_WRONLY=1, O_RDWR=2
684        // If writing to a file that exists only in lower layer, copy it up first
685        if is_write_operation && self.file_exists_in_lower_only(&overlay_node_ref.path) {
686            self.copy_up(&overlay_node_ref.path)?;
687        }
688        // Try upper layer first
689        if let Some((ref upper_mount, ref upper_node)) = self.upper {
690            if let Ok(upper_node) = self.resolve_in_layer(upper_mount, upper_node, &overlay_node_ref.path) {
691                let fs = Self::fs_from_mount(upper_mount)?;
692                if let Ok(file) = fs.open(&upper_node, flags) {
693                    return Ok(file);
694                }
695            }
696        }
697        // For write operations, we need an upper layer
698        if is_write_operation {
699            return Err(FileSystemError::new(FileSystemErrorKind::PermissionDenied, "Cannot write to read-only overlay"));
700        }
701        // Try lower layers for read operations
702        for (lower_mount, lower_node) in &self.lower_layers {
703            if let Ok(lower_node) = self.resolve_in_layer(lower_mount, lower_node, &overlay_node_ref.path) {
704                let fs = Self::fs_from_mount(lower_mount)?;
705                if let Ok(file) = fs.open(&lower_node, flags) {
706                    return Ok(file);
707                }
708            }
709        }
710        Err(FileSystemError::new(FileSystemErrorKind::NotFound, "File not found"))
711    }
712
713    fn create(&self, parent_node: &Arc<dyn VfsNode>, name: &String, file_type: FileType, mode: u32) -> Result<Arc<dyn VfsNode>, FileSystemError> {
714        let upper = self.get_upper_layer()?;
715        let upper_fs = Self::fs_from_mount(&upper.0)?;
716        let overlay_parent = parent_node.as_any()
717            .downcast_ref::<OverlayNode>()
718            .ok_or_else(|| FileSystemError::new(FileSystemErrorKind::NotSupported, "Invalid node type for OverlayFS"))?;
719        let child_path = if overlay_parent.path == "/" {
720            format!("/{}", name)
721        } else {
722            format!("{}/{}", overlay_parent.path, name)
723        };
724        // Ensure parent exists in upper layer (copy-up if needed)
725        if self.file_exists_in_lower_only(&overlay_parent.path) {
726            self.copy_up(&overlay_parent.path)?;
727        }
728        // Remove any existing whiteout
729        if self.is_whiteout(&child_path) {
730            // Remove whiteout file
731            let whiteout_name = format!(".wh.{}", name);
732            let parent_path = if let Some(pos) = overlay_parent.path.rfind('/') {
733                &overlay_parent.path[..pos]
734            } else {
735                "/"
736            };
737            if let Ok(whiteout_parent) = self.resolve_in_layer(&upper.0, &upper.1, parent_path) {
738                if upper_fs.remove(&whiteout_parent, &whiteout_name).is_err() {
739                    return Err(FileSystemError::new(FileSystemErrorKind::NotFound, "Whiteout file not found"));
740                }
741                // Successfully removed whiteout file
742            }
743        }
744        let upper_parent = self.resolve_in_layer(&upper.0, &upper.1, &overlay_parent.path)?;
745        let fs = Self::fs_from_mount(&upper.0)?;
746        let new_node = fs.create(&upper_parent, name, file_type, mode)?;
747        // Return overlay node
748        let metadata = new_node.metadata()?;
749        let overlay_node = OverlayNode::new(name.clone(), child_path, metadata.file_type, metadata.file_id);
750        if let Some(ref fs) = *overlay_parent.overlay_fs.read() {
751            overlay_node.set_overlay_fs(Arc::clone(fs));
752        }
753        Ok(overlay_node)
754    }
755
756    fn remove(&self, parent_node: &Arc<dyn VfsNode>, name: &String) -> Result<(), FileSystemError> {
757        let overlay_parent = parent_node.as_any()
758            .downcast_ref::<OverlayNode>()
759            .ok_or_else(|| FileSystemError::new(FileSystemErrorKind::NotSupported, "Invalid node type for OverlayFS"))?;
760
761        let child_path = if overlay_parent.path == "/" {
762            format!("/{}", name)
763        } else {
764            format!("{}/{}", overlay_parent.path, name)
765        };
766
767        // If file exists in upper layer, remove it
768        if let Some((ref upper_mount, ref upper_entry)) = self.upper {
769            if let Ok(upper_parent) = self.resolve_in_layer(upper_mount, upper_entry, &overlay_parent.path) {
770                let fs = Self::fs_from_mount(upper_mount)?;
771                if fs.remove(&upper_parent, name).is_ok() {
772                    // If file also exists in lower layers, create whiteout
773                    for (lower_mount, lower_entry) in &self.lower_layers {
774                        if self.resolve_in_layer(lower_mount, lower_entry, &child_path).is_ok() {
775                            self.create_whiteout(&child_path)?;
776                            break;
777                        }
778                    }
779                    return Ok(());
780                }
781            }
782        }
783
784        // If file exists only in lower layers, create whiteout
785        for (lower_mount, lower_node) in &self.lower_layers {
786            if self.resolve_in_layer(lower_mount, lower_node, &child_path).is_ok() {
787                self.create_whiteout(&child_path)?;
788                return Ok(());
789            }
790        }
791
792        Err(FileSystemError::new(FileSystemErrorKind::NotFound, "File not found"))
793    }
794
795    fn root_node(&self) -> Arc<dyn VfsNode> {
796        Arc::clone(&self.root_node) as Arc<dyn VfsNode>
797    }
798
799    fn name(&self) -> &str {
800        &self.name
801    }
802
803    fn is_read_only(&self) -> bool {
804        self.upper.is_none()
805    }
806
807    fn readdir(&self, node: &Arc<dyn VfsNode>) -> Result<Vec<DirectoryEntryInternal>, FileSystemError> {
808        let overlay_node = node.as_any()
809            .downcast_ref::<OverlayNode>()
810            .ok_or_else(|| FileSystemError::new(FileSystemErrorKind::NotSupported, "Invalid node type for OverlayFS"))?;
811
812        let mut entries = Vec::new();
813        let mut seen_names = BTreeSet::new();
814
815        // Get parent directory file_id for ".."
816        let parent_file_id = if overlay_node.path == "/" {
817            // Root directory's parent is itself
818            overlay_node.file_id
819        } else {
820            // Get parent by looking up ".." from current directory
821            match self.lookup(node, &"..".to_string()) {
822                Ok(parent_node) => parent_node.id(),
823                Err(_) => overlay_node.file_id, // Fallback to current if parent can't be resolved
824            }
825        };
826
827        // Add "." and ".." entries
828        entries.push(DirectoryEntryInternal {
829            name: ".".to_string(),
830            file_type: FileType::Directory,
831            file_id: overlay_node.file_id,
832        });
833        entries.push(DirectoryEntryInternal {
834            name: "..".to_string(),
835            file_type: FileType::Directory,
836            file_id: parent_file_id,
837        });
838        seen_names.insert(".".to_string());
839        seen_names.insert("..".to_string());
840
841        // Read from upper layer first
842        if let Some((ref upper_mount, ref upper_node)) = self.upper {
843            if let Ok(upper_node) = self.resolve_in_layer(upper_mount, upper_node, &overlay_node.path) {
844                let fs = upper_node.filesystem().and_then(|w| w.upgrade()).ok_or_else(|| FileSystemError::new(FileSystemErrorKind::NotSupported, "Node has no filesystem"))?;
845                if let Ok(upper_entries) = fs.readdir(&upper_node) {
846                    for entry in upper_entries {
847                        // Skip whiteout files themselves and . .. entries
848                        if entry.name.starts_with(".wh.") || entry.name == "." || entry.name == ".." {
849                            continue;
850                        }
851                        if !seen_names.contains(&entry.name) {
852                            seen_names.insert(entry.name.clone());
853                            entries.push(entry);
854                        }
855                    }
856                }
857            }
858        }
859
860        // Read from lower layers (skip entries already seen in upper layers)
861        for (lower_mount, lower_node) in &self.lower_layers {
862            if let Ok(lower_node) = self.resolve_in_layer(lower_mount, lower_node, &overlay_node.path) {
863                let fs = lower_node.filesystem().and_then(|w| w.upgrade()).ok_or_else(|| FileSystemError::new(FileSystemErrorKind::NotSupported, "Node has no filesystem"))?;
864                if let Ok(lower_entries) = fs.readdir(&lower_node) {
865                    for entry in lower_entries {
866                        // Skip . .. entries
867                        if entry.name == "." || entry.name == ".." {
868                            continue;
869                        }
870                        let entry_full_path = if overlay_node.path == "/" {
871                            format!("/{}", entry.name)
872                        } else {
873                            format!("{}/{}", overlay_node.path, entry.name)
874                        };
875                        // Only add if not already seen and not hidden by whiteout
876                        if !seen_names.contains(&entry.name) && !self.is_whiteout(&entry_full_path) {
877                            seen_names.insert(entry.name.clone());
878                            entries.push(entry);
879                        }
880                    }
881                }
882            }
883        }
884        entries.sort_by(|a, b| a.file_id.cmp(&b.file_id)); // Sort entries by file_id
885        Ok(entries)
886    }
887}
888
889/// File object for OverlayFS directory operations
890///
891/// OverlayDirectoryObject handles reading directory entries from overlayfs,
892/// merging entries from upper and lower layers while respecting whiteout files.
893pub struct OverlayDirectoryObject {
894    overlay_fs: Arc<OverlayFS>,
895    path: String, // Store path instead of node
896    position: RwLock<u64>,
897}
898
899impl OverlayDirectoryObject {
900    pub fn new(overlay_fs: Arc<OverlayFS>, path: String) -> Self {
901        Self {
902            overlay_fs,
903            path,
904            position: RwLock::new(0),
905        }
906    }
907
908    /// Collect all directory entries from all layers, handling whiteouts and merging
909    fn collect_directory_entries(&self) -> Result<Vec<crate::fs::DirectoryEntryInternal>, FileSystemError> {
910        let mut special_entries = Vec::new();
911        let mut all_entries = Vec::new();
912
913        let mut seen_names = BTreeSet::new();
914        
915        // Get current directory node by resolving path components
916        let current_dir_node = {
917            let mut current = self.overlay_fs.root_node();
918            if self.path != "/" {
919                for component in self.path.trim_start_matches('/').split('/') {
920                    if !component.is_empty() {
921                        current = self.overlay_fs.lookup(&current, &component.to_string())?;
922                    }
923                }
924            }
925            current
926        };
927        let current_file_id = current_dir_node.id();
928        
929        // Get parent directory file_id for ".."
930        let parent_file_id = if self.path == "/" {
931            // Root directory's parent is itself
932            current_file_id
933        } else {
934            // Get parent by looking up ".." from current directory
935            match self.overlay_fs.lookup(&current_dir_node, &"..".to_string()) {
936                Ok(parent_node) => parent_node.id(),
937                Err(_) => current_file_id, // Fallback to current if parent can't be resolved
938            }
939        };
940        
941        // Add "." and ".." entries first
942        special_entries.push(crate::fs::DirectoryEntryInternal {
943            name: ".".to_string(),
944            file_type: FileType::Directory,
945            file_id: current_file_id,
946            size: 0,
947            metadata: None,
948        });
949        special_entries.push(crate::fs::DirectoryEntryInternal {
950            name: "..".to_string(),
951            file_type: FileType::Directory,
952            file_id: parent_file_id,
953            size: 0,
954            metadata: None,
955        });
956        seen_names.insert(".".to_string());
957        seen_names.insert("..".to_string());
958        
959        // Check upper layer first
960        if let Some((ref upper_mount, ref upper_node)) = self.overlay_fs.upper {
961            if let Ok(upper_dir_node) = self.overlay_fs.resolve_in_layer(upper_mount, upper_node, &self.path) {
962                // Try to get filesystem from mount and read directory
963                if let Ok(upper_fs) = Self::try_fs_from_mount(upper_mount) {
964                    if let Ok(upper_entries) = upper_fs.readdir(&upper_dir_node) {
965                        for entry in upper_entries {
966                            if entry.name == "." || entry.name == ".." {
967                                continue; // Skip, already added
968                            }
969                            
970                            // Check for whiteout
971                            if entry.name.starts_with(".wh.") {
972                                // Hide the corresponding file from lower layers
973                                let hidden_name = &entry.name[4..]; // Remove ".wh." prefix
974                                seen_names.insert(hidden_name.to_string());
975                                continue; // Don't add the whiteout file itself
976                            }
977                            
978                            if !seen_names.contains(&entry.name) {
979                                all_entries.push(crate::fs::DirectoryEntryInternal {
980                                    name: entry.name.clone(),
981                                    file_type: entry.file_type,
982                                    file_id: entry.file_id,
983                                    size: 0,
984                                    metadata: None,
985                                });
986                                seen_names.insert(entry.name);
987                            }
988                        }
989                    }
990                }
991            }
992        }
993        
994        // Check lower layers
995        for (lower_mount, lower_node) in &self.overlay_fs.lower_layers {
996            if let Ok(lower_dir_node) = self.overlay_fs.resolve_in_layer(lower_mount, lower_node, &self.path) {
997                if let Ok(lower_fs) = Self::try_fs_from_mount(lower_mount) {
998                    if let Ok(lower_entries) = lower_fs.readdir(&lower_dir_node) {
999                        for entry in lower_entries {
1000                            if entry.name == "." || entry.name == ".." {
1001                                continue; // Skip, already added
1002                            }
1003                            
1004                            // Only add if not already seen (upper layer takes precedence)
1005                            if !seen_names.contains(&entry.name) {
1006                                all_entries.push(crate::fs::DirectoryEntryInternal {
1007                                    name: entry.name.clone(),
1008                                    file_type: entry.file_type,
1009                                    file_id: entry.file_id,
1010                                    size: 0,
1011                                    metadata: None,
1012                                });
1013                                seen_names.insert(entry.name);
1014                            }
1015                        }
1016                    }
1017                }
1018            }
1019        }
1020
1021        // Sort entries by file_id to maintain consistent order
1022        all_entries.sort_by(|a, b| a.file_id.cmp(&b.file_id));
1023        special_entries.extend(all_entries);
1024        Ok(special_entries)
1025    }
1026
1027    /// Safe version of fs_from_mount that returns Result instead of panicking
1028    fn try_fs_from_mount(mount: &Arc<MountPoint>) -> Result<Arc<dyn FileSystemOperations>, FileSystemError> {
1029        let filesystem = mount.root.node().filesystem()
1030            .ok_or_else(|| {
1031                FileSystemError::new(FileSystemErrorKind::BrokenFileSystem, "Mount point has no filesystem")
1032            })?;
1033        
1034        let fs_ops = filesystem.upgrade()
1035            .ok_or_else(|| {
1036                FileSystemError::new(FileSystemErrorKind::BrokenFileSystem, "Filesystem operations are no longer available")
1037            })?;
1038        
1039        Ok(fs_ops)
1040    }
1041}
1042
1043impl StreamOps for OverlayDirectoryObject {
1044    fn read(&self, buffer: &mut [u8]) -> Result<usize, StreamError> {
1045        // Collect all directory entries from all layers (simplified version)
1046        let all_entries = self.collect_directory_entries().map_err(StreamError::from)?;
1047        
1048        let position = *self.position.read() as usize;
1049        
1050        if position >= all_entries.len() {
1051            return Ok(0); // EOF
1052        }
1053        
1054        // Get current entry
1055        let fs_entry = &all_entries[position];
1056        
1057        // Convert to binary format
1058        let dir_entry = crate::fs::DirectoryEntry::from_internal(fs_entry);
1059        
1060        // Calculate actual entry size
1061        let entry_size = dir_entry.entry_size();
1062        
1063        // Check buffer size
1064        if buffer.len() < entry_size {
1065            return Err(StreamError::InvalidArgument); // Buffer too small
1066        }
1067        
1068        // Treat struct as byte array
1069        let entry_bytes = unsafe {
1070            core::slice::from_raw_parts(
1071                &dir_entry as *const _ as *const u8,
1072                entry_size
1073            )
1074        };
1075        
1076        // Copy to buffer
1077        buffer[..entry_size].copy_from_slice(entry_bytes);
1078        
1079        // Move to next entry
1080        *self.position.write() += 1;
1081        
1082        Ok(entry_size)
1083    }
1084    
1085    fn write(&self, _buffer: &[u8]) -> Result<usize, StreamError> {
1086        // Directories cannot be written to directly
1087        Err(StreamError::from(FileSystemError::new(
1088            FileSystemErrorKind::IsADirectory,
1089            "Cannot write to directory"
1090        )))
1091    }
1092}
1093
1094impl FileObject for OverlayDirectoryObject {
1095    fn seek(&self, _whence: crate::fs::SeekFrom) -> Result<u64, StreamError> {
1096        // Seeking in directories not supported for now
1097        Err(StreamError::NotSupported)
1098    }
1099    
1100    fn metadata(&self) -> Result<crate::fs::FileMetadata, StreamError> {
1101        // Get metadata for the directory path
1102        self.overlay_fs.get_metadata_for_path(&self.path).map_err(StreamError::from)
1103    }
1104    
1105    fn truncate(&self, _size: u64) -> Result<(), StreamError> {
1106        Err(StreamError::from(FileSystemError::new(
1107            FileSystemErrorKind::IsADirectory,
1108            "Cannot truncate directory"
1109        )))
1110    }
1111}
1112
1113/// Driver for creating OverlayFS instances
1114///
1115/// This driver implements the FileSystemDriver trait to allow OverlayFS
1116/// to be created through the standard filesystem driver infrastructure.
1117/// Currently, OverlayFS instances are typically created programmatically
1118/// rather than through driver parameters due to the complexity of specifying
1119/// multiple layer mount points.
1120pub struct OverlayFSDriver;
1121
1122impl FileSystemDriver for OverlayFSDriver {
1123    fn create_from_memory(&self, _memory_area: &MemoryArea) -> Result<Arc<dyn FileSystemOperations>, FileSystemError> {
1124        Ok(OverlayFS::create_from_option_string(None, None, Vec::new()))
1125    }
1126
1127    fn create_from_params(&self, _params: &dyn crate::fs::params::FileSystemParams) -> Result<Arc<dyn FileSystemOperations>, FileSystemError> {
1128        Ok(OverlayFS::create_from_option_string(None, None, Vec::new()))
1129    }
1130    
1131    fn name(&self) -> &'static str {
1132        "overlayfs"
1133    }
1134    
1135    fn filesystem_type(&self) -> crate::fs::FileSystemType {
1136        crate::fs::FileSystemType::Virtual
1137    }
1138}
1139
1140/// Register the OverlayFS driver with the filesystem driver manager
1141///
1142/// This function is called during kernel initialization to make the OverlayFS
1143/// driver available for use. It's automatically invoked by the driver_initcall
1144/// mechanism.
1145fn register_driver() {
1146    let fs_driver_manager = get_fs_driver_manager();
1147    fs_driver_manager.register_driver(Box::new(OverlayFSDriver));
1148}
1149
1150driver_initcall!(register_driver);
1151
1152// ========================================================================
1153// Implementation Notes and Usage Examples
1154// ========================================================================
1155//
1156// ## Creating an Overlay
1157//
1158// ```rust,no_run
1159// // Mount base filesystem
1160// let base_fs = create_base_filesystem()?;
1161// vfs.mount(base_fs, "/base", 0)?;
1162//
1163// // Mount overlay filesystem  
1164// let overlay_fs = create_overlay_filesystem()?;
1165// vfs.mount(overlay_fs, "/overlay", 0)?;
1166//
1167// // Create overlay combining them
1168// let (base_mount, base_entry) = vfs.resolve_path("/base")?;
1169// let (overlay_mount, overlay_entry) = vfs.resolve_path("/overlay")?;
1170//
1171// let overlay = OverlayFS::new(
1172//     Some((overlay_mount, overlay_entry)),  // Upper (writable)
1173//     vec![(base_mount, base_entry)],        // Lower (read-only)
1174//     "system_overlay".to_string()
1175// )?;
1176//
1177// vfs.mount(overlay, "/merged", 0)?;
1178// ```
1179//
1180// ## Key Behaviors
1181//
1182// - **Read operations**: Check upper first, then lower layers in order
1183// - **Write operations**: Always go to upper layer (copy-up if needed)
1184// - **Delete operations**: Create whiteout files in upper layer
1185// - **Directory listing**: Merge all layers, respecting whiteouts
1186//
1187// ## Whiteout Files
1188//
1189// To hide `/merged/file.txt`, create `/overlay/.wh.file.txt` in upper layer.
1190// This follows the standard overlay filesystem whiteout convention.
1191//
1192
1193// ========================================================================
1194// Usage Examples - Normal Filesystem Approach
1195// ========================================================================
1196//
1197// ## Example 1: Basic Overlay (Same VFS)
1198//
1199// ```rust,no_run
1200// // Setup base filesystem
1201// let base_fs = crate::fs::vfs_v2::drivers::tmpfs::TmpFS::new(0);
1202// vfs.mount(base_fs, "/base", 0)?;
1203//
1204// // Setup upper filesystem for writes
1205// let upper_fs = crate::fs::vfs_v2::drivers::tmpfs::TmpFS::new(0); 
1206// vfs.mount(upper_fs, "/upper", 0)?;
1207//
1208// // Create overlay combining them - NORMAL FILESYSTEM APPROACH
1209// let overlay = OverlayFS::new_from_paths(
1210//     &vfs,
1211//     Some("/upper"),           // Upper layer (writable)
1212//     vec!["/base"],           // Lower layers (read-only)
1213//     "my_overlay"
1214// )?;
1215//
1216// // Mount like any other filesystem!
1217// vfs.mount(overlay, "/merged", 0)?;
1218// ```
1219//
1220// ## Example 2: Multi-layer Overlay
1221//
1222// ```rust,no_run
1223// // Mount multiple base layers
1224// vfs.mount(system_fs, "/system", 0)?;    // System files
1225// vfs.mount(config_fs, "/config", 0)?;    // Configuration
1226// vfs.mount(overlay_fs, "/overlay", 0)?;  // Overlay workspace
1227//
1228// // Create multi-layer overlay
1229// let overlay = OverlayFS::new_from_paths(
1230//     &vfs,
1231//     Some("/overlay"),         // Writable layer
1232//     vec!["/config", "/system"], // Read-only layers (priority order)
1233//     "container_overlay"
1234// )?;
1235//
1236// // Mount normally
1237// vfs.mount(overlay, "/merged", 0)?;
1238// ```
1239//
1240// ## Benefits of Normal Filesystem Approach
1241//
1242// - **Consistent API**: Uses standard mount()/unmount() operations
1243// - **No special VFS methods**: No need for create_and_mount_overlay() etc.
1244// - **Flexible**: Can be combined with other filesystem operations
1245// - **Maintainable**: Less complexity in VfsManager
1246// - **Testable**: Easy to unit test overlay creation independently
1247//
1248
1249// ========================================================================
1250// Usage Examples - Including Cross-VFS Support
1251// ========================================================================
1252//
1253// ## Example 1: Same-VFS Overlay
1254//
1255// ```rust,no_run
1256// // Setup base filesystem
1257// let base_fs = crate::fs::vfs_v2::drivers::tmpfs::TmpFS::new(0);
1258// vfs.mount(base_fs, "/base", 0)?;
1259//
1260// // Setup upper filesystem for writes
1261// let upper_fs = crate::fs::vfs_v2::drivers::tmpfs::TmpFS::new(0); 
1262// vfs.mount(upper_fs, "/upper", 0)?;
1263//
1264// // Create overlay combining them - NORMAL FILESYSTEM APPROACH
1265// let overlay = OverlayFS::new_from_paths(
1266//     &vfs,
1267//     Some("/upper"),           // Upper layer (writable)
1268//     vec!["/base"],           // Lower layers (read-only)
1269//     "my_overlay"
1270// )?;
1271//
1272// // Mount like any other filesystem!
1273// vfs.mount(overlay, "/merged", 0)?;
1274// ```
1275//
1276// ## Example 2: Cross-VFS Overlay (Container Scenario)
1277//
1278// ```rust,no_run
1279// // Get global VFS with base system
1280// let base_vfs = get_global_vfs_manager();
1281//
1282// // Create container VFS
1283// let container_vfs = VfsManager::new();
1284//
1285// // Mount container-specific filesystems
1286// let overlay_fs = TmpFS::new(0);
1287// container_vfs.mount(overlay_fs, "/overlay", 0)?;
1288//
1289// let config_fs = TmpFS::new(0);
1290// container_vfs.mount(config_fs, "/config", 0)?;
1291//
1292// // Create cross-VFS overlay: base system from global VFS, overlay from container VFS
1293// let overlay = OverlayFS::new_from_paths_and_vfs(
1294//     Some((&container_vfs, "/overlay")),       // Upper in container VFS (writable)
1295//     vec![
1296//         (&container_vfs, "/config"),           // Container config (higher priority)
1297//         (&base_vfs, "/system"),               // Global system files (lower priority)
1298//     ],
1299//     "container_overlay"
1300// )?;
1301//
1302// // Mount in container VFS - completely seamless!
1303// container_vfs.mount(overlay, "/", 0)?;
1304// ```
1305//
1306// ## Example 3: Multi-layer Same-VFS Overlay
1307//
1308// ```rust,no_run
1309// // Mount multiple base layers
1310// vfs.mount(system_fs, "/system", 0)?;    // System files
1311// vfs.mount(config_fs, "/config", 0)?;    // Configuration
1312// vfs.mount(overlay_fs, "/overlay", 0)?;  // Overlay workspace
1313//
1314// // Create multi-layer overlay
1315// let overlay = OverlayFS::new_from_paths(
1316//     &vfs,
1317//     Some("/overlay"),         // Writable layer
1318//     vec!["/config", "/system"], // Read-only layers (priority order)
1319//     "container_overlay"
1320// )?;
1321//
1322// // Mount normally
1323// vfs.mount(overlay, "/merged", 0)?;
1324// ```
1325//
1326// ## Benefits of This Approach
1327//
1328// - **Cross-VFS Support**: Layers can come from different VFS managers
1329// - **Consistent API**: Uses standard mount()/unmount() operations
1330// - **No special VFS methods**: No need for create_and_mount_overlay() etc.
1331// - **Flexible**: Can be combined with other filesystem operations
1332// - **Container-friendly**: Perfect for namespace isolation
1333// - **Maintainable**: Less complexity in VfsManager
1334// - **Testable**: Easy to unit test overlay creation independently
1335//
1336
1337#[cfg(test)]
1338mod tests;