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