Skip to main content

starnix_modules_overlayfs/
lib.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#![recursion_limit = "512"]
6
7use fuchsia_rcu::RcuReadScope;
8use once_cell::sync::OnceCell;
9use rand::Rng;
10use starnix_core::fs::tmpfs::{TmpFs, TmpFsDirectory};
11use starnix_core::mm::memory::MemoryObject;
12use starnix_core::security::{self, PermissionFlags};
13use starnix_core::task::{CurrentTask, Kernel};
14use starnix_core::vfs::fs_args::MountParams;
15use starnix_core::vfs::rw_queue::{RwQueueReadGuard, RwQueueWriteGuard};
16use starnix_core::vfs::{
17    AppendLockWriteGuard, CacheMode, CheckAccessReason, DirEntry, DirEntryHandle,
18    DirectoryEntryType, DirentSink, FallocMode, FileHandle, FileObject, FileOps, FileSystem,
19    FileSystemHandle, FileSystemOps, FileSystemOptions, FsLockDepType, FsNode, FsNodeFlags,
20    FsNodeHandle, FsNodeInfo, FsNodeOps, FsStr, FsString, InputBuffer, MountInfo, OutputBuffer,
21    RenameContext, RenameFlags, SeekTarget, SymlinkTarget, UnlinkKind, ValueOrSize, VecInputBuffer,
22    VecOutputBuffer, XattrOp, default_seek, emit_dotdot, fileops_impl_directory,
23    fileops_impl_noop_sync, fileops_impl_seekable,
24};
25use starnix_logging::{log_error, log_warn, track_stub};
26use starnix_sync::{
27    DynamicLockDepRwLock, FsNodeAppend, LockDepReadGuard, LockDepRwLock, LockDepWriteGuard,
28    OverlayFsDirEntriesLock, OverlayFsStateLock,
29};
30use starnix_uapi::auth::{Credentials, FsCred};
31use starnix_uapi::device_id::DeviceId;
32use starnix_uapi::errors::{EEXIST, ENOENT, Errno};
33use starnix_uapi::file_mode::{FileMode, mode};
34use starnix_uapi::open_flags::OpenFlags;
35use starnix_uapi::{errno, error, ino_t, off_t, statfs};
36use std::collections::BTreeSet;
37use std::sync::Arc;
38use syncio::zxio_node_attr_has_t;
39
40// Name and value for the xattr used to mark opaque directories in the upper FS.
41// See https://docs.kernel.org/filesystems/overlayfs.html#whiteouts-and-opaque-directories
42const OPAQUE_DIR_XATTR: &str = "trusted.overlay.opaque";
43const OPAQUE_DIR_XATTR_VALUE: &str = "y";
44
45#[derive(Clone)]
46struct DirEntryInfo {
47    name: FsString,
48    inode_num: ino_t,
49    entry_type: DirectoryEntryType,
50}
51
52type DirEntries = Vec<DirEntryInfo>;
53
54#[derive(Default)]
55struct DirentSinkAdapter {
56    items: Vec<DirEntryInfo>,
57    offset: off_t,
58}
59
60impl DirentSink for DirentSinkAdapter {
61    fn add(
62        &mut self,
63        inode_num: ino_t,
64        offset: off_t,
65        entry_type: DirectoryEntryType,
66        name: &FsStr,
67    ) -> Result<(), Errno> {
68        if !DirEntry::is_reserved_name(name) {
69            self.items.push(DirEntryInfo { name: name.to_owned(), inode_num, entry_type });
70        }
71        self.offset = offset;
72        Ok(())
73    }
74
75    fn offset(&self) -> off_t {
76        self.offset
77    }
78}
79
80#[derive(Copy, Clone, Eq, PartialEq)]
81enum UpperCopyMode {
82    MetadataOnly,
83    CopyAll,
84}
85
86/// An `DirEntry` associated with the mount options. This is required because OverlayFs mostly
87/// works at the `DirEntry` level (mounts on the lower, upper and work directories are ignored),
88/// but operation must still depend on mount options.
89#[derive(Clone)]
90struct ActiveEntry {
91    entry: DirEntryHandle,
92    mount: MountInfo,
93}
94
95impl ActiveEntry {
96    fn mapper<'a>(entry: &'a ActiveEntry) -> impl Fn(DirEntryHandle) -> ActiveEntry + 'a {
97        |dir_entry| ActiveEntry { entry: dir_entry, mount: entry.mount.clone() }
98    }
99
100    fn entry(&self) -> &DirEntryHandle {
101        &self.entry
102    }
103
104    fn mount(&self) -> &MountInfo {
105        &self.mount
106    }
107
108    fn component_lookup(&self, current_task: &CurrentTask, name: &FsStr) -> Result<Self, Errno> {
109        self.entry()
110            .component_lookup(current_task, self.mount(), name)
111            .map(ActiveEntry::mapper(self))
112    }
113
114    fn create_entry(
115        &self,
116        current_task: &CurrentTask,
117        name: &FsStr,
118        create_node_fn: impl FnOnce(&FsNodeHandle, &MountInfo, &FsStr) -> Result<FsNodeHandle, Errno>,
119    ) -> Result<Self, Errno> {
120        self.entry()
121            .create_entry(current_task, self.mount(), name, create_node_fn)
122            .map(ActiveEntry::mapper(self))
123    }
124
125    /// Sets an xattr to mark the directory referenced by `entry` as opaque. Directories that are
126    /// marked as opaque in the upper FS are not merged with the corresponding directories in the
127    /// lower FS.
128    fn set_opaque_xattr(&self, current_task: &CurrentTask) -> Result<(), Errno> {
129        self.entry().node.set_xattr(
130            current_task,
131            self.mount(),
132            OPAQUE_DIR_XATTR.into(),
133            OPAQUE_DIR_XATTR_VALUE.into(),
134            XattrOp::Set,
135        )
136    }
137
138    /// Checks if the `entry` is marked as opaque.
139    fn is_opaque_node(&self, current_task: &CurrentTask) -> bool {
140        match self.entry().node.get_xattr(
141            current_task,
142            self.mount(),
143            OPAQUE_DIR_XATTR.into(),
144            OPAQUE_DIR_XATTR_VALUE.len(),
145        ) {
146            Ok(ValueOrSize::Value(v)) if v == OPAQUE_DIR_XATTR_VALUE => true,
147            _ => false,
148        }
149    }
150
151    /// Creates a "whiteout" entry in the directory called `name`. Whiteouts are created by
152    /// overlayfs to denote files and directories that were removed and should not be listed in the
153    /// directory. This is necessary because we cannot remove entries from the lower FS.
154    fn create_whiteout(
155        &self,
156        current_task: &CurrentTask,
157        name: &FsStr,
158    ) -> Result<ActiveEntry, Errno> {
159        self.create_entry(current_task, name, |dir, mount, name| {
160            dir.create_node(
161                current_task,
162                mount,
163                name,
164                FileMode::IFCHR,
165                DeviceId::NONE,
166                FsCred::root(),
167            )
168        })
169    }
170
171    /// Returns `true` if this is a "whiteout".
172    fn is_whiteout(&self) -> bool {
173        let info = self.entry().node.info();
174        info.mode.is_chr() && info.rdev == DeviceId::NONE
175    }
176
177    /// Checks whether the child of this entry represented by `info` is a "whiteout".
178    ///
179    /// Only looks up the corresponding `DirEntry` when necessary.
180    fn is_whiteout_child(
181        &self,
182        current_task: &CurrentTask,
183        info: &DirEntryInfo,
184    ) -> Result<bool, Errno> {
185        // We need to lookup the node only if the file is a char device.
186        if info.entry_type != DirectoryEntryType::CHR {
187            return Ok(false);
188        }
189        let entry = self.component_lookup(current_task, info.name.as_ref())?;
190        Ok(entry.is_whiteout())
191    }
192
193    fn read_dir_entries(&self, current_task: &CurrentTask) -> Result<Vec<DirEntryInfo>, Errno> {
194        let mut sink = DirentSinkAdapter::default();
195        self.entry()
196            .open_anonymous(current_task, OpenFlags::DIRECTORY)?
197            .readdir(current_task, &mut sink)?;
198        Ok(sink.items)
199    }
200}
201
202struct OverlayNode {
203    stack: Arc<OverlayStack>,
204
205    // Corresponding `DirEntries` in the lower and the upper filesystems. At least one must be
206    // set. Note that we don't care about `NamespaceNode`: overlayfs overlays filesystems
207    // (i.e. not namespace subtrees). These directories may not be mounted anywhere.
208    // `upper` may be created dynamically whenever write access is required.
209    upper: OnceCell<ActiveEntry>,
210    lower: Option<ActiveEntry>,
211
212    // `prepare_to_unlink()` may mark `upper` as opaque. In that case we want to skip merging
213    // with `lower` in `readdir()`.
214    upper_is_opaque: OnceCell<()>,
215
216    parent: Option<Arc<OverlayNode>>,
217}
218
219impl OverlayNode {
220    fn new(
221        stack: Arc<OverlayStack>,
222        lower: Option<ActiveEntry>,
223        upper: Option<ActiveEntry>,
224        parent: Option<Arc<OverlayNode>>,
225    ) -> Arc<Self> {
226        assert!(upper.is_some() || parent.is_some());
227
228        let upper = match upper {
229            Some(entry) => OnceCell::with_value(entry),
230            None => OnceCell::new(),
231        };
232
233        Arc::new(OverlayNode { stack, upper, lower, upper_is_opaque: OnceCell::new(), parent })
234    }
235
236    fn from_fs_node(node: &FsNodeHandle) -> Result<&Arc<Self>, Errno> {
237        Ok(&node.downcast_ops::<OverlayNodeOps>().ok_or_else(|| errno!(EIO))?.node)
238    }
239
240    fn main_entry(&self) -> &ActiveEntry {
241        self.upper.get().or(self.lower.as_ref()).expect("Expected either upper or lower node")
242    }
243
244    fn init_fs_node_for_child(
245        self: &Arc<OverlayNode>,
246        node: &FsNode,
247        lower: Option<ActiveEntry>,
248        upper: Option<ActiveEntry>,
249    ) -> FsNodeHandle {
250        let entry = upper.as_ref().or(lower.as_ref()).expect("expect either lower or upper node");
251        let ino = entry.entry().node.ino;
252        let info = entry.entry().node.info().clone();
253
254        // Parent may be needed to initialize `upper`. We don't need to pass it if we have `upper`.
255        let parent = if upper.is_some() { None } else { Some(self.clone()) };
256
257        let overlay_node =
258            OverlayNodeOps { node: OverlayNode::new(self.stack.clone(), lower, upper, parent) };
259        FsNode::new_uncached(ino, overlay_node, &node.fs(), info, FsNodeFlags::empty())
260    }
261
262    /// If the file is currently in the lower FS, then promote it to the upper FS. No-op if the
263    /// file is already in the upper FS.
264    fn ensure_upper(
265        &self,
266        current_task: &CurrentTask,
267        fs: &FileSystem,
268    ) -> Result<&ActiveEntry, Errno> {
269        self.ensure_upper_maybe_copy(current_task, UpperCopyMode::CopyAll, fs)
270    }
271
272    /// Same as `ensure_upper()`, but allows to skip copying of the file content.
273    fn ensure_upper_maybe_copy(
274        &self,
275        current_task: &CurrentTask,
276        copy_mode: UpperCopyMode,
277        fs: &FileSystem,
278    ) -> Result<&ActiveEntry, Errno> {
279        self.upper.get_or_try_init(|| {
280            let lower = self.lower.as_ref().expect("lower is expected when upper is missing");
281            let parent = self.parent.as_ref().expect("Parent is expected when upper is missing");
282            let parent_upper = parent.ensure_upper(current_task, fs)?;
283            let name = lower.entry.local_name(&RcuReadScope::new()).to_owned();
284            let info = {
285                let info = lower.entry.node.info();
286                info.clone()
287            };
288            let cred = info.cred();
289
290            let mut copy_up_creds = Credentials::clone(&self.stack.mounter);
291            security::fs_node_copy_up(current_task, &lower.entry.node, fs, &mut copy_up_creds);
292            let res = current_task.override_creds(Arc::new(copy_up_creds), || {
293                if info.mode.is_lnk() {
294                    let link_target = lower.entry.node.readlink(current_task)?;
295                    let link_path = match &link_target {
296                        SymlinkTarget::Node(_) => return error!(EIO),
297                        SymlinkTarget::Path(path) => path,
298                    };
299                    parent_upper.create_entry(current_task, name.as_ref(), |dir, mount, name| {
300                        dir.create_symlink(current_task, mount, name, link_path.as_ref(), cred)
301                    })
302                } else if info.mode.is_reg() && copy_mode == UpperCopyMode::CopyAll {
303                    // Regular files need to be copied from lower FS to upper FS.
304                    self.stack.create_upper_entry(
305                        current_task,
306                        parent_upper,
307                        name.as_ref(),
308                        |dir, name| {
309                            dir.create_entry(current_task, name, |dir_node, mount, name| {
310                                dir_node.create_node(
311                                    current_task,
312                                    mount,
313                                    name,
314                                    info.mode,
315                                    DeviceId::NONE,
316                                    cred,
317                                )
318                            })
319                        },
320                        |entry| copy_file_content(current_task, lower, &entry),
321                    )
322                } else {
323                    parent_upper.create_entry(current_task, name.as_ref(), |dir, mount, name| {
324                        dir.create_node(current_task, mount, name, info.mode, info.rdev, cred)
325                    })
326                }
327            });
328
329            track_stub!(TODO("https://fxbug.dev/322874151"), "overlayfs copy xattrs");
330            res
331        })
332    }
333
334    /// Checks if this node exists in the lower FS.
335    fn has_lower(&self) -> bool {
336        self.lower.is_some()
337    }
338
339    /// Check that an item isn't present in the lower FS.
340    fn lower_entry_exists(&self, current_task: &CurrentTask, name: &FsStr) -> Result<bool, Errno> {
341        match &self.lower {
342            Some(lower) => match lower.component_lookup(current_task, name) {
343                Ok(entry) => Ok(!entry.is_whiteout()),
344                Err(err) if err.code == ENOENT => Ok(false),
345                Err(err) => Err(err),
346            },
347            None => Ok(false),
348        }
349    }
350
351    /// Helper used to create a new entry in the directory. It first checks that the target node
352    /// doesn't exist. Then `do_create` is called to create the new node in the work dir, which
353    /// is then moved to the target dir in the upper file system.
354    ///
355    /// It's assumed that the calling `DirEntry` has the current directory locked, so it is not
356    /// supposed to change while this method is executed. Note that OveralayFS doesn't handle
357    /// the case when the underlying file systems are changed directly, but that restriction
358    /// is not enforced.
359    fn create_entry<F>(
360        self: &Arc<OverlayNode>,
361        node: &FsNode,
362        current_task: &CurrentTask,
363        name: &FsStr,
364        do_create: F,
365    ) -> Result<ActiveEntry, Errno>
366    where
367        F: Fn(&ActiveEntry, &FsStr) -> Result<ActiveEntry, Errno>,
368    {
369        let upper = self.ensure_upper(current_task, &node.fs())?;
370
371        match upper.component_lookup(current_task, name) {
372            Ok(existing) => {
373                // If there is an entry in the upper dir, then it must be a whiteout.
374                if !existing.is_whiteout() {
375                    return error!(EEXIST);
376                }
377            }
378
379            Err(e) if e.code == ENOENT => {
380                // If we don't have the entry in the upper fs, then check lower.
381                if self.lower_entry_exists(current_task, name)? {
382                    return error!(EEXIST);
383                }
384            }
385            Err(e) => return Err(e),
386        };
387
388        self.stack.create_upper_entry(
389            current_task,
390            upper,
391            name,
392            |entry, fs| do_create(entry, fs),
393            |_entry| Ok(()),
394        )
395    }
396
397    /// An overlay directory may appear empty when the corresponding upper dir isn't empty:
398    /// it may contain a number of whiteout entries. In that case the whiteouts need to be
399    /// unlinked before the upper directory can be unlinked as well.
400    /// `prepare_to_unlink()` checks that the directory doesn't contain anything other
401    /// than whiteouts and if that is the case then it unlinks all of them.
402    fn prepare_to_unlink(self: &Arc<OverlayNode>, current_task: &CurrentTask) -> Result<(), Errno> {
403        if self.main_entry().entry().node.is_dir() {
404            let mut lower_entries = BTreeSet::new();
405            if let Some(dir) = &self.lower {
406                for item in dir.read_dir_entries(current_task)?.drain(..) {
407                    if !dir.is_whiteout_child(current_task, &item)? {
408                        lower_entries.insert(item.name);
409                    }
410                }
411            }
412
413            if let Some(dir) = self.upper.get() {
414                let mut to_remove = Vec::<FsString>::new();
415                for item in dir.read_dir_entries(current_task)?.drain(..) {
416                    if !dir.is_whiteout_child(current_task, &item)? {
417                        return error!(ENOTEMPTY);
418                    }
419                    lower_entries.remove(&item.name);
420                    to_remove.push(item.name);
421                }
422
423                if !lower_entries.is_empty() {
424                    return error!(ENOTEMPTY);
425                }
426
427                // Mark the directory as opaque. Children can be removed after this.
428                dir.set_opaque_xattr(current_task)?;
429                let _ = self.upper_is_opaque.set(());
430
431                // Finally, remove the children.
432                for name in to_remove.iter() {
433                    dir.entry().unlink(
434                        current_task,
435                        dir.mount(),
436                        name.as_ref(),
437                        UnlinkKind::NonDirectory,
438                        false,
439                    )?;
440                }
441            }
442        }
443
444        Ok(())
445    }
446
447    fn as_mounter<R, F: FnOnce() -> R>(&self, current_task: &CurrentTask, do_work: F) -> R {
448        current_task.override_creds(self.stack.mounter.clone(), do_work)
449    }
450}
451
452struct OverlayNodeOps {
453    node: Arc<OverlayNode>,
454}
455
456impl FsNodeOps for OverlayNodeOps {
457    fn check_access(
458        &self,
459        node: &FsNode,
460        current_task: &CurrentTask,
461        access: security::PermissionFlags,
462        info: &DynamicLockDepRwLock<FsNodeInfo>,
463        reason: CheckAccessReason,
464        audit_context: security::Auditable<'_>,
465    ) -> Result<(), Errno> {
466        node.default_check_access_impl(current_task, access, reason, info.read(), audit_context)?;
467
468        self.node.as_mounter(current_task, || {
469            if let Some(entry) = self.node.upper.get() {
470                entry.entry.node.check_access(
471                    current_task,
472                    entry.mount(),
473                    access,
474                    reason,
475                    audit_context,
476                )
477            } else {
478                let entry = self.node.lower.as_ref().expect("Either upper or lower node is set");
479                let lower_node = &entry.entry.node;
480
481                // If the lower node is a regular file, directory or symlink then opening it for
482                // write access will cause it to be copied-up, so the mounter only requires read
483                // access to the underlying node.
484                //
485                // If the lower node is "special" (i.e. a device, FIFO or socket) then writes will
486                // affect the underlying resource, so to avoid privilege escalation via overlays,
487                // the mounter is still required to have write access to the node. This works
488                // even if the lower filesystem is readonly because special nodes remain writable
489                // in that case (though they may not be modified or unlinked, which would require
490                // actually writing to the filesystem).
491                let mut access = access;
492                if access.contains(PermissionFlags::WRITE) && !lower_node.info().mode.is_special() {
493                    // Verify that the mounter will be able to write to copy-up the node.
494                    // TODO: https://fxbug.dev/403260093 - Fix this to also verify discretionary
495                    // write access to the mounter, while correctly taking into account the
496                    // `context=` mount option (if any) for the mandatory write access check.
497                    security::fs_node_permission(
498                        current_task,
499                        node,
500                        PermissionFlags::WRITE,
501                        audit_context,
502                    )?;
503
504                    access |= PermissionFlags::READ;
505                    access &= !(PermissionFlags::WRITE | PermissionFlags::APPEND);
506                }
507
508                lower_node.check_access(current_task, &entry.mount, access, reason, audit_context)
509            }
510        })
511    }
512
513    fn create_file_ops(
514        &self,
515        node: &FsNode,
516        current_task: &CurrentTask,
517        flags: OpenFlags,
518    ) -> Result<Box<dyn FileOps>, Errno> {
519        self.node.as_mounter(current_task, || {
520            if flags.can_write() {
521                // Only upper FS can be writable.
522                let copy_mode = if flags.contains(OpenFlags::TRUNC) {
523                    UpperCopyMode::MetadataOnly
524                } else {
525                    UpperCopyMode::CopyAll
526                };
527                self.node.ensure_upper_maybe_copy(current_task, copy_mode, &node.fs())?;
528            }
529
530            let ops: Box<dyn FileOps> = if node.is_dir() {
531                Box::new(OverlayDirectory {
532                    node: self.node.clone(),
533                    dir_entries: Default::default(),
534                })
535            } else {
536                let state = match (self.node.upper.get(), &self.node.lower) {
537                    (Some(upper), _) => {
538                        OverlayFileState::Upper(upper.entry().open_anonymous(current_task, flags)?)
539                    }
540                    (None, Some(lower)) => {
541                        OverlayFileState::Lower(lower.entry().open_anonymous(current_task, flags)?)
542                    }
543                    _ => panic!("Expected either upper or lower node"),
544                };
545
546                Box::new(OverlayFile {
547                    node: self.node.clone(),
548                    flags,
549                    state: LockDepRwLock::new(state),
550                })
551            };
552
553            Ok(ops)
554        })
555    }
556
557    fn lookup(
558        &self,
559        node: &FsNode,
560        current_task: &CurrentTask,
561        name: &FsStr,
562    ) -> Result<FsNodeHandle, Errno> {
563        self.node.as_mounter(current_task, || {
564            let resolve_child = |dir_opt: Option<&ActiveEntry>| {
565                // TODO(sergeyu): lookup() checks access, but we don't need that here.
566                dir_opt
567                    .as_ref()
568                    .map(|dir| match dir.component_lookup(current_task, name) {
569                        Ok(entry) => Some(Ok(entry)),
570                        Err(e) if e.code == ENOENT => None,
571                        Err(e) => Some(Err(e)),
572                    })
573                    .flatten()
574                    .transpose()
575            };
576
577            let upper: Option<ActiveEntry> = resolve_child(self.node.upper.get())?;
578
579            let (upper_is_dir, upper_is_opaque) = match &upper {
580                Some(upper) if upper.is_whiteout() => return error!(ENOENT),
581                Some(upper) => {
582                    let is_dir = upper.entry().node.is_dir();
583                    let is_opaque = !is_dir || upper.is_opaque_node(current_task);
584                    (is_dir, is_opaque)
585                }
586                None => (false, false),
587            };
588
589            let parent_upper_is_opaque = self.node.upper_is_opaque.get().is_some();
590
591            // We don't need to resolve the lower node if we have an opaque node in the upper dir.
592            let lookup_lower = !parent_upper_is_opaque && !upper_is_opaque;
593            let lower: Option<ActiveEntry> = if lookup_lower {
594                match resolve_child(self.node.lower.as_ref())? {
595                    // If the upper node is a directory and the lower isn't then ignore the lower node.
596                    Some(lower) if upper_is_dir && !lower.entry().node.is_dir() => None,
597                    Some(lower) if lower.is_whiteout() => None,
598                    result => result,
599                }
600            } else {
601                None
602            };
603
604            if upper.is_none() && lower.is_none() {
605                return error!(ENOENT);
606            }
607
608            Ok(self.node.init_fs_node_for_child(node, lower, upper))
609        })
610    }
611
612    fn mknod(
613        &self,
614        node: &FsNode,
615        current_task: &CurrentTask,
616        name: &FsStr,
617        mode: FileMode,
618        dev: DeviceId,
619        owner: FsCred,
620    ) -> Result<FsNodeHandle, Errno> {
621        if mode.fmt() == FileMode::IFCHR && dev == DeviceId::NONE {
622            // Callers are blocked from creating character device nodes with Id zero, which would
623            // be indistuinguishable from those created to represent whiteouts.
624            return error!(EPERM);
625        }
626        let mut creds = Credentials::clone(&self.node.stack.mounter);
627        security::dentry_create_files_as(current_task, node, mode, name, &mut creds)?;
628        current_task.override_creds(Arc::new(creds), || {
629            let new_upper_node =
630                self.node.create_entry(node, current_task, name, |dir, temp_name| {
631                    dir.create_entry(current_task, temp_name, |dir_node, mount, name| {
632                        dir_node.create_node(current_task, mount, name, mode, dev, owner.clone())
633                    })
634                })?;
635            Ok(self.node.init_fs_node_for_child(node, None, Some(new_upper_node)))
636        })
637    }
638
639    fn mkdir(
640        &self,
641        node: &FsNode,
642        current_task: &CurrentTask,
643        name: &FsStr,
644        mode: FileMode,
645        owner: FsCred,
646    ) -> Result<FsNodeHandle, Errno> {
647        let mut creds = Credentials::clone(&self.node.stack.mounter);
648        security::dentry_create_files_as(current_task, node, mode, name, &mut creds)?;
649        current_task.override_creds(Arc::new(creds), || {
650            let new_upper_node =
651                self.node.create_entry(node, current_task, name, |dir, temp_name| {
652                    let entry =
653                        dir.create_entry(current_task, temp_name, |dir_node, mount, name| {
654                            dir_node.create_node(
655                                current_task,
656                                mount,
657                                name,
658                                mode,
659                                DeviceId::NONE,
660                                owner.clone(),
661                            )
662                        })?;
663
664                    // Set opaque attribute to ensure the new directory is not merged with lower.
665                    entry.set_opaque_xattr(current_task)?;
666
667                    Ok(entry)
668                })?;
669
670            Ok(self.node.init_fs_node_for_child(node, None, Some(new_upper_node)))
671        })
672    }
673
674    fn create_symlink(
675        &self,
676        node: &FsNode,
677        current_task: &CurrentTask,
678        name: &FsStr,
679        target: &FsStr,
680        owner: FsCred,
681    ) -> Result<FsNodeHandle, Errno> {
682        let mut creds = Credentials::clone(&self.node.stack.mounter);
683        security::dentry_create_files_as(current_task, node, FileMode::IFLNK, name, &mut creds)?;
684        current_task.override_creds(Arc::new(creds), || {
685            let new_upper_node =
686                self.node.create_entry(node, current_task, name, |dir, temp_name| {
687                    dir.create_entry(current_task, temp_name, |dir_node, mount, name| {
688                        dir_node.create_symlink(current_task, mount, name, target, owner.clone())
689                    })
690                })?;
691            Ok(self.node.init_fs_node_for_child(node, None, Some(new_upper_node)))
692        })
693    }
694
695    fn readlink(&self, _node: &FsNode, current_task: &CurrentTask) -> Result<SymlinkTarget, Errno> {
696        self.node
697            .as_mounter(current_task, || self.node.main_entry().entry().node.readlink(current_task))
698    }
699
700    fn link(
701        &self,
702        node: &FsNode,
703        current_task: &CurrentTask,
704        name: &FsStr,
705        child: &FsNodeHandle,
706    ) -> Result<(), Errno> {
707        self.node.as_mounter(current_task, || {
708            let child_overlay = OverlayNode::from_fs_node(child)?;
709            let upper_child = child_overlay.ensure_upper(current_task, &node.fs())?;
710            self.node.create_entry(node, current_task, name, |dir, temp_name| {
711                dir.create_entry(current_task, temp_name, |dir_node, mount, name| {
712                    dir_node.link(current_task, mount, name, &upper_child.entry().node)
713                })
714            })?;
715            Ok(())
716        })
717    }
718
719    fn unlink(
720        &self,
721        node: &FsNode,
722        current_task: &CurrentTask,
723        name: &FsStr,
724        child: &FsNodeHandle,
725    ) -> Result<(), Errno> {
726        self.node.as_mounter(current_task, || {
727            let upper = self.node.ensure_upper(current_task, &node.fs())?;
728            let child_overlay = OverlayNode::from_fs_node(child)?;
729            child_overlay.prepare_to_unlink(current_task)?;
730
731            let need_whiteout = self.node.lower_entry_exists(current_task, name)?;
732            if need_whiteout {
733                self.node.stack.create_upper_entry(
734                    current_task,
735                    &upper,
736                    &name,
737                    |work, name| work.create_whiteout(current_task, name),
738                    |_entry| Ok(()),
739                )?;
740            } else if let Some(child_upper) = child_overlay.upper.get() {
741                let kind = if child_upper.entry().node.is_dir() {
742                    UnlinkKind::Directory
743                } else {
744                    UnlinkKind::NonDirectory
745                };
746                upper.entry().unlink(current_task, upper.mount(), name, kind, false)?;
747            }
748
749            Ok(())
750        })
751    }
752
753    fn fetch_and_refresh_info<'a>(
754        &self,
755        _node: &FsNode,
756        current_task: &CurrentTask,
757        info: &'a DynamicLockDepRwLock<FsNodeInfo>,
758    ) -> Result<LockDepReadGuard<'a, FsNodeInfo>, Errno> {
759        self.node.as_mounter(current_task, || {
760            let underlying_node = &self.node.main_entry().entry().node;
761            // Work-around to ensure that mounter `getattr` access is required when a caller tries
762            // to `stat()` a file.
763            security::check_fs_node_getattr_access(current_task, underlying_node)?;
764            let real_info = underlying_node.fetch_and_refresh_info(current_task)?.clone();
765            let mut lock = info.write();
766            *lock = real_info;
767            Ok(LockDepWriteGuard::downgrade(lock))
768        })
769    }
770
771    // Work-around to allow the append-only writes to proceed without `getattr` access checks,
772    // which `fetch_and_refresh_info()`, above, would otherwise introduce.
773    fn get_size(&self, _node: &FsNode, current_task: &CurrentTask) -> Result<usize, Errno> {
774        self.node
775            .as_mounter(current_task, || self.node.main_entry().entry().node.get_size(current_task))
776    }
777
778    fn update_attributes(
779        &self,
780        node: &FsNode,
781        current_task: &CurrentTask,
782        new_info: &FsNodeInfo,
783        has: zxio_node_attr_has_t,
784    ) -> Result<(), Errno> {
785        self.node.as_mounter(current_task, || {
786            let upper = self.node.ensure_upper(current_task, &node.fs())?.entry();
787            upper.node.update_attributes(current_task, |info| {
788                if has.modification_time {
789                    info.time_modify = new_info.time_modify;
790                }
791                if has.access_time {
792                    info.time_access = new_info.time_access;
793                }
794                if has.mode {
795                    info.mode = new_info.mode;
796                }
797                if has.uid {
798                    info.uid = new_info.uid;
799                }
800                if has.gid {
801                    info.gid = new_info.gid;
802                }
803                if has.rdev {
804                    info.rdev = new_info.rdev;
805                }
806                Ok(())
807            })
808        })
809    }
810
811    fn append_lock_read<'a>(
812        &'a self,
813        node: &'a FsNode,
814        current_task: &CurrentTask,
815    ) -> Result<RwQueueReadGuard<'a, FsNodeAppend>, Errno> {
816        self.node.as_mounter(current_task, || {
817            let upper_node = self.node.ensure_upper(current_task, &node.fs())?.entry.node.as_ref();
818            upper_node.ops().append_lock_read(upper_node, current_task)
819        })
820    }
821
822    fn append_lock_write<'a>(
823        &'a self,
824        node: &'a FsNode,
825        current_task: &CurrentTask,
826    ) -> Result<RwQueueWriteGuard<'a, FsNodeAppend>, Errno> {
827        self.node.as_mounter(current_task, || {
828            let upper_node = self.node.ensure_upper(current_task, &node.fs())?.entry.node.as_ref();
829            upper_node.ops().append_lock_write(upper_node, current_task)
830        })
831    }
832
833    fn truncate(
834        &self,
835        guard: &AppendLockWriteGuard<'_>,
836        node: &FsNode,
837        current_task: &CurrentTask,
838        length: u64,
839    ) -> Result<(), Errno> {
840        self.node.as_mounter(current_task, || {
841            let upper = self.node.ensure_upper(current_task, &node.fs())?;
842
843            upper.entry().node.truncate_locked(guard, current_task, length)
844        })
845    }
846
847    fn allocate(
848        &self,
849        guard: &AppendLockWriteGuard<'_>,
850        node: &FsNode,
851        current_task: &CurrentTask,
852        mode: FallocMode,
853        offset: u64,
854        length: u64,
855    ) -> Result<(), Errno> {
856        self.node.as_mounter(current_task, || {
857            let node = &self.node.ensure_upper(current_task, &node.fs())?.entry().node;
858            node.fallocate_locked(guard, current_task, mode, offset, length)
859        })
860    }
861
862    fn get_xattr(
863        &self,
864        _node: &FsNode,
865        current_task: &CurrentTask,
866        name: &FsStr,
867        max_size: usize,
868    ) -> Result<ValueOrSize<FsString>, Errno> {
869        let entry = self
870            .node
871            .upper
872            .get()
873            .or(self.node.lower.as_ref())
874            .expect("expect either lower or upper node");
875        self.node.as_mounter(current_task, || {
876            entry.entry().node.get_xattr(current_task, &entry.mount, name, max_size)
877        })
878    }
879
880    fn set_xattr(
881        &self,
882        node: &FsNode,
883        current_task: &CurrentTask,
884        name: &FsStr,
885        value: &FsStr,
886        op: XattrOp,
887    ) -> Result<(), Errno> {
888        self.node.as_mounter(current_task, || {
889            let upper = self.node.ensure_upper(current_task, &node.fs())?;
890            upper.entry().node.set_xattr(current_task, &upper.mount, name, value, op)
891        })
892    }
893
894    fn remove_xattr(
895        &self,
896        node: &FsNode,
897        current_task: &CurrentTask,
898        name: &FsStr,
899    ) -> Result<(), Errno> {
900        self.node.as_mounter(current_task, || {
901            let upper = self.node.ensure_upper(current_task, &node.fs())?;
902            upper.entry().node.remove_xattr(current_task, &upper.mount, name)
903        })
904    }
905
906    fn list_xattrs(
907        &self,
908        _node: &FsNode,
909        current_task: &CurrentTask,
910        max_size: usize,
911    ) -> Result<ValueOrSize<Vec<FsString>>, Errno> {
912        self.node.as_mounter(current_task, || {
913            let entry = self
914                .node
915                .upper
916                .get()
917                .or(self.node.lower.as_ref())
918                .expect("expect either lower or upper node");
919            entry.entry().node.list_xattrs(current_task, max_size)
920        })
921    }
922}
923struct OverlayDirectory {
924    node: Arc<OverlayNode>,
925    dir_entries: LockDepRwLock<DirEntries, OverlayFsDirEntriesLock>,
926}
927
928impl OverlayDirectory {
929    fn refresh_dir_entries(&self, current_task: &CurrentTask) -> Result<(), Errno> {
930        let mut entries = DirEntries::new();
931
932        let upper_is_opaque = self.node.upper_is_opaque.get().is_some();
933        let merge_with_lower = self.node.lower.is_some() && !upper_is_opaque;
934
935        // First enumerate entries in the upper dir. Then enumerate the lower dir and add only
936        // items that are not present in the upper.
937        let mut upper_set = BTreeSet::new();
938        if let Some(dir) = self.node.upper.get() {
939            for item in dir.read_dir_entries(current_task)?.drain(..) {
940                // Fill `upper_set` only if we will need it later.
941                if merge_with_lower {
942                    upper_set.insert(item.name.clone());
943                }
944                if !dir.is_whiteout_child(current_task, &item)? {
945                    entries.push(item);
946                }
947            }
948        }
949
950        if merge_with_lower {
951            if let Some(dir) = &self.node.lower {
952                for item in dir.read_dir_entries(current_task)?.drain(..) {
953                    if !upper_set.contains(&item.name)
954                        && !dir.is_whiteout_child(current_task, &item)?
955                    {
956                        entries.push(item);
957                    }
958                }
959            }
960        }
961
962        *self.dir_entries.write() = entries;
963
964        Ok(())
965    }
966}
967
968impl FileOps for OverlayDirectory {
969    fileops_impl_directory!();
970    fileops_impl_noop_sync!();
971
972    fn seek(
973        &self,
974        _file: &FileObject,
975        current_task: &CurrentTask,
976        current_offset: off_t,
977        target: SeekTarget,
978    ) -> Result<off_t, Errno> {
979        self.node
980            .as_mounter(current_task, || default_seek(current_offset, target, || error!(EINVAL)))
981    }
982
983    fn readdir(
984        &self,
985        file: &FileObject,
986        current_task: &CurrentTask,
987        sink: &mut dyn DirentSink,
988    ) -> Result<(), Errno> {
989        self.node.as_mounter(current_task, || {
990            if sink.offset() == 0 {
991                self.refresh_dir_entries(current_task)?;
992            }
993
994            emit_dotdot(file, sink)?;
995
996            for item in self.dir_entries.read().iter().skip(sink.offset() as usize - 2) {
997                sink.add(item.inode_num, sink.offset() + 1, item.entry_type, item.name.as_ref())?;
998            }
999
1000            Ok(())
1001        })
1002    }
1003}
1004
1005enum OverlayFileState {
1006    Lower(FileHandle),
1007    Upper(FileHandle),
1008}
1009
1010impl OverlayFileState {
1011    fn file(&self) -> &FileHandle {
1012        match self {
1013            Self::Lower(f) | Self::Upper(f) => f,
1014        }
1015    }
1016}
1017
1018struct OverlayFile {
1019    node: Arc<OverlayNode>,
1020    flags: OpenFlags,
1021    state: LockDepRwLock<OverlayFileState, OverlayFsStateLock>,
1022}
1023
1024impl FileOps for OverlayFile {
1025    fileops_impl_seekable!();
1026
1027    fn read(
1028        &self,
1029        _file: &FileObject,
1030        current_task: &CurrentTask,
1031        offset: usize,
1032        data: &mut dyn OutputBuffer,
1033    ) -> Result<usize, Errno> {
1034        self.node.as_mounter(current_task, || {
1035            let mut state = self.state.read();
1036
1037            // Check if the file was promoted to the upper FS. In that case we need to reopen it
1038            // from there.
1039            if let Some(upper) = self.node.upper.get() {
1040                if matches!(*state, OverlayFileState::Lower(_)) {
1041                    std::mem::drop(state);
1042
1043                    {
1044                        let mut write_state = self.state.write();
1045
1046                        // TODO(mariagl): don't hold write_state while calling open_anonymous.
1047                        // It may call back into read(), causing lock order inversion.
1048                        *write_state = OverlayFileState::Upper(
1049                            upper.entry().open_anonymous(current_task, self.flags)?,
1050                        );
1051                    }
1052                    state = self.state.read();
1053                }
1054            }
1055
1056            // TODO(mariagl): Drop state here
1057            let file = state.file();
1058            security::file_permission(current_task, &file, security::PermissionFlags::READ)?;
1059            file.ops().read(file, current_task, offset, data)
1060        })
1061    }
1062
1063    fn write(
1064        &self,
1065        _file: &FileObject,
1066        current_task: &CurrentTask,
1067        offset: usize,
1068        data: &mut dyn InputBuffer,
1069    ) -> Result<usize, Errno> {
1070        self.node.as_mounter(current_task, || {
1071            let state = self.state.read();
1072            let file = match &*state {
1073                OverlayFileState::Upper(f) => f.clone(),
1074
1075                // `write()` should be called only for files that were opened for write, and that
1076                // required the file to be promoted to the upper FS.
1077                OverlayFileState::Lower(_) => panic!("write() called for a lower FS file."),
1078            };
1079            std::mem::drop(state);
1080            security::file_permission(current_task, &file, security::PermissionFlags::WRITE)?;
1081            file.ops().write(&file, current_task, offset, data)
1082        })
1083    }
1084
1085    fn sync(&self, _file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
1086        self.node.as_mounter(current_task, || {
1087            let state = self.state.read();
1088            let file = state.file();
1089            file.ops().sync(file, current_task)
1090        })
1091    }
1092
1093    fn get_memory(
1094        &self,
1095        _file: &FileObject,
1096        current_task: &CurrentTask,
1097        length: Option<usize>,
1098        prot: starnix_core::mm::ProtectionFlags,
1099    ) -> Result<Arc<MemoryObject>, Errno> {
1100        self.node.as_mounter(current_task, || {
1101            let state = self.state.read();
1102            let file = state.file();
1103            // Not that the VMO returned here will not updated if the file is promoted to upper FS
1104            // later. This is consistent with OverlayFS behavior on Linux, see
1105            // https://docs.kernel.org/filesystems/overlayfs.html#non-standard-behavior .
1106            file.ops().get_memory(file, current_task, length, prot)
1107        })
1108    }
1109}
1110
1111pub fn new_overlay_fs(
1112    current_task: &CurrentTask,
1113    options: FileSystemOptions,
1114) -> Result<FileSystemHandle, Errno> {
1115    OverlayStack::new_fs(current_task, options)
1116}
1117
1118pub struct OverlayStack {
1119    // Keep references to the underlying file systems to ensure they outlive `overlayfs` since
1120    // they may be unmounted before overlayfs.
1121    #[allow(unused)]
1122    lower_fs: FileSystemHandle,
1123    upper_fs: FileSystemHandle,
1124
1125    work: ActiveEntry,
1126
1127    // Used when interacting with the `upper_fs`, `lower_fs` or `work` directories.
1128    mounter: Arc<Credentials>,
1129}
1130
1131impl OverlayStack {
1132    fn new_fs(
1133        current_task: &CurrentTask,
1134        options: FileSystemOptions,
1135    ) -> Result<FileSystemHandle, Errno> {
1136        match options.params.get("redirect_dir".as_bytes()) {
1137            None => (),
1138            Some(o) if o == "off" => (),
1139            Some(_) => {
1140                track_stub!(TODO("https://fxbug.dev/322874205"), "overlayfs redirect_dir");
1141                return error!(ENOTSUP);
1142            }
1143        }
1144
1145        let lower = resolve_dir_param(current_task, &options.params, "lowerdir".into())?;
1146        let upper = resolve_dir_param(current_task, &options.params, "upperdir".into())?;
1147        let work = resolve_dir_param(current_task, &options.params, "workdir".into())?;
1148
1149        let lower_fs = lower.entry().node.fs();
1150        let upper_fs = upper.entry().node.fs();
1151
1152        if upper_fs.fs_lockdep_type() == FsLockDepType::Recursive {
1153            // Recursive filesystems (like OverlayFS itself) are not supported as upper filesystems.
1154            return error!(EINVAL);
1155        }
1156
1157        if !Arc::ptr_eq(&upper_fs, &work.entry().node.fs()) {
1158            log_error!("overlayfs: upperdir and workdir must be on the same FS");
1159            return error!(EINVAL);
1160        }
1161
1162        let kernel = current_task.kernel();
1163        let mounter = current_task.current_creds().clone();
1164        let stack = Arc::new(OverlayStack { lower_fs, upper_fs, work, mounter });
1165        let root_node = OverlayNode::new(stack.clone(), Some(lower), Some(upper), None);
1166        let fs = FileSystem::new(kernel, CacheMode::Uncached, OverlayFs { stack }, options)?;
1167        let root_ino = fs.allocate_ino();
1168        fs.create_root(root_ino, OverlayNodeOps { node: root_node });
1169        Ok(fs)
1170    }
1171
1172    /// Given a filesystem, wraps it in a tmpfs-backed writable overlayfs.
1173    pub fn wrap_fs_in_writable_layer(
1174        kernel: &Kernel,
1175        rootfs: FileSystemHandle,
1176    ) -> Result<FileSystemHandle, Errno> {
1177        let lower = ActiveEntry { entry: rootfs.root().clone(), mount: MountInfo::detached() };
1178
1179        // Create upper and work directories in an invisible tmpfs.
1180        let invisible_tmp = TmpFs::new_fs(kernel);
1181
1182        let create_directory = |fs: &FileSystemHandle| {
1183            let ino = fs.allocate_ino();
1184            let info = FsNodeInfo::new(mode!(IFDIR, 0o777), FsCred::root());
1185            let node = fs.create_detached_node(ino, TmpFsDirectory::new(), info);
1186            let dir_entry = DirEntry::new(node, None, FsString::default());
1187
1188            // TODO: https://fxbug.dev/455771186 - Revise FsNode initialization to better ensure
1189            // that all the things are appropriately labeled.
1190            security::fs_node_init_with_dentry_deferred(kernel, &dir_entry);
1191
1192            dir_entry
1193        };
1194
1195        let upper =
1196            ActiveEntry { entry: create_directory(&invisible_tmp), mount: MountInfo::detached() };
1197        let work =
1198            ActiveEntry { entry: create_directory(&invisible_tmp), mount: MountInfo::detached() };
1199
1200        let lower_fs = rootfs;
1201        let upper_fs = invisible_tmp;
1202
1203        let mounter = Credentials::root();
1204        let stack = Arc::new(OverlayStack { lower_fs, upper_fs, work, mounter });
1205        let root_node = OverlayNode::new(stack.clone(), Some(lower), Some(upper), None);
1206        let fs = FileSystem::new(
1207            kernel,
1208            CacheMode::Uncached,
1209            OverlayFs { stack },
1210            FileSystemOptions::default(),
1211        )?;
1212        let root_ino = fs.allocate_ino();
1213        fs.create_root(root_ino, OverlayNodeOps { node: root_node });
1214        Ok(fs)
1215    }
1216
1217    // Helper used to create new entry called `name` in `target_dir` in the upper FS.
1218    // 1. Calls `try_create` to create a new entry in `work`. It is called repeateadly with a
1219    //    new name until it returns any result other than `EEXIST`.
1220    // 2. `do_init` is called to initilize the contents and the attributes of the new entry, etc.
1221    // 3. The new entry is moved to `target_dir`. If there is an existing entry called `name` in
1222    //    `target_dir` then it's replaced with the new entry.
1223    // The temp file is cleared from the work dir if either of the last two steps fails.
1224    fn create_upper_entry<FCreate, FInit>(
1225        &self,
1226        current_task: &CurrentTask,
1227        target_dir: &ActiveEntry,
1228        name: &FsStr,
1229        try_create: FCreate,
1230        do_init: FInit,
1231    ) -> Result<ActiveEntry, Errno>
1232    where
1233        FCreate: Fn(&ActiveEntry, &FsStr) -> Result<ActiveEntry, Errno>,
1234        FInit: FnOnce(&ActiveEntry) -> Result<(), Errno>,
1235    {
1236        let mut rng = rand::rng();
1237        let (temp_name, entry) = loop {
1238            let x: u64 = rng.random();
1239            let temp_name = FsString::from(format!("tmp{:x}", x));
1240            match try_create(&self.work, temp_name.as_ref()) {
1241                Err(err) if err.code == EEXIST => continue,
1242                Err(err) => return Err(err),
1243                Ok(entry) => break (temp_name, entry),
1244            }
1245        };
1246
1247        do_init(&entry)
1248            .and_then(|()| {
1249                DirEntry::rename(
1250                    current_task,
1251                    self.work.entry(),
1252                    self.work.mount(),
1253                    temp_name.as_ref(),
1254                    target_dir.entry(),
1255                    target_dir.mount(),
1256                    name,
1257                    RenameFlags::REPLACE_ANY,
1258                )
1259            })
1260            .map_err(|e| {
1261                // Remove the temp entry in case of a failure.
1262                self.work
1263                    .entry()
1264                    .unlink(
1265                        current_task,
1266                        self.work.mount(),
1267                        temp_name.as_ref(),
1268                        UnlinkKind::NonDirectory,
1269                        false,
1270                    )
1271                    .unwrap_or_else(|e| {
1272                        log_error!("Failed to cleanup work dir after an error: {}", e)
1273                    });
1274                e
1275            })?;
1276
1277        Ok(entry)
1278    }
1279}
1280
1281struct OverlayFs {
1282    stack: Arc<OverlayStack>,
1283}
1284
1285impl FileSystemOps for OverlayFs {
1286    fn fs_lockdep_type(&self) -> FsLockDepType {
1287        FsLockDepType::Recursive
1288    }
1289
1290    fn statfs(&self, _fs: &FileSystem, current_task: &CurrentTask) -> Result<statfs, Errno> {
1291        current_task
1292            .override_creds(self.stack.mounter.clone(), || self.stack.upper_fs.statfs(current_task))
1293    }
1294
1295    fn name(&self) -> &'static FsStr {
1296        "overlay".into()
1297    }
1298
1299    fn rename(
1300        &self,
1301        _fs: &FileSystem,
1302        current_task: &CurrentTask,
1303        context: &mut RenameContext<'_>,
1304        old_name: &FsStr,
1305        new_name: &FsStr,
1306    ) -> Result<(), Errno> {
1307        let old_parent = &context.old_parent().node;
1308        let new_parent = &context.new_parent().node;
1309        let renamed = &context.renamed.node;
1310        current_task.override_creds(self.stack.mounter.clone(), || {
1311            let renamed_overlay = OverlayNode::from_fs_node(renamed)?;
1312            if renamed_overlay.has_lower() && renamed_overlay.main_entry().entry().node.is_dir() {
1313                // Return EXDEV for directory renames. Potentially they may be handled with the
1314                // `redirect_dir` feature, but it's not implemented here yet.
1315                // See https://docs.kernel.org/filesystems/overlayfs.html#renaming-directories
1316                return error!(EXDEV);
1317            }
1318            renamed_overlay.ensure_upper(current_task, &renamed.fs())?;
1319
1320            let old_parent_overlay = OverlayNode::from_fs_node(old_parent)?;
1321            let old_parent_upper = old_parent_overlay.ensure_upper(current_task, &renamed.fs())?;
1322
1323            let new_parent_overlay = OverlayNode::from_fs_node(new_parent)?;
1324            let new_parent_upper = new_parent_overlay.ensure_upper(current_task, &renamed.fs())?;
1325
1326            let need_whiteout = old_parent_overlay.lower_entry_exists(current_task, old_name)?;
1327
1328            DirEntry::rename(
1329                current_task,
1330                old_parent_upper.entry(),
1331                old_parent_upper.mount(),
1332                old_name,
1333                new_parent_upper.entry(),
1334                new_parent_upper.mount(),
1335                new_name,
1336                RenameFlags::REPLACE_ANY,
1337            )?;
1338
1339            // If the old node existed in lower FS, then override it in the upper FS with a
1340            // whiteout.
1341            if need_whiteout {
1342                match old_parent_upper.create_whiteout(current_task, old_name) {
1343                    Err(e) => log_warn!("overlayfs: failed to create whiteout for {old_name}: {e}"),
1344                    Ok(_) => (),
1345                }
1346            }
1347
1348            Ok(())
1349        })
1350    }
1351
1352    fn unmount(&self) {}
1353}
1354
1355/// Helper used to resolve directories passed in mount options. The directory is resolved in the
1356/// namespace of the calling process, but only `DirEntry` is returned (detached from the
1357/// namespace). The corresponding file systems may be unmounted before overlayfs that uses them.
1358fn resolve_dir_param(
1359    current_task: &CurrentTask,
1360    params: &MountParams,
1361    name: &FsStr,
1362) -> Result<ActiveEntry, Errno> {
1363    let path = params.get(&**name).ok_or_else(|| {
1364        log_error!("overlayfs: {name} was not specified");
1365        errno!(EINVAL)
1366    })?;
1367
1368    current_task
1369        .open_file(path.as_ref(), OpenFlags::RDONLY | OpenFlags::DIRECTORY)
1370        .map(|f| ActiveEntry { entry: f.name.entry.clone(), mount: f.name.mount.clone() })
1371        .map_err(|e| {
1372            log_error!("overlayfs: Failed to lookup {path}: {}", e);
1373            e
1374        })
1375}
1376
1377/// Copies file content from one file to another.
1378fn copy_file_content(
1379    current_task: &CurrentTask,
1380    from: &ActiveEntry,
1381    to: &ActiveEntry,
1382) -> Result<(), Errno> {
1383    let from_file = from.entry().open_anonymous(current_task, OpenFlags::RDONLY)?;
1384    let to_file = to.entry().open_anonymous(current_task, OpenFlags::WRONLY)?;
1385
1386    security::fs_node_permission(
1387        current_task,
1388        from_file.node().as_ref(),
1389        security::PermissionFlags::READ,
1390        (&**from_file).into(),
1391    )?;
1392    security::fs_node_permission(
1393        current_task,
1394        to_file.node().as_ref(),
1395        security::PermissionFlags::WRITE,
1396        (&**to_file).into(),
1397    )?;
1398
1399    const BUFFER_SIZE: usize = 4096;
1400
1401    let mut read_offset = 0;
1402    let mut write_offset = 0;
1403    loop {
1404        // TODO(sergeyu): Reuse buffer between iterations.
1405
1406        let mut output_buffer = VecOutputBuffer::new(BUFFER_SIZE);
1407        let bytes_read =
1408            from_file.ops().read(&from_file, current_task, read_offset, &mut output_buffer)?;
1409        if bytes_read == 0 {
1410            break;
1411        }
1412        read_offset += bytes_read;
1413
1414        let buffer: Vec<u8> = output_buffer.into();
1415        let mut input_buffer = VecInputBuffer::from(buffer);
1416        while input_buffer.available() > 0 {
1417            write_offset +=
1418                to_file.ops().write(&to_file, current_task, write_offset, &mut input_buffer)?;
1419        }
1420    }
1421
1422    to_file.ops().data_sync(&to_file, current_task)?;
1423
1424    Ok(())
1425}