//
// Syd: rock-solid application kernel
// src/fs.rs: Filesystem utilities
//
// Copyright (c) 2023, 2024, 2025 Ali Polatel <alip@chesswob.org>
// Based in part upon uutils coreutils package's src/lib/features/fs.rs which is:
//   (c) Joseph Crail <jbcrail@gmail.com>
//   (c) Jian Zeng <anonymousknight96 AT gmail.com>
// Tests base based in part upon gnulib packages' tests/test-canonicalize.c which is:
//   (c) Free Software Foundation, Inc.
// {chdir,getdir}_long() functions are based in part upon zsh/Src/compat.c which is:
//   (c) 1992-1997 Paul Falstad
//   SPDX-License-Identifier: ZSH
//
// SPDX-License-Identifier: GPL-3.0

//! Set of functions to manage files and symlinks

use std::{
    borrow::Cow,
    collections::{HashMap, HashSet, VecDeque},
    ffi::CStr,
    fmt,
    fs::{metadata, set_permissions, File},
    hash::Hash,
    io::Write,
    ops::{Deref, RangeInclusive},
    os::{
        fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd},
        unix::{ffi::OsStrExt, fs::PermissionsExt},
    },
    path::Path,
};

use ahash::RandomState;
use bitflags::bitflags;
use btoi::btoi;
use nix::{
    errno::Errno,
    fcntl::{fcntl, FcntlArg, FdFlag, OFlag, OpenHow, ResolveFlag, SealFlag},
    libc::{
        mode_t, DT_BLK, DT_CHR, DT_DIR, DT_FIFO, DT_LNK, DT_REG, DT_SOCK, S_IFBLK, S_IFCHR,
        S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK,
    },
    sched::CloneCb,
    sys::{
        inotify::AddWatchFlags,
        resource::{getrlimit, Resource},
        socket::{
            getsockopt,
            sockopt::{ReceiveTimeout, SendTimeout},
        },
        stat::Mode,
    },
    unistd::{close, dup3, unlinkat, Pid, UnlinkatFlags},
    NixPath,
};
use serde::{ser::SerializeMap, Serialize, Serializer};

use crate::{
    compat::{
        fstatx, getdents64, statx, FileStatx, STATX_INO, STATX_MNT_ID, STATX_MNT_ID_UNIQUE,
        STATX_MODE, STATX_SIZE, STATX_TYPE,
    },
    config::*,
    err::err2no,
    path::{dotdot_with_nul, XPath, XPathBuf, PATH_MAX},
    proc::{proc_fd, proc_tgid},
    sandbox::Flags,
};

/// MFD_CLOEXEC memfd_create(2) flag.
pub const MFD_CLOEXEC: libc::c_uint = libc::MFD_CLOEXEC;
/// MFD_ALLOW_SEALING memfd_create(2) flag.
pub const MFD_ALLOW_SEALING: libc::c_uint = libc::MFD_ALLOW_SEALING;
/// MFD_NOEXEC_SEAL memfd_create(2) flag.
pub const MFD_NOEXEC_SEAL: libc::c_uint = libc::MFD_NOEXEC_SEAL;
/// MFD_EXEC memfd_create(2) flag.
pub const MFD_EXEC: libc::c_uint = libc::MFD_EXEC;

/// Information to uniquely identify a file.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct FileInformation {
    /// Inode number
    pub ino: u64,
    /// Mount id
    pub mnt: u64,
}

impl FileInformation {
    /// Get information for the current working directory.
    pub fn from_cwd() -> Result<Self, Errno> {
        statx::<BorrowedFd, XPath>(None, XPath::empty(), libc::AT_EMPTY_PATH, Self::mask())
            .map(Self::from_statx)
    }

    /// Get information for a given file descriptor.
    pub fn from_fd<F: AsRawFd>(fd: &F) -> Result<Self, Errno> {
        fstatx(fd, Self::mask()).map(Self::from_statx)
    }

    /// Get information for a given link.
    pub fn from_link(path: &XPath) -> Result<Self, Errno> {
        // SAFETY: rootfs, devfs, procfs, and sysfs views must be identical!
        if path.is_rootfs() {
            fstatx(&ROOT_FILE(), Self::mask())
        } else if path.is_devfs() {
            fstatx(&DEV_FILE(), Self::mask())
        } else if path.is_procfs() {
            fstatx(&PROC_FILE(), Self::mask())
        } else if path.is_sysfs() {
            fstatx(&SYS_FILE(), Self::mask())
        } else if path.is_relative() {
            statx::<BorrowedFd, XPath>(None, path, libc::AT_SYMLINK_NOFOLLOW, Self::mask())
        } else if path.is_dev() {
            let base = XPath::from_bytes(&path.as_bytes()[b"/dev/".len()..]);
            statx(
                Some(&DEV_FD()),
                base,
                libc::AT_SYMLINK_NOFOLLOW,
                Self::mask(),
            )
        } else if path.is_proc() {
            let base = XPath::from_bytes(&path.as_bytes()[b"/proc/".len()..]);
            statx(
                Some(&PROC_FD()),
                base,
                libc::AT_SYMLINK_NOFOLLOW,
                Self::mask(),
            )
        } else if path.is_sys() {
            let base = XPath::from_bytes(&path.as_bytes()[b"/sys/".len()..]);
            statx(
                Some(&SYS_FD()),
                base,
                libc::AT_SYMLINK_NOFOLLOW,
                Self::mask(),
            )
        } else {
            let base = XPath::from_bytes(&path.as_bytes()[1..]);
            statx(
                Some(&ROOT_FD()),
                base,
                libc::AT_SYMLINK_NOFOLLOW,
                Self::mask(),
            )
        }
        .map(Self::from_statx)
    }

    /// Get information from a given path.
    pub fn from_path(path: &XPath) -> Result<Self, Errno> {
        // SAFETY: rootfs, devfs, procfs, and sysfs views must be identical!
        if path.is_rootfs() {
            fstatx(&ROOT_FILE(), Self::mask())
        } else if path.is_devfs() {
            fstatx(&DEV_FILE(), Self::mask())
        } else if path.is_procfs() {
            fstatx(&PROC_FILE(), Self::mask())
        } else if path.is_sysfs() {
            fstatx(&SYS_FILE(), Self::mask())
        } else if path.is_relative() {
            statx::<BorrowedFd, XPath>(None, path, 0, Self::mask())
        } else if path.is_dev() {
            let base = XPath::from_bytes(&path.as_bytes()[b"/dev/".len()..]);
            statx(Some(&DEV_FD()), base, 0, Self::mask())
        } else if path.is_proc() {
            let base = XPath::from_bytes(&path.as_bytes()[b"/proc/".len()..]);
            statx(Some(&PROC_FD()), base, 0, Self::mask())
        } else if path.is_sys() {
            let base = XPath::from_bytes(&path.as_bytes()[b"/sys/".len()..]);
            statx(Some(&SYS_FD()), base, 0, Self::mask())
        } else {
            let base = XPath::from_bytes(&path.as_bytes()[1..]);
            statx(Some(&ROOT_FD()), base, 0, Self::mask())
        }
        .map(Self::from_statx)
    }

    /// Convert statx information to FileInformation.
    ///
    /// The statx(2) call must have been called with STATX_INO|STATX_MNT_ID.
    pub fn from_statx(stx: FileStatx) -> Self {
        Self {
            ino: stx.stx_ino,
            mnt: stx.stx_mnt_id,
        }
    }

    #[inline]
    fn mask() -> libc::c_uint {
        let mut mask = STATX_INO;
        mask |= if *HAVE_STATX_MNT_ID_UNIQUE {
            STATX_MNT_ID_UNIQUE
        } else {
            STATX_MNT_ID
        };
        mask
    }
}

bitflags! {
    /// Path canonicalization options
    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    pub struct FsFlags: u16 {
        /// All components of the path must exist.
        /// This is the default.
        /// Without this option, the behaviour is:
        /// Last component may exist, other components must exist.
        /// Conflicts with the option `MISS_LAST`.
        const MUST_PATH = 1 << 0;
        /// Last component must not exist, other components must exist.
        /// Without this option, the default is:
        /// Last component may exist, other components must exist.
        /// Conflicts with the option `MUST_PATH`.
        const MISS_LAST = 1 << 1;
        /// Do not follow symbolic links for the last path component.
        /// Symbolic links for parent components will be resolved.
        const NO_FOLLOW_LAST = 1 << 2;
        /// Do not permit the path resolution to succeed if any
        /// component of the resolution is not a descendant of the
        /// directory indicated by dirfd. This causes absolute symbolic
        /// links (and absolute values of pathname) to be rejected.
        /// Currently, this flag also disables magic-link resolution
        /// (see below). However, this may change in the future.
        /// Therefore, to ensure that magic links are not resolved, the
        /// caller should explicitly specify RESOLVE_NO_MAGICLINKS.
        const RESOLVE_BENEATH = 1 << 3;
        /// Do not resolve symbolic links for any of the path components.
        const NO_RESOLVE_PATH = 1 << 4;
        /// Do not resolve proc magic symbolic links.
        const NO_RESOLVE_PROC = 1 << 5;
        /// Do not traverse through mount points.
        const NO_RESOLVE_XDEV = 1 << 6;
        /// Do not traverse through `..` components.
        const NO_RESOLVE_DOTDOT = 1 << 7;
        /// The return file descriptor should be split to (parent, base),
        /// and a fd to the owning directory should be opened instead.
        ///
        /// Default is to use an `O_PATH` file descriptor directly to the file.
        /// Conflicts with the option `WANT_READ`.
        const WANT_BASE = 1 << 8;
        ///
        /// The return file descriptor should be made read-only.
        ///
        /// Default is to use an `O_PATH` file descriptor.
        /// Conflicts with the option `WANT_BASE`.
        const WANT_READ = 1 << 9;
    }
}

impl Default for FsFlags {
    fn default() -> Self {
        // All components of the path must exist.
        // This is the default.
        Self::MUST_PATH
    }
}

// Controls how missing components should be handled when canonicalizing a path.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum MissingHandling {
    // Last component may exist, other components must exist.
    Normal,

    // All components must exist.
    // Maps to FsFlags::MUST_PATH.
    Existing,

    // Last component must not exist, other componenets must exist.
    // Maps to FsFlags::MISS_LAST.
    Missing,
}

impl From<FsFlags> for MissingHandling {
    fn from(flag: FsFlags) -> Self {
        if flag.contains(FsFlags::MUST_PATH) {
            Self::Existing
        } else if flag.contains(FsFlags::MISS_LAST) {
            Self::Missing
        } else {
            Self::Normal
        }
    }
}

impl FsFlags {
    /// Return `Errno` corresponding to magic link restrictions.
    pub fn magic_errno(&self) -> Errno {
        if self.intersects(Self::RESOLVE_BENEATH | Self::NO_RESOLVE_XDEV) {
            Errno::EXDEV
        } else if self.intersects(Self::NO_RESOLVE_PATH | Self::NO_RESOLVE_PROC) {
            Errno::ELOOP
        } else {
            Errno::EACCES
        }
    }

    /// Return true if symbolic links in last path component should be followed.
    pub fn follow_last(&self) -> bool {
        !self.contains(Self::NO_FOLLOW_LAST)
    }

    /// Return true if symbolic links in path should be resolved.
    pub fn resolve_path(&self) -> bool {
        !self.contains(Self::NO_RESOLVE_PATH)
    }

    /// Return true if magic /proc symbolic links should be resolved.
    pub fn resolve_proc(&self) -> bool {
        !self.intersects(Self::NO_RESOLVE_PROC | Self::NO_RESOLVE_XDEV | Self::RESOLVE_BENEATH)
    }

    /// Return true if the path must exist.
    pub fn must_exist(&self) -> bool {
        self.contains(Self::MUST_PATH)
    }

    /// Return true if the file may be missing.
    pub fn missing(&self) -> bool {
        self.contains(Self::MISS_LAST)
    }
}

impl Serialize for FsFlags {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut flags: Vec<&str> = vec![];

        if self.is_empty() {
            return serializer.collect_seq(flags);
        }

        if self.contains(Self::MUST_PATH) {
            flags.push("must-path");
        }
        if self.contains(Self::MISS_LAST) {
            flags.push("miss-last");
        }
        if self.contains(Self::NO_FOLLOW_LAST) {
            flags.push("no-follow");
        }
        if self.contains(Self::RESOLVE_BENEATH) {
            flags.push("resolve-beneath");
        }
        if self.contains(Self::NO_RESOLVE_PATH) {
            flags.push("no-resolve-path");
        }
        if self.contains(Self::NO_RESOLVE_PROC) {
            flags.push("no-resolve-proc");
        }

        flags.sort();
        serializer.collect_seq(flags)
    }
}

/// This function creates a flock(2) lock.
pub fn flock_fd<F: AsRawFd>(fd: &F, exclusive: bool, wait: bool) -> Result<(), Errno> {
    let fd = fd.as_raw_fd();
    let mut op = if exclusive {
        libc::LOCK_EX
    } else {
        libc::LOCK_SH
    };
    if !wait {
        op |= libc::LOCK_NB;
    }
    // SAFETY: nix deprecated direct flock,
    // and we cannot use the type-safe interface here.
    retry_on_eintr(|| Errno::result(unsafe { libc::flock(fd, op) })).map(drop)
}

/// This function unlocks a flock(2) lock.
pub fn funlock_fd<F: AsRawFd>(fd: &F) -> Result<(), Errno> {
    let fd = fd.as_raw_fd();
    // SAFETY: nix deprecated direct flock,
    // and we cannot use the type-safe interface here.
    retry_on_eintr(|| Errno::result(unsafe { libc::flock(fd, libc::LOCK_UN) })).map(drop)
}

/// This function creates an Open File Description (OFD) lock.
pub fn lock_fd<F: AsRawFd>(fd: &F, write: bool, wait: bool) -> Result<(), Errno> {
    let fd = fd.as_raw_fd();
    #[allow(clippy::cast_possible_truncation)]
    let lock = libc::flock {
        l_type: if write { libc::F_WRLCK } else { libc::F_RDLCK } as i16,
        l_whence: libc::SEEK_SET as i16,
        l_start: 0,
        l_len: 1, // Lock the first byte.
        l_pid: 0, // The kernel sets this value.
    };
    retry_on_eintr(|| {
        fcntl(
            fd,
            if wait {
                FcntlArg::F_OFD_SETLKW(&lock)
            } else {
                FcntlArg::F_OFD_SETLK(&lock)
            },
        )
    })
    .map(drop)
}

/// This function releases an Open File Description (OFD) lock.
pub fn unlock_fd<F: AsRawFd>(fd: &F) -> Result<(), Errno> {
    let fd = fd.as_raw_fd();
    #[allow(clippy::cast_possible_truncation)]
    let lock = libc::flock {
        l_type: libc::F_UNLCK as i16,
        l_whence: libc::SEEK_SET as i16,
        l_start: 0,
        l_len: 1, // Lock the first byte.
        l_pid: 0, // The kernel sets this value.
    };
    retry_on_eintr(|| fcntl(fd, FcntlArg::F_OFD_SETLK(&lock))).map(drop)
}

/// Retries a closure on `EINTR` error.
///
/// This function will call the provided closure, and if the closure
/// returns an `EINTR` error, it will retry the operation until it
/// succeeds or fails with a different error.
#[inline]
pub(crate) fn retry_on_eintr<F, T>(mut f: F) -> Result<T, Errno>
where
    F: FnMut() -> Result<T, Errno>,
{
    loop {
        match f() {
            Err(Errno::EINTR) => continue,
            result => return result,
        }
    }
}

/// Creates an anonymous, non-executable file that lives in memory, and
/// return an owned file-descriptor to it.
pub fn create_memfd(name: &[u8], flags: libc::c_uint) -> Result<OwnedFd, Errno> {
    create_memfd_raw(name, flags).map(|fd| {
        // SAFETY: memfd_create returns a valid FD.
        unsafe { OwnedFd::from_raw_fd(fd) }
    })
}

/// Creates an anonymous, non-executable file that lives in memory, and
/// return a raw file-descriptor to it.
pub fn create_memfd_raw(name: &[u8], flags: libc::c_uint) -> Result<RawFd, Errno> {
    // Ensure the name is at most 255 bytes and null-terminated.
    if name.len() > 255 {
        return Err(Errno::ENAMETOOLONG);
    }
    // SAFETY: ^^ asserts arithmetic below cannot overflow.
    #[allow(clippy::arithmetic_side_effects)]
    let c_name = if name.last() == Some(&0) {
        Cow::Borrowed(name)
    } else {
        let mut c_name = Vec::with_capacity(name.len() + 1);
        c_name.extend_from_slice(name);
        c_name.push(0);
        Cow::Owned(c_name)
    };

    // SAFETY: nix' MemFdCreateFlags don't define MFD_EXEC and MFD_NOEXEC_SEAL yet.
    let fd = unsafe { libc::memfd_create(c_name.as_ptr().cast(), flags | MFD_CLOEXEC) };
    match Errno::result(fd) {
        Ok(fd) => Ok(fd),
        Err(Errno::EINVAL) => {
            // 1. Flags included unknown bits.
            // 2. Name was too long.
            // 3. Both MFD_HUGETLB and MFD_ALLOW_SEALING were
            //    specified in flags.
            // In our case only the first one is relevant and
            // indicates MFD_NOEXEC_SEAL is unsupported. To avoid
            // potential confusion, we return EOPNOTSUPP rather
            // EINVAL than in this case.
            Err(Errno::EOPNOTSUPP)
        }
        Err(errno) => Err(errno),
    }
}

/// Seals the memfd for writing.
pub fn seal_memfd<F: AsRawFd>(fd: &F) -> Result<(), Errno> {
    // Seal memory fd.
    fcntl(
        fd.as_raw_fd(),
        FcntlArg::F_ADD_SEALS(
            SealFlag::F_SEAL_SEAL
                | SealFlag::F_SEAL_WRITE
                | SealFlag::F_SEAL_SHRINK
                | SealFlag::F_SEAL_GROW,
        ),
    )
    .map(drop)
}

/// Sets or clears the append (O_APPEND) flag on a file descriptor.
pub fn set_append<F: AsFd>(fd: &F, state: bool) -> Result<(), Errno> {
    let fd = fd.as_fd().as_raw_fd();
    let flags = fcntl(fd, FcntlArg::F_GETFL)?;

    let mut new_flags = flags;
    if state {
        new_flags |= OFlag::O_APPEND.bits();
    } else {
        new_flags &= !OFlag::O_APPEND.bits();
    }

    fcntl(fd, FcntlArg::F_SETFL(OFlag::from_bits_truncate(new_flags))).map(drop)
}

/// Returns `true` if the given file descriptor is set to non-blocking mode.
pub fn get_nonblock<F: AsFd>(fd: &F) -> Result<bool, Errno> {
    fcntl(fd.as_fd().as_raw_fd(), FcntlArg::F_GETFL).map(|flags| flags & libc::O_NONBLOCK != 0)
}

/// Sets or clears the non-blocking (O_NONBLOCK) flag on a file descriptor.
pub fn set_nonblock<F: AsFd>(fd: &F, state: bool) -> Result<(), Errno> {
    let fd = fd.as_fd().as_raw_fd();
    let flags = fcntl(fd, FcntlArg::F_GETFL)?;

    let mut new_flags = flags;
    if state {
        new_flags |= OFlag::O_NONBLOCK.bits();
    } else {
        new_flags &= !OFlag::O_NONBLOCK.bits();
    }

    fcntl(fd, FcntlArg::F_SETFL(OFlag::from_bits_truncate(new_flags))).map(drop)
}

/// Sets or clears the close-on-exec (FD_CLOEXEC) flag on a file descriptor.
pub fn set_cloexec<Fd: AsRawFd>(fd: &Fd, state: bool) -> Result<(), Errno> {
    let fd = fd.as_raw_fd();
    let flags = fcntl(fd, FcntlArg::F_GETFD)?;

    let mut new_flags = flags;
    if state {
        new_flags |= FdFlag::FD_CLOEXEC.bits();
    } else {
        new_flags &= !FdFlag::FD_CLOEXEC.bits();
    }

    fcntl(fd, FcntlArg::F_SETFD(FdFlag::from_bits_truncate(new_flags))).map(drop)
}

/// Set pipe max size of the given pipe.
pub fn set_pipemax<Fd: AsRawFd>(fd: &Fd, size: libc::c_int) -> Result<usize, Errno> {
    #[allow(clippy::cast_sign_loss)]
    fcntl(fd.as_raw_fd(), FcntlArg::F_SETPIPE_SZ(size)).map(|r| r as usize)
}

/// Check two fds point to the same open file description for the given processes.
pub fn is_same_fd(pid1: Pid, pid2: Pid, fd1: RawFd, fd2: RawFd) -> Result<bool, Errno> {
    const KCMP_FILE: u64 = 0;
    // SAFETY: There's no libc wrapper for kcmp.
    Ok(Errno::result(unsafe {
        libc::syscall(
            libc::SYS_kcmp,
            pid1.as_raw(),
            pid2.as_raw(),
            KCMP_FILE,
            fd1,
            fd2,
        )
    })? == 0)
}

/// Checks if the given file descriptor has a send timeout set.
pub fn has_send_timeout<F: AsFd>(fd: &F) -> Result<bool, Errno> {
    let tv = getsockopt(fd, SendTimeout)?;
    Ok(tv.tv_sec() != 0 || tv.tv_usec() != 0)
}

/// Checks if the given file descriptor has a receive timeout set.
pub fn has_recv_timeout<F: AsFd>(fd: &F) -> Result<bool, Errno> {
    let tv = getsockopt(fd, ReceiveTimeout)?;
    Ok(tv.tv_sec() != 0 || tv.tv_usec() != 0)
}

/// Initializes a new fanotify group.
///
/// This function wraps the `fanotify_init` system call.
///
/// # Arguments
///
/// * `flags` - The flags to control the behavior of the fanotify group.
/// * `event_f_flags` - The file descriptor flags for the event.
///
/// # Returns
///
/// A `Result` containing the file descriptor of the new fanotify group
/// if the operation was successful, or an `Err` containing the `Errno`
/// if it failed.
pub fn fanotify_init(flags: libc::c_uint, event_f_flags: libc::c_uint) -> Result<OwnedFd, Errno> {
    // SAFETY: The `fanotify_init` function is inherently unsafe because
    // it performs a system call that initializes a new fanotify group.
    // We ensure safety by:
    // - Passing valid `flags` and `event_f_flags` arguments as expected
    // by the system call.
    // - Checking the return value of `fanotify_init` for errors and
    // converting it to a safe `Result` type.
    let fd = unsafe { libc::fanotify_init(flags, event_f_flags) };

    if fd >= 0 {
        // SAFETY: fanotify_init returns a valid FD.
        Ok(unsafe { OwnedFd::from_raw_fd(fd) })
    } else {
        Err(Errno::last())
    }
}

/// Marks a file or directory for fanotify.
///
/// This function wraps the `fanotify_mark` system call, always passing
/// a null pointer for the path.
///
/// # Arguments
///
/// * `notify_fd` - The fanotify file descriptor.
/// * `flags`     - The flags to control the behavior of the mark.
/// * `mask`      - The event mask to specify which events to notify on.
/// * `dirfd`     - The file descriptor of the file being marked.
///
/// # Returns
///
/// A `Result` which is `Ok` if the operation was successful, or an
/// `Err` containing the `Errno` if it failed.
pub fn fanotify_mark<F: AsRawFd, P: ?Sized + NixPath>(
    notify_fd: &F,
    flags: libc::c_uint,
    mask: u64,
    dirfd: Option<RawFd>,
    path: Option<&P>,
) -> Result<(), Errno> {
    fn with_opt_nix_path<P, T, F>(p: Option<&P>, f: F) -> Result<T, Errno>
    where
        P: ?Sized + NixPath,
        F: FnOnce(*const libc::c_char) -> T,
    {
        match p {
            Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())),
            None => Ok(f(std::ptr::null())),
        }
    }

    // SAFETY: The `fanotify_mark` function is inherently unsafe
    // because it involves raw pointers and system-level operations.
    // We ensure safety by:
    // - Handling the optional `path` argument using the
    // `with_opt_nix_path` function.
    // - Using `dirfd.unwrap_or(libc::AT_FDCWD)` to provide a
    // default value for `dirfd` if it's `None`.
    // - Checking the return value of `fanotify_mark` for errors and
    // converting it to a safe `Result` type.
    let res = with_opt_nix_path(path, |p| unsafe {
        libc::fanotify_mark(
            notify_fd.as_raw_fd(),
            flags,
            mask,
            dirfd.unwrap_or(libc::AT_FDCWD),
            p,
        )
    })?;

    Errno::result(res).map(drop)
}

/// Wrapper for inotify_add_watch.
pub fn inotify_add_watch<F: AsRawFd, P: ?Sized + NixPath>(
    fd: &F,
    path: &P,
    mask: AddWatchFlags,
) -> Result<libc::c_int, Errno> {
    // SAFETY: We need this because nix' `WatchDescriptor` is opaque...
    let res = path.with_nix_path(|cstr| unsafe {
        libc::inotify_add_watch(fd.as_raw_fd(), cstr.as_ptr(), mask.bits())
    })?;

    Errno::result(res).map(|wd| wd as libc::c_int)
}

/// Returns file mode for the given file descriptor.
/// The file mode includes the file type.
pub fn fd_mode<F: AsRawFd>(fd: &F) -> Result<libc::mode_t, Errno> {
    retry_on_eintr(|| fstatx(fd, STATX_MODE | STATX_TYPE)).map(|statx| statx.stx_mode.into())
}

/// Represents UNIX file types
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum FileType {
    /// Represents regular file
    Reg,
    /// Represents directory
    Dir,
    /// Represents symbolic link
    ///
    /// Optionally, carries with it the symlink path it originates.
    Lnk,
    /// Represents a procfs magic symbolic link
    ///
    /// Carries with it the tid, fd, and symlink path it originates.
    MagicLnk(Pid, RawFd),
    /// Represents FIFO
    Fifo,
    /// Represents socket
    Sock,
    /// Represents character device
    Chr,
    /// Represents block device
    Blk,
    /// Represents unknown file
    Unk,
}

impl Serialize for FileType {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        // SAFETY: Both Lnk and MagicLnk have XPathBuf as saved data,
        // and its Display trait masks control characters.
        let repr = match self {
            Self::Reg => "reg".to_string(),
            Self::Dir => "dir".to_string(),
            Self::Lnk => "lnk".to_string(),
            Self::MagicLnk(pid, fd) => format!("mgc@{}", remote_fd(*pid, *fd)),
            Self::Fifo => "fifo".to_string(),
            Self::Sock => "sock".to_string(),
            Self::Chr => "chr".to_string(),
            Self::Blk => "blk".to_string(),
            Self::Unk => "unk".to_string(),
        };

        serializer.serialize_str(&repr)
    }
}

impl FileType {
    /// Test whether file type represents a regular file.
    pub fn is_file(&self) -> bool {
        *self == Self::Reg
    }

    /// Test whether file type represents a directory.
    pub fn is_dir(&self) -> bool {
        *self == Self::Dir
    }

    /// Test whether file type represents a symlink.
    pub fn is_symlink(&self) -> bool {
        matches!(*self, Self::Lnk)
    }

    /// Test whether file type represents a magic link.
    pub fn is_magic_link(&self) -> bool {
        matches!(self, Self::MagicLnk(_, _))
    }

    /// Test whether file type represents a magic directory.
    ///
    /// SAFETY: Used to harden magic link open calls with O_DIRECTORY.
    pub fn is_magic_dir(&self) -> bool {
        matches!(self, Self::MagicLnk(_, fd) if matches!(*fd, -1 | libc::AT_FDCWD))
    }

    /// Test whether file type represents a block device.
    pub fn is_block_device(&self) -> bool {
        *self == Self::Blk
    }

    /// Test whether file type represents a character device.
    pub fn is_char_device(&self) -> bool {
        *self == Self::Chr
    }

    /// Test whether file type represents a FIFO.
    pub fn is_fifo(&self) -> bool {
        *self == Self::Fifo
    }

    /// Test whether file type represents a socket.
    pub fn is_socket(&self) -> bool {
        *self == Self::Sock
    }

    /// Test whether file type represents an unknown file.
    pub fn is_unknown(&self) -> bool {
        *self == Self::Unk
    }
}

impl From<u8> for FileType {
    fn from(dt_type: u8) -> Self {
        match dt_type {
            DT_DIR => Self::Dir,
            DT_REG => Self::Reg,
            DT_LNK => Self::Lnk,
            DT_CHR => Self::Chr,
            DT_BLK => Self::Blk,
            DT_FIFO => Self::Fifo,
            DT_SOCK => Self::Sock,
            _ => Self::Unk,
        }
    }
}

impl From<mode_t> for FileType {
    fn from(mode: mode_t) -> Self {
        match mode & S_IFMT {
            S_IFBLK => Self::Blk,
            S_IFCHR => Self::Chr,
            S_IFDIR => Self::Dir,
            S_IFIFO => Self::Fifo,
            S_IFLNK => Self::Lnk,
            S_IFREG => Self::Reg,
            S_IFSOCK => Self::Sock,
            _ => Self::Unk,
        }
    }
}

/// Return the file type of the given file descriptor, and optional path.
#[allow(clippy::cast_possible_truncation)]
pub fn file_type<F: AsRawFd>(
    fd: &F,
    p: Option<&XPath>,
    follow_symlinks: bool,
) -> Result<FileType, Errno> {
    if let Some(p) = p {
        statx(
            Some(fd),
            p,
            if p.is_empty() {
                libc::AT_EMPTY_PATH
            } else if follow_symlinks {
                0
            } else {
                libc::AT_SYMLINK_NOFOLLOW
            },
            STATX_TYPE,
        )
    } else {
        fstatx(fd, STATX_TYPE)
    }
    .map(|statx| FileType::from(mode_t::from(statx.stx_mode)))
}

/// Checks if the given file mode represents a sidechannel device.
///
/// A sidechannel device is defined as a character or block device that
/// is world-readable or world-writable. This function checks the file
/// mode to determine if it meets these criteria.
///
/// # Arguments
///
/// * `mode` - The mode of the file to check.
#[inline]
pub fn is_sidechannel_device(mode: libc::mode_t) -> bool {
    mode & (libc::S_IROTH | libc::S_IWOTH) != 0
        && matches!(mode & libc::S_IFMT, libc::S_IFCHR | libc::S_IFBLK)
}

/// Resolve a symbolic link honouring magic proc links.
#[inline]
fn resolve_symlink(
    path: &XPath,
    options: FsFlags,
    filemap: &mut FileMap,
    filetyp: Option<FileType>,
) -> Result<XPathBuf, Errno> {
    if path.is_static() {
        // Static paths are not symlinks.
        return Err(Errno::EINVAL);
    }

    // If we have queried this file before, reuse information.
    let entry = if let Some(entry) = filemap.0.get_mut(path) {
        entry
    } else {
        filemap.open(path, filetyp)?
    };

    if let Some(target) = &entry.target {
        if !options.resolve_path() {
            // RESOLVE_NO_SYMLINKS -> ELOOP
            return Err(Errno::ELOOP);
        }

        if target.is_absolute() && options.contains(FsFlags::RESOLVE_BENEATH) {
            // RESOLVE_BENEATH -> EXDEV
            return Err(Errno::EXDEV);
        }

        // Symbolic link, return target.
        return Ok(target.to_owned());
    } else if !matches!(entry.file_type, None | Some(FileType::MagicLnk(_, _))) {
        // Not a symbolic link, return EINVAL.
        return Err(Errno::EINVAL);
    }

    // All done, resolve symbolic link.
    //
    // ENOENT we get if the file descriptor is not a symlink.
    let target = match readlinkat(Some(&entry.fd), XPath::empty()) {
        Ok(target) => target,
        Err(Errno::EINVAL | Errno::ENOENT) => return Err(Errno::EINVAL),
        Err(errno) => return Err(errno),
    };

    if !options.resolve_path() {
        // RESOLVE_NO_SYMLINKS -> ELOOP
        return Err(Errno::ELOOP);
    }

    if target.is_absolute() && options.contains(FsFlags::RESOLVE_BENEATH) {
        // RESOLVE_BENEATH -> EXDEV
        return Err(Errno::EXDEV);
    }

    // File is known to be a symlink, save target.
    entry.target = Some(target.clone());

    // RESOLVE_NO_MAGICLINKS is handled by proc_fd in canonicalize().
    Ok(target)
}

/// A safe version of clone that returns a PidFD,
/// and therefore is not subject to PID-recycling
/// races.
pub fn safe_clone(
    mut cb: CloneCb,
    stack: &mut [u8],
    flags: libc::c_int,
    signal: Option<libc::c_int>,
) -> Result<OwnedFd, Errno> {
    #[allow(clippy::cast_possible_truncation)]
    extern "C" fn callback(data: *mut CloneCb) -> libc::c_int {
        // SAFETY: nix' version does not support CLONE_PIDFD.
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as libc::c_int
    }

    let mut pid_fd: libc::c_int = -1;
    let combined: libc::c_int = flags | libc::CLONE_PIDFD | signal.unwrap_or(0);
    // SAFETY: ditto.
    #[allow(clippy::missing_transmute_annotations)]
    let res = unsafe {
        let ptr = stack.as_mut_ptr().add(stack.len());
        let ptr_aligned = ptr.sub(ptr as usize % 16);
        libc::clone(
            std::mem::transmute(callback as extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32),
            ptr_aligned as *mut libc::c_void,
            combined,
            std::ptr::addr_of_mut!(cb) as *mut libc::c_void,
            &mut pid_fd,
        )
    };

    Errno::result(res).map(|_| {
        // SAFETY: clone with CLONE_PIDFD returns a valid FD.
        unsafe { OwnedFd::from_raw_fd(pid_fd) }
    })
}

/// Ensure the file we open is a regular file.
/// Ensure we do not block on a fifo if the file is one.
/// Returns (File, FileStatx) on success, Errno on failure.
pub fn safe_open_file<F: AsRawFd>(
    fd: Option<&F>,
    base: &XPath,
) -> Result<(File, FileStatx), Errno> {
    // Step 1: Open the file with O_PATH.
    let fd = safe_open_path(fd, base, OFlag::O_NOFOLLOW)?;

    // Step 2: Check the file type and bail if it's not a regular file.
    let statx = retry_on_eintr(|| fstatx(&fd, STATX_INO | STATX_TYPE | STATX_SIZE))?;
    let ftype = FileType::from(libc::mode_t::from(statx.stx_mode));
    if !ftype.is_file() {
        return Err(Errno::ENOEXEC);
    }

    // Step 3: Reopen the file safely via /proc/self/fd.
    // Note, we cannot use RESOLVE_NO_{MAGIC,SYM}LINKS or O_NOFOLLOW here.
    let mut pfd = XPathBuf::from("self/fd");
    pfd.push_fd(fd.as_raw_fd());

    let flags = OFlag::O_RDONLY | OFlag::O_NOCTTY | OFlag::O_CLOEXEC;

    let fd = safe_open_magicsym(Some(&PROC_FILE()), &pfd, flags).map(File::from)?;

    // Step 4: Return the File and FileStatx.
    Ok((fd, statx))
}

/// Safely open and copy the given pathname into the file,
/// if the pathname exists. Returns the number of bytes copied.
pub fn safe_copy_if_exists<F: Write>(dst: &mut F, src: &XPath) -> Result<u64, Errno> {
    let how = safe_open_how(OFlag::O_PATH);

    // SAFETY: This function is only called before sandboxing.
    #[allow(clippy::disallowed_methods)]
    let fd = if let Ok(fd) = retry_on_eintr(|| {
        nix::fcntl::openat2(libc::AT_FDCWD, src, how).map(|fd|
            // SAFETY: openat2 returns a valid FD.
            unsafe { OwnedFd::from_raw_fd(fd) })
    }) {
        fd
    } else {
        return Ok(0);
    };

    // Check the file type and bail if it's not a regular file.
    let statx = retry_on_eintr(|| fstatx(&fd, STATX_TYPE))?;
    let ftype = FileType::from(libc::mode_t::from(statx.stx_mode));
    if !ftype.is_file() {
        return Err(Errno::ENOEXEC);
    }

    // Reopen the file safely via /proc/self/fd.
    // Note, we cannot use RESOLVE_NO_{MAGIC,SYM}LINKS or O_NOFOLLOW here.
    let mut pfd = XPathBuf::from("/proc/self");
    pfd.push(b"fd");
    pfd.push_fd(fd.as_raw_fd());

    let how = safe_open_how(OFlag::O_RDONLY | OFlag::O_NOCTTY);

    // SAFETY: This function is only called before sandboxing.
    #[allow(clippy::disallowed_methods)]
    let mut src = if let Ok(src) = retry_on_eintr(|| {
        nix::fcntl::openat2(libc::AT_FDCWD, &pfd, how).map(|fd| {
            // SAFETY: openat2 returns a valid FD.
            File::from(unsafe { OwnedFd::from_raw_fd(fd) })
        })
    }) {
        src
    } else {
        return Ok(0);
    };

    #[allow(clippy::disallowed_methods)]
    std::io::copy(&mut src, dst).map_err(|e| err2no(&e))
}

/// Return a safe OpenHow structure.
#[inline]
pub fn safe_open_how(flags: OFlag) -> OpenHow {
    // Note we leave the caller to handle O_NOCTTY,
    // because its use is invalid with O_PATH.
    let mode = if flags.contains(OFlag::O_CREAT) || flags.contains(OFlag::O_TMPFILE) {
        Mode::from_bits_truncate(0o600)
    } else {
        Mode::empty()
    };
    OpenHow::new()
        .flags(flags | OFlag::O_CLOEXEC | OFlag::O_NOFOLLOW)
        .mode(mode)
        .resolve(
            ResolveFlag::RESOLVE_NO_MAGICLINKS
                | ResolveFlag::RESOLVE_NO_SYMLINKS
                | ResolveFlag::RESOLVE_BENEATH,
        )
}

/// Return a safe OpenHow structure without RESOLVE_BENEATH,
/// which allows for absolute pathnames.
pub fn safe_open_how_abs(flags: OFlag) -> OpenHow {
    // Note we leave the caller to handle O_NOCTTY,
    // because its use is invalid with O_PATH.
    let mode = if flags.contains(OFlag::O_CREAT) || flags.contains(OFlag::O_TMPFILE) {
        Mode::from_bits_truncate(0o600)
    } else {
        Mode::empty()
    };
    OpenHow::new()
        .flags(flags | OFlag::O_CLOEXEC | OFlag::O_NOFOLLOW)
        .mode(mode)
        .resolve(ResolveFlag::RESOLVE_NO_MAGICLINKS | ResolveFlag::RESOLVE_NO_SYMLINKS)
}

/// Return a safe OpenHow structure without O_NOFOLLOW,
/// RESOLVE_NO_MAGICLINKS and RESOLVE_NO_SYMLINKS.
#[inline]
pub fn safe_open_how_magicsym(flags: OFlag) -> OpenHow {
    // Note we leave the caller to handle O_NOCTTY,
    // because its use is invalid with O_PATH.
    OpenHow::new().flags(flags | OFlag::O_CLOEXEC)
}

// Return the mount id and file type of a path safely.
#[allow(clippy::cast_possible_truncation)]
fn safe_stat_mount_id(
    path: &XPath,
    filemap: &mut FileMap,
    filetyp: Option<FileType>,
) -> Result<u64, Errno> {
    let mut mask = STATX_TYPE;
    mask |= if *HAVE_STATX_MNT_ID_UNIQUE {
        STATX_MNT_ID_UNIQUE
    } else {
        STATX_MNT_ID
    };

    // If we have queried this file before, reuse information.
    let entry = if let Some(entry) = filemap.0.get_mut(path) {
        entry
    } else {
        filemap.open(path, filetyp)?
    };

    // Return mount id if we've saved it before.
    if let Some(mnt_id) = entry.mnt_id {
        return Ok(mnt_id);
    }

    // All done, fstat the fd of the entry.
    let stx = retry_on_eintr(|| fstatx(&entry.fd, mask))?;

    // Keep magic link information for readlink to consume later.
    if !entry.is_magic_link() {
        let file_type = FileType::from(mode_t::from(stx.stx_mode));
        entry.file_type = Some(file_type);
    }

    // Save and return mount id.
    let mnt_id = stx.stx_mnt_id;
    entry.mnt_id = Some(mnt_id);

    Ok(mnt_id)
}

/// Open a path safely using O_PATH and return an OwnedFd.
pub fn safe_open_path<F: AsRawFd>(
    fd: Option<&F>,
    base: &XPath,
    flags: OFlag,
) -> Result<OwnedFd, Errno> {
    safe_open(fd, base, OFlag::O_PATH | flags)
}

/// Open a path safely and return an OwnedFd.
pub fn safe_open<F: AsRawFd>(fd: Option<&F>, base: &XPath, flags: OFlag) -> Result<OwnedFd, Errno> {
    safe_open_raw(fd, base, flags).map(|fd| {
        // SAFETY: openat2 returns a valid FD.
        unsafe { OwnedFd::from_raw_fd(fd) }
    })
}

/// Open a path safely and return a RawFd.
#[allow(static_mut_refs)]
pub fn safe_open_raw<F: AsRawFd>(
    fd: Option<&F>,
    base: &XPath,
    flags: OFlag,
) -> Result<RawFd, Errno> {
    let how = safe_open_how(flags);

    let (fd, base) = if let Some(fd) = fd {
        (fd.as_raw_fd(), base)
    } else if base.is_relative() {
        (libc::AT_FDCWD, base)
    } else if base.is_rootfs() {
        unreachable!("BUG: Attempt to reopen /");
    } else {
        (ROOT_FD(), XPath::from_bytes(&base.as_bytes()[b"/".len()..]))
    };

    #[allow(clippy::disallowed_methods)]
    retry_on_eintr(|| nix::fcntl::openat2(fd, base, how))
}

/// Open an absolute path safely using O_PATH and return an OwnedFd.
pub fn safe_open_path_abs(path: &XPath, flags: OFlag) -> Result<OwnedFd, Errno> {
    safe_open_abs(path, OFlag::O_PATH | flags)
}

/// Open an absolute path safely and return an OwnedFd.
pub fn safe_open_abs(path: &XPath, flags: OFlag) -> Result<OwnedFd, Errno> {
    let how = safe_open_how_abs(flags);

    // SAFETY: Ensure path is an absolute path.
    if path.is_relative() {
        return Err(Errno::EINVAL);
    }

    #[allow(clippy::disallowed_methods)]
    retry_on_eintr(|| {
        nix::fcntl::openat2(libc::AT_FDCWD, path, how).map(|fd|
                // SAFETY: openat2 returns a valid FD.
                unsafe { OwnedFd::from_raw_fd(fd) })
    })
}

/// Open a magic symlink safely using O_PATH and return an OwnedFd.
pub fn safe_open_path_magicsym<F: AsRawFd>(
    fd: Option<&F>,
    base: &XPath,
    flags: OFlag,
) -> Result<OwnedFd, Errno> {
    safe_open_magicsym(fd, base, flags)
}

/// Open a magic symlink safely and return an OwnedFd.
pub fn safe_open_magicsym<F: AsRawFd>(
    fd: Option<&F>,
    path: &XPath,
    flags: OFlag,
) -> Result<OwnedFd, Errno> {
    safe_open_raw_magicsym(fd, path, flags).map(|fd| {
        // SAFETY: openat2 returns a valid FD.
        unsafe { OwnedFd::from_raw_fd(fd) }
    })
}

/// Open a magic symlink safely and return a RawFd.
#[allow(clippy::disallowed_methods)]
pub fn safe_open_raw_magicsym<F: AsRawFd>(
    fd: Option<&F>,
    path: &XPath,
    flags: OFlag,
) -> Result<RawFd, Errno> {
    let how = safe_open_how_magicsym(flags);

    let (fd, base) = if let Some(fd) = fd {
        (fd.as_raw_fd(), path)
    } else if path.is_rootfs() {
        unreachable!("BUG: Attempt to reopen /");
    } else {
        (ROOT_FD(), XPath::from_bytes(&path.as_bytes()[b"/".len()..]))
    };

    retry_on_eintr(|| nix::fcntl::openat2(fd, base, how))
}

/// Get an extended attribute value.
///
/// # Arguments
/// - `fd`    - The file descriptor of the file.
/// - `name`  - The name of the extended attribute.
/// - `value` - The buffer to store the attribute value,
///   if None do a check run.
///
/// # Returns
/// - `Result<usize>` - The size of the extended attribute value.
///
/// # Errors
/// Returns an error if the operation fails.
///
/// # Safety
/// This function is unsafe as it directly interfaces with the libc function `fgetxattr`.
///
/// # See Also
/// [`fgetxattr`](https://man7.org/linux/man-pages/man2/fgetxattr.2.html)
pub fn fgetxattr<F: AsRawFd, P: ?Sized + NixPath>(
    fd: &F,
    name: &P,
    value: Option<&mut [u8]>,
) -> Result<usize, Errno> {
    let (value, len) = match value {
        Some(v) => (v.as_mut_ptr() as *mut libc::c_void, v.len() as libc::size_t),
        None => (std::ptr::null_mut(), 0),
    };

    // SAFETY: nix lacks a wrapper for fgetxattr.
    let res = name.with_nix_path(|name_ptr| unsafe {
        libc::fgetxattr(fd.as_raw_fd(), name_ptr.as_ptr(), value, len)
    })?;

    #[allow(clippy::cast_sign_loss)]
    if res == -1 {
        Err(Errno::last())
    } else {
        Ok(res as usize)
    }
}

/// Set an extended attribute value.
///
/// # Arguments
/// - `fd`    - The file descriptor of the file.
/// - `name`  - The name of the extended attribute.
/// - `value` - The buffer containing the attribute value.
/// - `flags` - Flags to control the operation.
///
/// # Returns
/// - `Result<()>` - Returns an Ok result if the operation succeeds.
///
/// # Errors
/// Returns an error if the operation fails.
///
/// # Safety
/// This function is unsafe as it directly interfaces with the libc function `fsetxattr`.
///
/// # See Also
/// [`fsetxattr`](https://man7.org/linux/man-pages/man2/fsetxattr.2.html)
pub fn fsetxattr<F: AsRawFd, P: ?Sized + NixPath>(
    fd: &F,
    name: &P,
    value: &[u8],
    flags: i32,
) -> Result<(), Errno> {
    // SAFETY: nix lacks a wrapper for fsetxattr.
    let res = name.with_nix_path(|name_ptr| unsafe {
        libc::fsetxattr(
            fd.as_raw_fd(),
            name_ptr.as_ptr(),
            value.as_ptr() as *const libc::c_void,
            value.len() as libc::size_t,
            flags as libc::c_int,
        )
    })?;

    Errno::result(res).map(drop)
}

/// Remove an extended attribute value.
///
/// # Arguments
/// - `fd`    - The file descriptor of the file.
/// - `name`  - The name of the extended attribute.
///
/// # Returns
/// - `Result<()>` - Returns an Ok result if the operation succeeds.
///
/// # Errors
/// Returns an error if the operation fails.
///
/// # Safety
/// This function is unsafe as it directly interfaces with the libc function `fremovexattr`.
///
/// # See Also
/// [`fremovexattr`](https://man7.org/linux/man-pages/man2/fremovexattr.2.html)
pub fn fremovexattr<F: AsRawFd, P: ?Sized + NixPath>(fd: &F, name: &P) -> Result<(), Errno> {
    // SAFETY: nix lacks a wrapper for fremovexattr.
    let res = name.with_nix_path(|name_ptr| unsafe {
        libc::fremovexattr(fd.as_raw_fd(), name_ptr.as_ptr())
    })?;

    Errno::result(res).map(drop)
}

/// Deny access to user.syd* extended attributes.
/// # Safety
/// Dereferences name after a NULL check.
/// If name is not NULL, it must be a valid NUL-terminated C-String.
/// # Security
/// Denies with ENODATA for stealth.
pub unsafe fn denyxattr(name: *const libc::c_char) -> Result<(), Errno> {
    const SYD_XATTR: &[u8] = b"user.syd.";

    if name.is_null() {
        Ok(())
    } else {
        // SAFETY: The pointer from CStr is guaranteed to be valid and
        // null-terminated.
        if unsafe {
            libc::strncmp(
                name,
                SYD_XATTR.as_ptr() as *const libc::c_char,
                SYD_XATTR.len(),
            )
        } == 0
        {
            Err(Errno::ENODATA)
        } else {
            Ok(())
        }
    }
}

/// Filters out extended attribute names that start with "user.syd".
///
/// # Arguments
///
/// * `buf` - A buffer containing the extended attribute names as
///   null-terminated strings.
/// * `n` - The length of valid data in the buffer.
pub fn filterxattr(buf: &[u8], n: usize) -> Result<Vec<u8>, Errno> {
    let mut filtered_buf = Vec::new();
    let mut start = 0;

    #[allow(clippy::arithmetic_side_effects)]
    while start < n {
        if let Some(end) = buf[start..].iter().position(|&c| c == 0) {
            let name = &buf[start..start + end + 1]; // +1 to include the null terminator
            let cstr = CStr::from_bytes_with_nul(name).or(Err(Errno::E2BIG))?;
            if !cstr.to_bytes().starts_with(b"user.syd.") {
                filtered_buf.extend_from_slice(name);
            }
            start += end + 1;
        } else {
            break;
        }
    }

    Ok(filtered_buf)
}

/// Get secure bytes using the OS random number generator.
pub fn getrandom(size: usize) -> Result<Vec<u8>, Errno> {
    let mut buf = Vec::new();
    if buf.try_reserve(size).is_err() {
        return Err(Errno::ENOMEM);
    }

    fillrandom(&mut buf)?;
    Ok(buf)
}

/// Fill the given buffer using the OS random number generator.
pub fn fillrandom(buf: &mut [u8]) -> Result<(), Errno> {
    // libc crate does not define getentropy(3) for musl yet!
    #[link(name = "c")]
    extern "C" {
        #[link_name = "getentropy"]
        fn ffi_getentropy(buffer: *mut u8, length: usize) -> i32;
    }

    // getentropy(3) mandates that 'length' must not exceed 256.
    if buf.len() > 256 {
        return Err(Errno::EINVAL);
    }

    // SAFETY: We pass a valid pointer (buf.as_mut_ptr()) and a length (buf.len())
    // for a slice that is in scope and never exceeds 256 bytes.
    Errno::result(unsafe { ffi_getentropy(buf.as_mut_ptr(), buf.len()) }).map(drop)
}

/// Return a random `u64` within the given inclusive range using the OS random number generator.
#[allow(clippy::arithmetic_side_effects)]
pub fn randint(range: RangeInclusive<u64>) -> Result<u64, Errno> {
    let (start, end) = range.into_inner();

    if start > end {
        return Err(Errno::ERANGE);
    }

    let mut buf = [0u8; std::mem::size_of::<u64>()];
    fillrandom(&mut buf)?;

    Ok(start + (u64::from_le_bytes(buf) % (end - start + 1)))
}

/// Duplicate the file descriptor to a random fd.
#[allow(clippy::arithmetic_side_effects)]
pub fn duprand(fd: RawFd) -> Result<RawFd, Errno> {
    let range_start = 7u64;
    let (range_end, _) = getrlimit(Resource::RLIMIT_NOFILE)?;
    #[allow(clippy::unnecessary_cast)]
    let range_end = range_end.saturating_sub(1) as u64;

    // SAFETY: Cap to a sane maximum because
    // sufficiently big values of the hard limit
    // tend to return ENOMEM.
    let range_end = range_end.min(0x10000);

    if range_end <= range_start {
        return Err(Errno::EMFILE);
    }

    let range = range_start..=range_end;

    // SAFETY: To make this file descriptor harder to spot by an
    // attacker we duplicate it to a random fd number.
    for _ in range.clone() {
        let fd_rand = randint(range.clone())? as RawFd;

        // Check if the slot is free.
        // This is arguably subject to race but
        // since this is solely used for fds at
        // startup, we dont really care.
        if fcntl(fd_rand, FcntlArg::F_GETFD) != Err(Errno::EBADF) {
            continue;
        }

        match retry_on_eintr(|| dup3(fd, fd_rand, OFlag::O_CLOEXEC)) {
            Ok(_) => return Ok(fd_rand),
            Err(Errno::EMFILE) => return Err(Errno::EMFILE),
            Err(_) => {}
        }
    }

    Err(Errno::EBADF)
}

/// Return a random unprivileged port number using the OS random number
/// generator.
#[allow(clippy::cast_possible_truncation)]
#[inline]
pub fn randport() -> Result<u16, Errno> {
    randint(1025..=0xFFFF).map(|port| port as u16)
}

/// Create a unique temporary file in `dirfd` relative to `prefix`
/// unlink the file and return its file descriptor. Unlike libc's
/// mkstemp(3) function the template here does not have to end with any
/// number of `X` characters. The function appends an implementation
/// defined number of random characters after `prefix`. `prefix` must
/// not start with the `/` character and not be longer than `libc::PATH_MAX`
/// characters long. It is OK for prefix to be empty.
pub fn mkstempat<F: AsRawFd>(dirfd: &F, prefix: &XPath) -> Result<RawFd, Errno> {
    const MAX_TCOUNT: usize = 8;
    const SUFFIX_LEN: usize = 128;
    const CHARSET: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._-";

    if prefix.is_absolute() {
        return Err(Errno::EINVAL);
    } else if prefix.len().saturating_sub(SUFFIX_LEN) > PATH_MAX {
        return Err(Errno::ENAMETOOLONG);
    }

    let mut attempts = 0;
    let mut rng_data = [0u8; SUFFIX_LEN];
    #[allow(clippy::arithmetic_side_effects)]
    loop {
        attempts += 1;
        if attempts > MAX_TCOUNT {
            // Too many collisions.
            return Err(Errno::EEXIST);
        }

        // Fill with random bytes.
        fillrandom(&mut rng_data)?;

        // Map bytes to characters.
        let mut base = XPathBuf::with_capacity(prefix.len() + SUFFIX_LEN);
        base.append_bytes(prefix.as_bytes());
        for &b in &rng_data {
            base.append_byte(CHARSET[(b as usize) % CHARSET.len()]);
        }

        match safe_open_raw(
            Some(dirfd),
            &base,
            OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_RDWR,
        ) {
            Ok(fd) => {
                unlinkat(Some(dirfd.as_raw_fd()), &base, UnlinkatFlags::NoRemoveDir)?;
                return Ok(fd);
            }
            Err(Errno::EEXIST) => {
                // Try again with a new random sequence.
                continue;
            }
            Err(errno) => return Err(errno),
        }
    }
}

/// Check if the given File is executable.
pub(crate) fn is_executable<F: AsRawFd>(file: &F) -> bool {
    // SAFETY: Our nix version does not have AtFlags::AT_EACCES (TODO).
    Errno::result(unsafe {
        libc::faccessat(
            file.as_raw_fd(),
            c"".as_ptr().cast(),
            libc::X_OK,
            libc::AT_EACCESS | libc::AT_EMPTY_PATH,
        )
    })
    .map(drop)
    .is_ok()
}

/// Parse a FD from a Path.
#[inline]
pub(crate) fn parse_fd(path: &XPath) -> Result<RawFd, Errno> {
    btoi::<RawFd>(path.as_bytes()).or(Err(Errno::EBADF))
}

/// Read a symbolic link and return a `XPathBuf`.
// TODO: Move to compat.rs
pub fn readlinkat<F: AsRawFd>(fd: Option<&F>, base: &XPath) -> Result<XPathBuf, Errno> {
    nix::fcntl::readlinkat(fd.map(|fd| fd.as_raw_fd()), base).map(XPathBuf::from)
}

/// Create file and write the given content.
#[allow(clippy::disallowed_methods)]
pub fn cat<P: AsRef<Path>, T: AsRef<[u8]>>(path: P, content: T) -> std::io::Result<()> {
    let mut file = File::create(path)?;
    file.write_all(content.as_ref())?;
    Ok(())
}

/// Make a file executable.
pub fn chmod_x<P: AsRef<Path>>(path: P) -> std::io::Result<()> {
    // Set permissions to make path executable.
    let metadata = metadata(path.as_ref())?;
    let mut permissions = metadata.permissions();
    permissions.set_mode(0o700); // This sets the file executable for the owner (rwx).
    set_permissions(path.as_ref(), permissions)
}

#[derive(Debug, PartialEq)]
enum PathComponent {
    //We handle {Root,Cur}Dir transparently for efficiency.
    //RootDir,
    //CurDir,
    ParentDir,
    Normal(XPathBuf),
}

impl Serialize for PathComponent {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        // SAFETY: Convert to XPath to mask control characters in log output.
        let comp = match self {
            Self::Normal(p) => p.to_owned(),
            Self::ParentDir => XPathBuf::from(".."),
        };

        serializer.serialize_str(&comp.to_string())
    }
}

/// Generates a VecDeque of path components, optimized for performance and correctness.
/// - Assumes handling of the initial RootDir is done by the caller.
/// - Directly walks the path bytes to construct components, efficiently skipping multiple leading slashes.
/// - Returns an additional bool to check for trailing slash.
#[inline]
fn path_components(path: &XPath) -> Result<(VecDeque<PathComponent>, bool), Errno> {
    // Create a new searcher for the '/' character.
    let searcher = memchr::arch::all::memchr::One::new(b'/');

    let path_bytes = path.as_os_str().as_bytes();

    let mut components = VecDeque::new();
    let comp_count = searcher.iter(path_bytes).count().min(PATH_MAX_COMP);
    components.try_reserve(comp_count).or(Err(Errno::ENOMEM))?;

    let mut start = 0;
    #[allow(clippy::arithmetic_side_effects)]
    for pos in searcher.iter(path_bytes) {
        if pos > start {
            match &path_bytes[start..pos] {
                b"." => {} // Skip current directory component.
                b".." => components.push_back(PathComponent::ParentDir),
                component => {
                    if component.len() >= PATH_MAX {
                        return Err(Errno::ENAMETOOLONG);
                    }
                    components.push_back(PathComponent::Normal(component.into()));
                }
            }
        }
        start = pos + 1; // Move past the '/'.
    }

    // Handle the last component if it's not ended by a slash.
    #[allow(clippy::arithmetic_side_effects)]
    let slash = if start < path_bytes.len() {
        match &path_bytes[start..] {
            b"." => {
                // Skip current directory component.
                components.is_empty() || (start >= 1 && path_bytes[start - 1] == b'/')
            }
            b".." => {
                components.push_back(PathComponent::ParentDir);
                true
            }
            component => {
                if component.len() >= PATH_MAX {
                    return Err(Errno::ENAMETOOLONG);
                }
                components.push_back(PathComponent::Normal(component.into()));
                false
            }
        }
    } else {
        true
    };

    Ok((components, slash))
}

/// Adds to a VecDeque of (owning) path components, optimized for performance and correctness.
/// - Assumes handling of the initial RootDir is done by the caller.
/// - Directly walks the path bytes to construct components, efficiently skipping multiple leading slashes.
#[inline]
fn path_components2(path: &XPath, components: &mut VecDeque<PathComponent>) -> Result<(), Errno> {
    let path_bytes = path.as_os_str().as_bytes();

    // Create a new searcher for the '/' character.
    let searcher = memchr::arch::all::memchr::One::new(b'/');

    let mut last_pos = path_bytes.len();
    let mut last_component = true;
    #[allow(clippy::arithmetic_side_effects)]
    for pos in searcher.iter(path_bytes).rev() {
        match &path_bytes[pos + 1..last_pos] {
            b"" | b"." => {} // Skip current directory and empty components.
            b".." => {
                components.try_reserve(1).or(Err(Errno::ENOMEM))?;
                components.push_front(PathComponent::ParentDir);
            }
            component => {
                let mut component: XPathBuf = component.into();
                if last_component && path.ends_with(b"/") {
                    component.append_byte(b'/');
                }
                last_component = false;

                components.try_reserve(1).or(Err(Errno::ENOMEM))?;
                components.push_front(PathComponent::Normal(component));
            }
        }
        last_pos = pos;
    }

    // Handle the remaining component before the first slash (or the
    // only component if no slashes).
    match &path_bytes[..last_pos] {
        b"" | b"." => {} // Skip current directory and empty components.
        b".." => {
            components.try_reserve(1).or(Err(Errno::ENOMEM))?;
            components.push_front(PathComponent::ParentDir);
        }
        component => {
            let mut component: XPathBuf = component.into();
            if last_component && path.ends_with(b"/") {
                component.append_byte(b'/');
            }

            components.try_reserve(1).or(Err(Errno::ENOMEM))?;
            components.push_front(PathComponent::Normal(component));
        }
    }

    Ok(())
}

/// Gets current working directory handling arbitrarily long pathnames.
///
/// Safety: This function does not change the current working directory.
#[allow(clippy::arithmetic_side_effects)]
pub fn getdir_long(fd: RawFd, max_components: usize) -> Result<XPathBuf, Errno> {
    // Record information on current directory.
    let mut pinfo = FileInformation::from_fd(&fd)?;

    let mut dir = fd;
    let mut cwd = Vec::new();
    cwd.try_reserve(PATH_MAX).or(Err(Errno::ENOMEM))?;

    let flags = (OFlag::O_RDONLY
        | OFlag::O_CLOEXEC
        | OFlag::O_DIRECTORY
        | OFlag::O_LARGEFILE
        | OFlag::O_NOCTTY
        | OFlag::O_NOFOLLOW)
        .bits();

    let mut i = 0;
    while i < max_components {
        // Move one directory level up.
        let fd = retry_on_eintr(|| {
            // SAFETY: We do confine the string pointer here, so we cannot use nix.
            Errno::result(unsafe {
                libc::openat(dir, dotdot_with_nul() as *const libc::c_char, flags, 0)
            })
        })
        .map(|fd| fd as RawFd)?;
        if i > 0 {
            let _ = close(dir);
        }
        dir = fd;

        let info = FileInformation::from_fd(&dir)?;
        if info == pinfo {
            // Current file information and parent are the same:
            // We have reached the root directory.
            if i > 0 {
                let _ = close(dir);
            }

            let cwd = if !cwd.is_empty() {
                // Re-reverse the path and return.
                cwd.reverse();
                cwd.into()
            } else {
                // LOL: This was rootfs to begin with!
                XPathBuf::from("/")
            };
            return Ok(cwd);
        }

        let mut dot = 0u8;
        let mut found = false;
        let new_device = info.mnt != pinfo.mnt;
        'main: loop {
            let mut entries = match getdents64(&dir, 0x10000) {
                Ok(entries) => entries,
                Err(Errno::UnknownErrno) => break,
                Err(errno) => return Err(errno),
            };

            for entry in &mut entries {
                if dot < 2 && entry.is_dot() {
                    dot += 1;
                    continue;
                } else if !new_device && entry.ino() != pinfo.ino {
                    // This is not our directory entry, continue.
                    continue;
                } else if pinfo
                    != statx(
                        Some(&dir),
                        entry.as_xpath(),
                        libc::AT_SYMLINK_NOFOLLOW,
                        FileInformation::mask(),
                    )
                    .map(FileInformation::from_statx)?
                {
                    // This is not our directory entry as verified by device & inode check.
                    continue;
                }

                // Found our entry!
                found = true;

                // Record parent information.
                pinfo = info;

                // Push the name reversed,
                // we'll re-reverse at the end.
                cwd.try_reserve(entry.name_bytes().len().saturating_add(1))
                    .or(Err(Errno::ENOMEM))?;
                cwd.extend(entry.name_bytes().iter().rev());
                cwd.push(b'/');

                break 'main;
            }
        }

        if found {
            i += 1;
        } else {
            if i > 0 {
                let _ = close(dir);
            }
            return Err(Errno::ENOENT);
        }
    }

    if i > 0 {
        let _ = close(dir);
    }

    Err(Errno::ERANGE)
}

/// An enum that may either be an OwnedFd or BorrowedFd.
pub enum MaybeFd {
    /// An `OwnedFd` which will be closed when `MaybeFd` is closed.
    Owned(OwnedFd),
    /// A `RawFd` that will remain open at least as long as `MaybeFd`.
    RawFd(RawFd),
}

impl Clone for MaybeFd {
    fn clone(&self) -> Self {
        match self {
            MaybeFd::Owned(fd) => MaybeFd::RawFd(fd.as_raw_fd()),
            MaybeFd::RawFd(fd) => MaybeFd::RawFd(*fd),
        }
    }
}

impl AsRawFd for MaybeFd {
    fn as_raw_fd(&self) -> RawFd {
        match self {
            MaybeFd::Owned(owned) => owned.as_raw_fd(),
            MaybeFd::RawFd(fd) => *fd,
        }
    }
}

impl From<OwnedFd> for MaybeFd {
    fn from(fd: OwnedFd) -> Self {
        MaybeFd::Owned(fd)
    }
}

impl From<RawFd> for MaybeFd {
    fn from(fd: RawFd) -> Self {
        MaybeFd::RawFd(fd)
    }
}

impl fmt::Debug for MaybeFd {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            MaybeFd::Owned(_) => f.debug_tuple("OwnedFd").field(&self.as_raw_fd()).finish(),
            MaybeFd::RawFd(_) => f.debug_tuple("RawFd").field(&self.as_raw_fd()).finish(),
        }
    }
}

#[derive(Debug)]
pub(crate) struct FileMapEntry {
    fd: MaybeFd,
    file_type: Option<FileType>,
    mnt_id: Option<u64>,
    target: Option<XPathBuf>,
}

struct FileMap(HashMap<XPathBuf, FileMapEntry, RandomState>);

impl FileMapEntry {
    pub(crate) fn new(
        fd: MaybeFd,
        file_type: Option<FileType>,
        mnt_id: Option<u64>,
        target: Option<XPathBuf>,
    ) -> Self {
        Self {
            fd,
            file_type,
            mnt_id,
            target,
        }
    }

    #[allow(clippy::cognitive_complexity)]
    fn from_raw_fd(pid: Pid, fd: RawFd, want_dir: bool) -> Result<(Self, XPathBuf), Errno> {
        // Create path to symlink.
        let sym = remote_fd(pid, fd);

        // Step 1: Try to readlink().
        let (target, is_deleted) = match readlinkat(Some(&PROC_FILE()), &sym) {
            Ok(p) => {
                if p.is_relative() {
                    // /proc/1/fd/42 -> pipe:[4242], socket:[4242]
                    if want_dir {
                        return Err(Errno::EBADF);
                    } else if matches!(fd, -1 | libc::AT_FDCWD) {
                        // /proc/$pid/{cwd,root}
                        // This can never happen.
                        return Err(Errno::ENOTDIR);
                    }

                    // Magic link points to magic path.
                    // Paths such as [pipe:64], [socket:42] etc.
                    // 1. /proc/$pid/exe
                    // 2. /proc/$pid/fd/$fd
                    (Some(p), false)
                } else if p.ends_with(b" (deleted)") {
                    // /proc/1/cwd -> /path/to/foo (deleted)
                    //
                    // This may be a deleted directory, or a directory
                    // whose name funnily ends with a genuine " (deleted)"
                    // string. getdir_long is going to find out for sure.
                    (None, true)
                } else {
                    // Genuine file descriptor that points to a valid directory.
                    (Some(p), false)
                }
            }
            Err(Errno::ENOENT) => return Err(Errno::EBADF),
            Err(Errno::ENAMETOOLONG) => (None, false),
            Err(errno) => return Err(errno),
        };

        // Step 2: Open directory using the magic symlink.
        let flags = if want_dir {
            OFlag::O_PATH | OFlag::O_DIRECTORY
        } else {
            OFlag::O_PATH
        };

        let remote_fd = fd;
        let fd = safe_open_magicsym(Some(&PROC_FILE()), &sym, flags)?;

        if let Some(target) = target {
            // We managed to successfully readlink,
            // and open the magic symlink, return.
            let file_type = if want_dir {
                Some(FileType::Dir)
            } else {
                file_type(&fd, None, false).ok()
            };

            let entry = Self {
                fd: fd.into(),
                file_type,
                mnt_id: None,
                target: Some(target),
            };

            return Ok((entry, sym));
        }

        // Step 3: Use getdir_long().

        // SAFETY:
        // 1. getdir_long() does not change CWD!
        // 2. We limit maximum dir components to PATH_MAX_COMP so the
        //    sandbox process cannot create arbitrarily long directories
        //    and crash Syd.
        let target = match getdir_long(fd.as_raw_fd(), PATH_MAX_COMP) {
            Ok(path) => path,
            Err(Errno::ENOENT | Errno::ENOTDIR) if is_deleted => {
                // SAFETY: /proc fd symlink refers to a
                // deleted filesystem path.
                let mut sym = XPathBuf::from("/proc");
                sym.push_pid(pid);

                sym.push(b"fd");
                sym.push_fd(remote_fd);

                sym
            }
            Err(errno) => return Err(errno),
        };

        let file_type = if want_dir {
            Some(FileType::Dir)
        } else {
            file_type(&fd, None, false).ok()
        };

        let entry = Self {
            fd: fd.into(),
            file_type,
            mnt_id: None,
            target: Some(target),
        };

        Ok((entry, sym))
    }

    fn is_magic_link(&self) -> bool {
        matches!(self.file_type, Some(FileType::MagicLnk(_, _)))
    }
}

impl FileMap {
    fn new() -> Self {
        Self(HashMap::default())
    }

    /*
    fn len(&self) -> usize {
        self.0.len()
    }
    */

    fn remove(&mut self, path: &XPath) -> Option<FileMapEntry> {
        self.0.remove(path)
    }

    fn get(&self, path: &XPath) -> Option<&FileMapEntry> {
        self.0.get(path)
    }

    fn open(
        &mut self,
        path: &XPath,
        file_type: Option<FileType>,
    ) -> Result<&mut FileMapEntry, Errno> {
        // SAFETY: rootfs, devfs, procfs, and sysfs views must be identical!
        let (parent, base) = path.split();
        let (parent_fd, base) = if let Some(parent_entry) = self.0.get(parent) {
            (parent_entry.fd.as_raw_fd(), base)
        } else if path.starts_with(b"/dev/") {
            let base = XPath::from_bytes(&path.as_bytes()[b"/dev/".len()..]);
            (DEV_FD(), base)
        } else if path.starts_with(b"/proc/") {
            let base = XPath::from_bytes(&path.as_bytes()[b"/proc/".len()..]);
            (PROC_FD(), base)
        } else if path.starts_with(b"/sys/") {
            let base = XPath::from_bytes(&path.as_bytes()[b"/sys/".len()..]);
            (SYS_FD(), base)
        } else {
            let base = XPath::from_bytes(&path.as_bytes()[1..]);
            (ROOT_FD(), base)
        };

        let fd = safe_open_path(Some(&parent_fd), base, OFlag::O_NOFOLLOW)?;

        // Attempt to reserve memory or bail.
        self.0.try_reserve(1).or(Err(Errno::ENOMEM))?;

        // All good, insert entry and return FD.
        let entry = FileMapEntry::new(fd.into(), file_type, None, None);
        self.0.insert(path.to_owned(), entry);

        self.0.get_mut(path).ok_or(Errno::ENOENT)
    }
}

/// Return value of `safe_canonicalize`.
#[derive(Debug)]
#[allow(dead_code)]
pub struct CanonicalPath<'a> {
    // Canonical, absolute form of path.
    //
    // SAFETY: This must solely used in access check,
    // and must never be passed as an argument to
    // system calls. Failing to do so will very likely
    // result in a TOCTTOU vulnerability.
    abs: XPathBuf,

    /// The final, base, component of the path.
    ///
    /// This is a reference into the `abs` element.
    /// This may be empty in which case `dir` must be used.
    pub base: &'a XPath,

    /// An `O_PATH` file descriptor to the owning directory.
    ///
    /// SAFETY: This is `Some` for all paths except the
    /// root path, ie `/`, which has no owning directory.
    pub dir: Option<MaybeFd>,

    /// File type information, if available.
    pub typ: Option<FileType>,
}

impl fmt::Display for CanonicalPath<'_> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // SAFETY: XPathBuf's Display masks control characters in path.
        write!(f, "{}", self.abs())
    }
}

impl Serialize for CanonicalPath<'_> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut map = serializer.serialize_map(Some(4))?;

        map.serialize_entry("abs", &self.abs)?;
        if self.base.is_empty() {
            map.serialize_entry("fd", &self.dir.as_ref().map(|fd| fd.as_raw_fd()))?;
        } else {
            map.serialize_entry("dir", &self.dir.as_ref().map(|fd| fd.as_raw_fd()))?;
            map.serialize_entry("base", self.base)?;
        }
        map.serialize_entry("type", &self.typ)?;

        let owned = matches!(self.dir, Some(MaybeFd::Owned(_)));
        map.serialize_entry("owned", &owned)?;

        map.end()
    }
}

impl<'a> CanonicalPath<'a> {
    /// Test whether file type represents a regular file.
    pub fn is_file(&self) -> bool {
        self.typ.as_ref().map(|typ| typ.is_file()).unwrap_or(false)
    }

    /// Test whether file type represents a directory.
    pub fn is_dir(&self) -> bool {
        self.typ.as_ref().map(|typ| typ.is_dir()).unwrap_or(false)
    }

    /// Test whether file type represents a symlink.
    pub fn is_symlink(&self) -> bool {
        self.typ
            .as_ref()
            .map(|typ| typ.is_symlink())
            .unwrap_or(false)
    }

    /// Test whether file type represents a magic link.
    pub fn is_magic_link(&self) -> bool {
        self.typ
            .as_ref()
            .map(|typ| typ.is_magic_link())
            .unwrap_or(false)
    }

    /// Test whether file type represents a magic directory.
    ///
    /// SAFETY/TODO: Used to harden magic link calls with O_DIRECTORY.
    pub fn is_magic_dir(&self) -> bool {
        self.typ
            .as_ref()
            .map(|typ| typ.is_magic_dir())
            .unwrap_or(false)
    }

    /// Test whether file type represents a block device.
    pub fn is_block_device(&self) -> bool {
        self.typ
            .as_ref()
            .map(|typ| typ.is_block_device())
            .unwrap_or(false)
    }

    /// Test whether file type represents a character device.
    pub fn is_char_device(&self) -> bool {
        self.typ
            .as_ref()
            .map(|typ| typ.is_char_device())
            .unwrap_or(false)
    }

    /// Test whether file type represents a FIFO.
    pub fn is_fifo(&self) -> bool {
        self.typ.as_ref().map(|typ| typ.is_fifo()).unwrap_or(false)
    }

    /// Test whether file type represents a socket.
    pub fn is_socket(&self) -> bool {
        self.typ
            .as_ref()
            .map(|typ| typ.is_socket())
            .unwrap_or(false)
    }

    /// Test whether file type represents an unknown file.
    pub fn is_unknown(&self) -> bool {
        self.typ
            .as_ref()
            .map(|typ| typ.is_unknown())
            .unwrap_or(false)
    }

    /// Returns a reference to the absolute form of path.
    ///
    /// SAFETY: This must solely used in access check,
    /// and must never be passed as an argument to
    /// system calls. Failing to do so will very likely
    /// result in a TOCTTOU vulnerability.
    #[inline]
    pub fn abs(&self) -> &XPath {
        XPath::from_bytes(self.abs.as_bytes())
    }

    /// Consume the `CanonicalPath` and return the absolute path.
    pub fn take(self) -> XPathBuf {
        self.abs
    }

    /// Create a new `CanonicalPath`.
    pub fn new(abs: XPathBuf, typ: FileType, options: FsFlags) -> Result<CanonicalPath<'a>, Errno> {
        // SAFETY: rootfs, devfs, procfs and sysfs views must be identical!
        if abs.is_rootfs() {
            return Ok(Self::new_root());
        } else if abs.is_devfs() {
            return Ok(Self::new_dev());
        } else if abs.is_procfs() {
            return Ok(Self::new_proc());
        } else if abs.is_sysfs() {
            return Ok(Self::new_sys());
        } else if abs.is_equal(b"/dev/null") {
            return Ok(Self::new_null());
        }

        // SAFETY:
        // 1. Use NONBLOCK with non-path fds to avoid blocking on pipes, FIFOs etc.
        // 2. Use NOCTTY to avoid acquiring controlling terminal.
        let flags = if options.contains(FsFlags::WANT_READ) {
            OFlag::O_RDONLY | OFlag::O_NONBLOCK | OFlag::O_NOCTTY
        } else if typ.is_dir() {
            // SAFETY: Assert known directory with O_DIRECTORY.
            OFlag::O_PATH | OFlag::O_DIRECTORY
        } else {
            OFlag::O_PATH
        };

        // SAFETY: safe_open does not follow symlinks.
        let fd = safe_open::<BorrowedFd>(None, &abs, flags)?;

        Ok(Self {
            abs,
            base: XPath::from_bytes(b""),
            dir: Some(fd.into()),
            typ: Some(typ),
        })
    }

    /// Create a new `CanonicalPath` for (saved) `/`.
    ///
    /// This fd is opened at startup.
    pub fn new_root() -> CanonicalPath<'a> {
        Self {
            abs: XPathBuf::from("/"),
            base: XPath::from_bytes(b""),
            dir: Some(ROOT_FD().into()),
            typ: Some(FileType::Dir),
        }
    }

    /// Create a new `CanonicalPath` for (saved) `/dev`.
    ///
    /// This fd is opened at startup.
    pub fn new_dev() -> CanonicalPath<'a> {
        Self {
            abs: XPathBuf::from("/dev"),
            base: XPath::from_bytes(b""),
            dir: Some(DEV_FD().into()),
            typ: Some(FileType::Dir),
        }
    }

    /// Create a new `CanonicalPath` for (saved) `/proc`.
    ///
    /// This fd is opened at startup.
    pub fn new_proc() -> CanonicalPath<'a> {
        Self {
            abs: XPathBuf::from("/proc"),
            base: XPath::from_bytes(b""),
            dir: Some(PROC_FD().into()),
            typ: Some(FileType::Dir),
        }
    }

    /// Create a new `CanonicalPath` for (saved) `/sys`.
    ///
    /// This fd is opened at startup.
    pub fn new_sys() -> CanonicalPath<'a> {
        Self {
            abs: XPathBuf::from("/sys"),
            base: XPath::from_bytes(b""),
            dir: Some(SYS_FD().into()),
            typ: Some(FileType::Dir),
        }
    }

    /// Create a new `CanonicalPath` for a magic file.
    ///
    /// Magic files are virtual files that do not have a filesystem part,
    /// and therefore are not subject to TOCTTOU.
    pub fn new_magic(virtual_path: XPathBuf) -> CanonicalPath<'a> {
        Self {
            abs: virtual_path,
            base: XPath::from_bytes(b""),
            dir: Some(NULL_FD().into()),
            typ: Some(FileType::Chr),
        }
    }

    /// Create a new `CanonicalPath` for a `/dev/null'.
    pub fn new_null() -> CanonicalPath<'a> {
        Self {
            abs: XPathBuf::from("/dev/null"),
            base: XPath::from_bytes(b""),
            dir: Some(NULL_FD().into()),
            typ: Some(FileType::Chr),
        }
    }

    /// Create a new `CanonicalPath` from an absolute tty name.
    pub fn new_tty(abs: XPathBuf) -> Result<CanonicalPath<'a>, Errno> {
        assert!(
            abs.is_dev(),
            "BUG: non /dev path passed to CanonicalPath::new_tty!"
        );

        let base = XPath::from_bytes(&abs.as_bytes()[b"/dev/".len()..]);
        let fd = safe_open_path(Some(&DEV_FILE()), base, OFlag::O_NOFOLLOW)?;

        Ok(Self {
            abs,
            base: XPath::empty(),
            dir: Some(fd.into()),
            typ: Some(FileType::Chr),
        })
    }

    /// Create a new `CanonicalPath` from a file descriptor.
    ///
    /// The return value has `abs` field populated and
    /// may be used in access checks.
    pub fn new_fd(mut fd: MaybeFd, pid: Pid, remote_fd: RawFd) -> Result<CanonicalPath<'a>, Errno> {
        // Create path to symlink.
        let sym = local_fd(pid, fd.as_raw_fd());
        let cwd = fd.as_raw_fd() == libc::AT_FDCWD;

        // Step 1: Try to readlink().
        let (target, is_deleted) = match readlinkat(Some(&PROC_FILE()), &sym) {
            Ok(p) => {
                if p.is_relative() {
                    // /proc/1/fd/42 -> pipe:[4242], socket:[4242]
                    if cwd {
                        // /proc/$pid/cwd
                        // This can never happen.
                        return Err(Errno::ENOTDIR);
                    }

                    // SAFETY: /proc fd symlink does not refer to a
                    // filesystem path.
                    let mut sym = XPathBuf::from("/proc");
                    sym.push_pid(pid);

                    sym.push(b"fd");
                    sym.push(p.as_bytes());

                    (Some(sym), false)
                } else if p.ends_with(b" (deleted)") {
                    // /proc/1/cwd -> /path/to/foo (deleted)
                    //
                    // This may be a deleted directory, or a directory
                    // whose name funnily ends with a genuine " (deleted)"
                    // string. getdir_long is going to find out for sure.
                    (None, true)
                } else {
                    // Genuine file descriptor that points to a valid directory.
                    (Some(p), false)
                }
            }
            Err(Errno::ENOENT) => return Err(Errno::EBADF),
            Err(Errno::ENAMETOOLONG) => (None, false),
            Err(errno) => return Err(errno),
        };

        // Step 2: Open CWD using the magic symlink.
        if cwd {
            let flags = OFlag::O_PATH | OFlag::O_DIRECTORY;
            fd = safe_open_magicsym(Some(&PROC_FILE()), &sym, flags)?.into();
        }

        if let Some(path) = target {
            // We managed to successfully readlink,
            // and open the magic symlink, return.
            let file_type = if cwd {
                Some(FileType::Dir)
            } else {
                file_type(&fd, None, false).ok()
            };

            return Ok(Self {
                abs: path,
                base: XPath::from_bytes(b""),
                dir: Some(fd),
                typ: file_type,
            });
        }

        // Step 3: Use getdir_long().

        // SAFETY:
        // 1. getdir_long() does not change CWD!
        // 2. We limit maximum dir components to 128 so the sandbox
        //    process cannot create arbitrarily long directories and
        //    crash Syd.
        let path = match getdir_long(fd.as_raw_fd(), 128) {
            Ok(path) => path,
            Err(Errno::ENOENT | Errno::ENOTDIR) if is_deleted => {
                // SAFETY: /proc fd symlink refers to a
                // deleted filesystem path.
                let mut sym = XPathBuf::from("/proc");
                sym.push_pid(pid);

                sym.push(b"fd");
                sym.push_fd(remote_fd);

                sym
            }
            Err(errno) => return Err(errno),
        };

        let file_type = if cwd {
            Some(FileType::Dir)
        } else {
            file_type(&fd, None, false).ok()
        };

        Ok(Self {
            abs: path,
            base: XPath::from_bytes(b""),
            dir: Some(fd),
            typ: file_type,
        })
    }

    // Create a `CanonicalPath` using a `FileMap`.
    #[allow(clippy::cognitive_complexity)]
    fn new_map(
        mut abs: XPathBuf,
        mut typ: Option<FileType>,
        options: FsFlags,
        mut filemap: FileMap,
    ) -> Result<CanonicalPath<'a>, Errno> {
        // SAFETY: rootfs, devfs, procfs and sysfs views must be identical!
        if abs.is_rootfs() {
            return Ok(Self::new_root());
        } else if abs.is_devfs() {
            return Ok(Self::new_dev());
        } else if abs.is_procfs() {
            return Ok(Self::new_proc());
        } else if abs.is_sysfs() {
            return Ok(Self::new_sys());
        } else if abs.is_equal(b"/dev/null") {
            return Ok(Self::new_null());
        }

        let follow_last = options.follow_last();
        let (is_magic_link, magic_base) = match typ {
            Some(FileType::MagicLnk(_pid, -1)) => (true, None),
            Some(FileType::MagicLnk(_pid, -2)) => (true, None),
            Some(FileType::MagicLnk(_pid, libc::AT_FDCWD)) => (true, None),
            Some(FileType::MagicLnk(_pid, fd)) if abs.starts_with(b"/proc") => {
                (true, Some(XPathBuf::from_fd(fd)))
            }
            Some(FileType::MagicLnk(_pid, _fd)) => (true, None),
            _ => (false, None),
        };

        // During statx and openat2 we do not want trailing slash,
        // or we'll get unexpected ELOOP on symbolic links.
        let has_trailing_slash = abs.ends_with_slash();
        if has_trailing_slash {
            #[allow(clippy::arithmetic_side_effects)]
            abs.truncate(abs.len() - 1);
        }

        // Determine file type.
        // SAFETY: rootfs and procfs views must be identical!
        let entry = filemap.remove(&abs);
        let mut magic_parent: XPathBuf;
        let (parent, mut base) = abs.split();

        // SAFETY: magic links are _always_ prefixed with `/proc`.
        // Hence the `unwrap` in the second branch is fine.
        #[allow(clippy::disallowed_methods)]
        let (parent_fd, has_parent) = if let Some(entry_parent) = filemap.remove(parent) {
            if let Some(ref magic_base) = magic_base {
                base = magic_base;
            } else {
                typ = if let Some(Some(file_type)) = entry.as_ref().map(|e| e.file_type) {
                    Some(file_type)
                } else {
                    file_type(&entry_parent.fd, Some(base), false).ok()
                };
            }
            (entry_parent.fd, true)
        } else if let Some(ref magic_base) = magic_base {
            magic_parent = parent.strip_prefix(b"/proc").unwrap().to_owned();
            magic_parent.push(magic_base.as_bytes());
            base = &magic_parent;

            (PROC_FD().into(), false)
        } else if abs.is_dev() {
            base = XPath::from_bytes(&abs.as_bytes()[b"/dev/".len()..]);

            if !is_magic_link {
                typ = if let Some(Some(file_type)) = entry.as_ref().map(|e| e.file_type) {
                    Some(file_type)
                } else {
                    file_type(&DEV_FILE(), Some(base), false).ok()
                };
            }

            (DEV_FD().into(), false)
        } else if abs.is_proc() {
            base = XPath::from_bytes(&abs.as_bytes()[b"/proc/".len()..]);

            if !is_magic_link {
                typ = if let Some(Some(file_type)) = entry.as_ref().map(|e| e.file_type) {
                    Some(file_type)
                } else {
                    file_type(&PROC_FILE(), Some(base), false).ok()
                };
            }

            (PROC_FD().into(), false)
        } else if abs.is_sys() {
            base = XPath::from_bytes(&abs.as_bytes()[b"/sys/".len()..]);

            if !is_magic_link {
                typ = if let Some(Some(file_type)) = entry.as_ref().map(|e| e.file_type) {
                    Some(file_type)
                } else {
                    file_type(&SYS_FILE(), Some(base), false).ok()
                };
            }

            (SYS_FD().into(), false)
        } else {
            base = XPath::from_bytes(&abs.as_bytes()[1..]);

            if !is_magic_link {
                typ = if let Some(Some(file_type)) = entry.as_ref().map(|e| e.file_type) {
                    Some(file_type)
                } else {
                    file_type(&ROOT_FILE(), Some(base), false).ok()
                };
            }

            (ROOT_FD().into(), false)
        };

        crate::debug!("ctx": "resolve_path", "op": "open_last",
            "path": &abs,
            "base": &base,
            "type": &typ,
            "options": format!("{options:?}"),
            "open_files": filemap.0.len());

        // Do we want to resolve symbolic links for the last component?
        if follow_last {
            match typ {
                None if options.must_exist() => {
                    // SAFETY: last component must exist but it does not!
                    return Err(Errno::ENOENT);
                }
                Some(FileType::Lnk) => {
                    // SAFETY: symlink appeared out-of-nowhere, deny!
                    return Err(Errno::ELOOP);
                }
                _ => {}
            }
        } else if has_trailing_slash && typ.is_none() && options.must_exist() {
            // SAFETY: Attempt to follow dangling symbolic link.
            return Err(Errno::ENOENT);
        }

        if options.intersects(FsFlags::MISS_LAST | FsFlags::WANT_BASE)
            || (typ.is_none() && !options.must_exist())
        {
            // Open an `O_PATH` file descriptor to the owning directory.
            // Use parent fd as a reference if available.
            // SAFETY: rootfs, devfs, procfs and sysfs views must be identical!
            let parent_fd = if has_parent {
                parent_fd
            } else if parent.starts_with(b"/dev") {
                let fd: MaybeFd = if parent.len() == b"/dev".len() {
                    DEV_FD().into()
                } else {
                    let parent_base = XPath::from_bytes(&parent.as_bytes()[b"/dev/".len()..]);

                    safe_open_path::<BorrowedFd>(
                        Some(&DEV_FILE()),
                        parent_base,
                        OFlag::O_PATH | OFlag::O_DIRECTORY,
                    )?
                    .into()
                };

                fd
            } else if parent.starts_with(b"/proc") {
                let fd: MaybeFd = if parent.len() == b"/proc".len() {
                    PROC_FD().into()
                } else {
                    let parent_base = XPath::from_bytes(&parent.as_bytes()[b"/proc/".len()..]);

                    safe_open_path::<BorrowedFd>(
                        Some(&PROC_FILE()),
                        parent_base,
                        OFlag::O_PATH | OFlag::O_DIRECTORY,
                    )?
                    .into()
                };

                fd
            } else if parent.starts_with(b"/sys") {
                let fd: MaybeFd = if parent.len() == b"/sys".len() {
                    SYS_FD().into()
                } else {
                    let parent_base = XPath::from_bytes(&parent.as_bytes()[b"/sys/".len()..]);

                    safe_open_path::<BorrowedFd>(
                        Some(&SYS_FILE()),
                        parent_base,
                        OFlag::O_PATH | OFlag::O_DIRECTORY,
                    )?
                    .into()
                };

                fd
            } else {
                let parent_base = XPath::from_bytes(&parent.as_bytes()[1..]);

                let fd: MaybeFd = if parent_base.is_empty() {
                    ROOT_FD().into()
                } else {
                    safe_open_path::<BorrowedFd>(
                        Some(&ROOT_FILE()),
                        parent_base,
                        OFlag::O_PATH | OFlag::O_DIRECTORY,
                    )?
                    .into()
                };

                fd
            };

            // Calculate parent length early here, as `parent' which is
            // a reference into `abs' can potentially get invalidated in
            // the next trailing slash check.
            let parent_len = parent.len();

            #[allow(clippy::arithmetic_side_effects)]
            if has_trailing_slash {
                // SAFETY: Preserve trailing slash to assert
                // directory after sandbox path hide check.
                abs.append_byte(b'/');
            };

            // Ensure we have the correct base path, because e.g. for
            // /proc/self/fd, `base' atm points not the actual base but
            // $pid/fd.  This happens due to the special parent handling
            // above and here we correct base.
            #[allow(clippy::arithmetic_side_effects)]
            {
                base = XPath::from_bytes(&abs.as_bytes()[parent_len + 1..]);
            }

            // SAFETY: Extend the lifetime of `base` to `'a`
            let base = unsafe { std::mem::transmute::<&XPath, &'a XPath>(base) };

            return Ok(Self {
                abs,
                base,
                dir: Some(parent_fd),
                typ,
            });
        }

        // SAFETY:
        // 1. Use NONBLOCK with non-path fds to avoid blocking on pipes, FIFOs etc.
        // 2. Use NOCTTY to avoid acquiring controlling terminal.
        let (mut flags, is_read) = if options.contains(FsFlags::WANT_READ) {
            (OFlag::O_RDONLY | OFlag::O_NOCTTY | OFlag::O_NONBLOCK, true)
        } else {
            (OFlag::O_PATH, false)
        };

        // SAFETY: Do not open block devices without O_PATH,
        // which can have unintended side-effects. Note,
        // we already pass O_NONBLOCK so as not to block on FIFOs,
        // and pass O_NOCTTY so as not to acquire a controlling terminal.
        if is_read && typ.as_ref().map(|t| t.is_block_device()).unwrap_or(false) {
            return Err(Errno::ENOENT);
        }

        if !is_read {
            // Return the O_PATH fd if we're already opened.
            if let Some(entry) = entry {
                if has_trailing_slash {
                    // SAFETY: Preserve trailing slash to assert
                    // directory after sandbox path hide check.
                    abs.append_byte(b'/');
                }

                return Ok(Self {
                    abs,
                    base: XPath::from_bytes(b""),
                    dir: Some(entry.fd),
                    typ,
                });
            }
        }

        // SAFETY: safe_open does not follow symlinks.
        // Exception: Final component is a (magic) symlink,
        // and NO_FOLLOW_LAST is not set.
        let fd = if is_magic_link {
            if !follow_last {
                // NO_FOLLOW_LAST set, insert O_NOFOLLOW.
                flags.insert(OFlag::O_NOFOLLOW);
            }
            safe_open_magicsym(Some(&parent_fd), base, flags)
        } else {
            // O_NOFOLLOW already set here.
            safe_open(Some(&parent_fd), base, flags)
        }?;

        if has_trailing_slash {
            // SAFETY: Preserve trailing slash to assert
            // directory after sandbox path hide check.
            abs.append_byte(b'/');
        }

        Ok(Self {
            abs,
            base: XPath::from_bytes(b""),
            dir: Some(fd.into()),
            typ,
        })
    }
}

/// Return local fd magic symlink path.
pub(crate) fn local_fd(pid: Pid, fd: RawFd) -> XPathBuf {
    match fd {
        libc::AT_FDCWD => {
            let mut sym = XPathBuf::from_pid(pid);
            sym.push(b"cwd");
            sym
        }
        fd => {
            let mut sym = XPathBuf::from("self/fd");
            sym.push_fd(fd);
            sym
        }
    }
}

/// Return remote fd magic symlink path.
pub(crate) fn remote_fd(pid: Pid, fd: RawFd) -> XPathBuf {
    let mut sym = XPathBuf::from_pid(pid);

    match fd {
        -1 => sym.push(b"root"),
        -2 => sym.push(b"exe"),
        libc::AT_FDCWD => sym.push(b"cwd"),
        fd => {
            sym.push(b"fd");
            sym.push_fd(fd);
        }
    };

    sym
}

/// Return the canonical, absolute form of a path safely as a
/// file descriptor to the owning file descriptor together with
/// the base component and optional file type.
///
/// The `flag` parameter determines the sandbox restrictions to apply.
///
/// The `miss_mode` parameter controls how missing components are handled.
///
/// The `resolve` is a boolean parameter which controls whether the last
/// component should be resolved or not. Remaining components are always
/// resolved.
#[allow(clippy::cognitive_complexity)]
pub fn safe_canonicalize<'a>(
    pid: Pid,
    fd: Option<RawFd>,
    path: &XPath,
    options: FsFlags,
    flags: Flags,
) -> Result<CanonicalPath<'a>, Errno> {
    // SAFETY: File map is a hash table with paths as keys. The
    // values are the file descriptor, the file type, and optional
    // symbolic link target. This map is used throughout
    // canonicalization to ensure:
    // 1. We never reopen the same file.
    // 2. We never follow the same link.
    // 3. We never recheck the file type or mount id.
    let mut filemap: FileMap = FileMap::new();
    let mut file_type = None;

    // SAFETY: Populate the filemap with pre-opened static fds:
    // /, /dev, /proc, /sys, /dev/null
    filemap.0.try_reserve(5).or(Err(Errno::ENOMEM))?;

    let entry = FileMapEntry::new(
        ROOT_FD().into(),
        Some(FileType::Dir),
        Some(ROOT_MNT_ID()),
        None,
    );
    filemap.0.insert(XPathBuf::from("/"), entry);

    let entry = FileMapEntry::new(
        DEV_FD().into(),
        Some(FileType::Dir),
        Some(DEV_MNT_ID()),
        None,
    );
    filemap.0.insert(XPathBuf::from("/dev"), entry);

    let entry = FileMapEntry::new(
        PROC_FD().into(),
        Some(FileType::Dir),
        Some(PROC_MNT_ID()),
        None,
    );
    filemap.0.insert(XPathBuf::from("/proc"), entry);

    let entry = FileMapEntry::new(
        SYS_FD().into(),
        Some(FileType::Dir),
        Some(SYS_MNT_ID()),
        None,
    );
    filemap.0.insert(XPathBuf::from("/sys"), entry);

    let entry = FileMapEntry::new(
        NULL_FD().into(),
        Some(FileType::Chr),
        Some(NULL_MNT_ID()),
        None,
    );
    filemap.0.insert(XPathBuf::from("/dev/null"), entry);

    let resolve_beneath = options.contains(FsFlags::RESOLVE_BENEATH);
    let (mut result, cwd) = if path.is_relative() {
        if let Some(fd) = fd {
            let want_dir = if fd == libc::AT_FDCWD {
                true
            } else if fd < 0 {
                return Err(Errno::EBADF);
            } else {
                false
            };
            let (mut entry, sym) = FileMapEntry::from_raw_fd(pid, fd, want_dir)?;

            // SAFETY: fd_entry's target member is always Some,
            // when FileMapEntry::from_raw_fd returns success
            // with want_dir parameter set to true.
            #[allow(clippy::disallowed_methods)]
            let dir = entry.target.clone().unwrap();

            let entry_sym = FileMapEntry::new(
                MaybeFd::RawFd(entry.fd.as_raw_fd()),
                Some(FileType::MagicLnk(pid, fd)),
                entry.mnt_id,
                entry.target.take(),
            );

            entry.file_type = Some(FileType::Dir);
            filemap.0.try_reserve(2).or(Err(Errno::ENOMEM))?;
            filemap.0.insert(dir.clone(), entry);
            filemap.0.insert(sym, entry_sym);

            (dir.clone(), Some(dir))
        } else if !path.is_empty() {
            let (mut entry, sym) = FileMapEntry::from_raw_fd(pid, libc::AT_FDCWD, true)?;

            // SAFETY: cwd_entry's target member is always Some,
            // when FileMapEntry::from_raw_fd returns success
            // with want_dir parameter set to true.
            #[allow(clippy::disallowed_methods)]
            let dir = entry.target.clone().unwrap();

            let entry_sym = FileMapEntry::new(
                MaybeFd::RawFd(entry.fd.as_raw_fd()),
                Some(FileType::MagicLnk(pid, libc::AT_FDCWD)),
                entry.mnt_id,
                entry.target.take(),
            );

            entry.file_type = Some(FileType::Dir);
            filemap.0.try_reserve(2).or(Err(Errno::ENOMEM))?;
            filemap.0.insert(dir.clone(), entry);
            filemap.0.insert(sym, entry_sym);

            (dir.clone(), Some(dir))
        } else {
            return Err(Errno::ENOENT);
        }
    } else if resolve_beneath {
        // RESOLVE_BENEATH rejects absolute values of pathname.
        return Err(Errno::EXDEV);
    } else if path.is_rootfs() {
        // Special case, `/` is never a symlink.
        // This must be done after the RESOLVE_BENEATH check!
        return Ok(CanonicalPath::new_root());
    } else if path.is_devfs() {
        // Special case, `/dev` is never a symlink.
        // This must be done after the RESOLVE_BENEATH check!
        return Ok(CanonicalPath::new_dev());
    } else if path.is_procfs() {
        // Special case, `/proc` is never a symlink.
        // This must be done after the RESOLVE_BENEATH check!
        return Ok(CanonicalPath::new_proc());
    } else if path.is_sysfs() {
        // Special case, `/sys` is never a symlink.
        // This must be done after the RESOLVE_BENEATH check!
        return Ok(CanonicalPath::new_sys());
    } else {
        // Absolute path, CWD is ignored.
        (XPathBuf::from("/"), Some(XPathBuf::from("/")))
    };

    // What do we do when a component is missing?
    let miss_mode = MissingHandling::from(options);
    // Do we want to resolve magic /proc symbolic links?
    let resolve_proc = options.resolve_proc();
    // Do we want to traverse through mount points?
    let resolve_xdev = !options.contains(FsFlags::NO_RESOLVE_XDEV);

    // `..` restriction for path traversal for chdir and open* family calls.
    let deny_dotdot = options.contains(FsFlags::NO_RESOLVE_DOTDOT);

    // Restriction for /proc magic links.
    let restrict_magiclinks = !flags.contains(Flags::FL_ALLOW_UNSAFE_MAGICLINKS);

    // Do we want to resolve symbolic links for the last component?
    let no_follow_last = !options.follow_last();

    // Options to open flags. O_NOFOLLOW is omitted here on purpose.
    let is_split = options.intersects(FsFlags::MISS_LAST | FsFlags::WANT_BASE);
    let mut open_flags = if !is_split && options.contains(FsFlags::WANT_READ) {
        OFlag::O_RDONLY | OFlag::O_NONBLOCK | OFlag::O_NOCTTY
    } else {
        OFlag::O_PATH
    };

    // SAFETY: Set close-on-exec.
    open_flags |= OFlag::O_CLOEXEC;

    // Split path into components, record trailing slash.
    let (mut parts, mut has_to_be_directory) = path_components(path)?;

    // Assert directory requirement with O_DIRECTORY.
    if has_to_be_directory {
        open_flags.insert(OFlag::O_DIRECTORY);
    }

    crate::debug!("ctx": "resolve_path", "op": "loop_init",
        "pid": pid.as_raw(),
        "path": &result,
        "root": &cwd,
        "is_dir": has_to_be_directory,
        "parts": &parts,
        "options": format!("{options:?}"),
        "flags": format!("{flags:?}"));

    // Used by proc_fd:
    //  Deny regardless of PID if RESOLVE_NO_MAGICLINKS.
    // `magic_errno` determines between EXDEV and ELOOP.
    let pid_errno = options.magic_errno();

    // Determine reference mount id for RESOLVE_NO_XDEV.
    let mnt_id = if resolve_xdev {
        // Do nothing if RESOLVE_NO_XDEV is not set.
        None
    } else if let Some(ref cwd) = cwd {
        Some(safe_stat_mount_id(cwd, &mut filemap, file_type)?)
    } else if result.is_rootfs() {
        // Jumping to "/" is ok, but later components cannot cross.
        None
    } else {
        return Err(Errno::EXDEV);
    };

    // Symbolic Lnk Loop Detection.
    const SYMLINKS_TO_LOOK_FOR_LOOPS: u8 = 16;
    let mut followed_symlinks = 0;
    let mut visited_files: Option<HashSet<FileInformation, RandomState>> = None;

    let mut last;
    let mut loop_first = true;
    let mut no_resolve_symlinks;
    while let Some(part) = parts.pop_front() {
        // SAFETY: Limit maximum dir components to PATH_MAX_COMP so the
        // sandbox process cannot create arbitrarily long directories
        // and crash Syd.
        if result.len() >= PATH_MAX && parts.len() >= PATH_MAX_COMP {
            return Err(Errno::ENAMETOOLONG);
        }

        // Check if this is the last component.
        //
        // It may not necessarily be the last iteration,
        // in case the last component points to a symlink.
        last = parts.is_empty();

        // Do we want to resolve symbolic links in this path component?
        //
        // The answer is YES for all path components but the final
        // component. The resolution of the final component depends
        // on the following conditions:
        //
        // The answer is NO _if_ NO_FOLLOW_LAST flag is set, YES otherwise.
        //
        // _Unless_ the final component has a trailing slash which asserts a directory,
        // in which case we _DO_ resolve symbolic links in the final component regardless
        // of the NO_FOLLOW_LAST flag.
        //
        // _However_, if the MISS_LAST flag is also set, the trailing slash
        // is irrelevant, and we do _NOT_ resolve symlinks in the final
        // component.
        no_resolve_symlinks = last
            && no_follow_last
            && (!has_to_be_directory || miss_mode == MissingHandling::Missing);

        crate::debug!("ctx": "resolve_path", "op": "loop_iter",
            "pid": pid.as_raw(),
            "path": &result,
            "type": &file_type,
            "root": &cwd,
            "options": format!("{options:?}"),
            "part": &part,
            "parts": &parts,
            "open_files": filemap.0.len(),
            "resolve_beneath": resolve_beneath,
            "resolve_proc": resolve_proc,
            "resolve_xdev": resolve_xdev,
            "is_last": last,
            "is_dir": has_to_be_directory,
            "follow_last": !no_follow_last,
            "is_split": is_split,
            "open_flags": format!("{open_flags:?}"),
            "miss_mode": format!("{miss_mode:?}"),
            "deny_dotdot": deny_dotdot,
            "restrict_magiclinks": restrict_magiclinks);

        if deny_dotdot && matches!(part, PathComponent::ParentDir) {
            // SAFETY: Traversing through `..` is forbidden with
            // trace/deny_dotdot:1.
            return Err(Errno::EACCES);
        }

        // The first iteration of checks for RESOLVE_BENEATH,
        // and RESOLVE_NO_XDEV was done before the loop so
        // we skip them here for one turn.
        if !loop_first {
            // Check for RESOLVE_BENEATH and RESOLVE_NO_XDEV.
            // Temporary jumps are not allowed!
            if resolve_beneath {
                if let Some(ref cwd) = cwd {
                    if !result.deref().descendant_of(cwd.as_bytes()) {
                        return Err(Errno::EXDEV);
                    }
                } else {
                    return Err(Errno::EXDEV);
                }
            }

            if let Some(mnt_id) = mnt_id {
                // Jumping to "/" is ok, but later components cannot cross.
                if !result.is_rootfs() {
                    let my_mnt_id = safe_stat_mount_id(&result, &mut filemap, file_type)?;
                    if my_mnt_id != mnt_id {
                        return Err(Errno::EXDEV);
                    }
                }
            }
        }

        match part {
            PathComponent::Normal(ref p) => {
                result.try_reserve(p.len()).or(Err(Errno::ENAMETOOLONG))?;
                result.push(p.as_bytes());
            }
            PathComponent::ParentDir => {
                // SAFETY:
                // 1. `result` is a normalized absolute path.
                // 2. `result` does not have a trailing slash.
                unsafe { result.pop_unchecked() };

                if last {
                    // Invalidate file type if it's the last component.
                    file_type = None;
                }

                if result.is_rootfs() {
                    // RootDir as part of walking up path of
                    // an earlier symlink.
                    continue;
                }
            }
        }

        // SAFETY:
        // 1. NO_MAGICLINKS unless trace/allow_unsafe_magiclinks:1.
        //    Continue in case:
        //    (a) pipe:42 socket:42 etc, special paths.
        //    (b) file descriptors that point to deleted paths.
        // 2. Handle /proc/self and /proc/thread-self indirections.
        let result_magic = match proc_fd(pid, result.deref(), restrict_magiclinks)? {
            Some(_) if pid_errno == Errno::ELOOP && (!last || !no_follow_last) => {
                // PROC_NO_SYMLINKS || PROC_NO_MAGICLINKS.
                return Err(pid_errno);
            }
            Some((fd, tid)) => {
                // Handle /proc/$pid/fd/$fd indirection unless
                // this is the final component and NO_FOLLOW_LAST is set.
                let sym = remote_fd(pid, fd);
                file_type = Some(FileType::MagicLnk(tid, fd));

                if let Some(entry) = filemap.get(&sym) {
                    // SAFETY: Magic link target member is always Some.
                    #[allow(clippy::disallowed_methods)]
                    Some(Ok(entry.target.clone().unwrap()))
                } else {
                    let want_dir = matches!(fd, -1 | libc::AT_FDCWD);
                    let (mut entry, _) = FileMapEntry::from_raw_fd(tid, fd, want_dir)?;

                    // SAFETY: Magic link target member is always Some.
                    #[allow(clippy::disallowed_methods)]
                    let target = entry.target.clone().unwrap();

                    let entry_sym = FileMapEntry::new(
                        MaybeFd::RawFd(entry.fd.as_raw_fd()),
                        Some(FileType::MagicLnk(tid, fd)),
                        entry.mnt_id,
                        entry.target.take(),
                    );

                    filemap.0.try_reserve(2).or(Err(Errno::ENOMEM))?;
                    filemap.0.insert(target.clone(), entry);
                    filemap.0.insert(sym, entry_sym);

                    Some(Ok(target))
                }
            }
            None if result.is_proc_self(false) => {
                // Handle /proc/self indirection unless
                // this is the final component and NO_FOLLOW_LAST is set.
                if !no_resolve_symlinks {
                    file_type = Some(FileType::Dir);

                    // SAFETY:
                    // 1. `result` is a normalized absolute path.
                    // 2. `result` does not have a trailing slash.
                    unsafe { result.pop_unchecked() };

                    result.push_pid(pid);
                } else if last {
                    // Set file type to symlink.
                    // TODO: Do we want to set to magic link here?
                    file_type = Some(FileType::Lnk);
                }

                Some(Err(Errno::EINVAL))
            }
            None if result.is_proc_self(true) => {
                // Handle /proc/thread-self indirection unless
                // this is the final component and NO_FOLLOW_LAST is set.
                if !no_resolve_symlinks {
                    file_type = Some(FileType::Dir);

                    // SAFETY:
                    // 1. `result` is a normalized absolute path.
                    // 2. `result` does not have a trailing slash.
                    unsafe { result.pop_unchecked() };

                    let tgid = proc_tgid(pid)?;
                    result.push_pid(tgid);
                    result.push(b"task");
                    result.push_pid(pid);
                } else if last {
                    // Set file type to symlink.
                    // TODO: Do we want to set to magic link here?
                    file_type = Some(FileType::Lnk);
                }

                Some(Err(Errno::EINVAL))
            }
            None => None,
        };

        // We're resolving symbolic links for all path components but last.
        // The resolution of the last component depends on the NO_FOLLOW_LAST option.
        if no_resolve_symlinks {
            // Handle trailing slash as part of a symlink target.
            if result.ends_with(b"/") {
                has_to_be_directory = true;
                open_flags.insert(OFlag::O_DIRECTORY);
            }

            // SAFETY: Invalidate file type since we are not going to
            // resolve the final component. One exception is (magic)
            // symbolic links whose information we keep for later
            // hardening.
            if !file_type
                .as_ref()
                .map(|typ| typ.is_symlink() || typ.is_magic_link())
                .unwrap_or(false)
            {
                file_type = None;
            }

            // Nothing left to do, break out.
            break;
        }

        loop_first = false;
        let resolve_result = if let Some(result_magic) = result_magic {
            result_magic
        } else {
            resolve_symlink(&result, options, &mut filemap, file_type)
        };

        crate::debug!("ctx": "resolve_path", "op": "read_symlink",
            "pid": pid.as_raw(),
            "ret": format!("{resolve_result:?}"),
            "path": &result,
            "type": &file_type,
            "root": &cwd,
            "part": &part,
            "parts": &parts,
            "options": format!("{options:?}"),
            "open_files": filemap.0.len(),
            "resolve_beneath": resolve_beneath,
            "resolve_proc": resolve_proc,
            "resolve_xdev": resolve_xdev,
            "is_last": last,
            "follow_last": !no_follow_last,
            "is_split": is_split,
            "open_flags": format!("{open_flags:?}"),
            "miss_mode": format!("{miss_mode:?}"),
            "deny_dotdot": deny_dotdot,
            "restrict_magiclinks": restrict_magiclinks);

        match resolve_result {
            Ok(target) => {
                let rel = target.is_relative();

                // SAFETY: Check for magiclinks, see above.
                if let Some(FileType::MagicLnk(_, _)) = file_type {
                    const DELETED_SUFFIX: &[u8] = b" (deleted)";
                    let del = !rel && target.ends_with(DELETED_SUFFIX);

                    if last {
                        if del {
                            // Deleted paths with the " (deleted)" suffix.
                            // Keep result as is, file type is already set.
                        } else if !rel {
                            // Magic link points to genuine path.
                            // Set the result to target, reset file type.
                            result = target;
                            file_type = None;
                        } else {
                            // Magic link points to magic path.
                            // Paths such as [pipe:64], [socket:42] etc.
                            // Append to result so the user can filter.

                            // SAFETY:
                            // 1. `result` is a normalized absolute path.
                            // 2. `result` does not have a trailing slash.
                            unsafe { result.pop_unchecked() };
                            result.push(target.as_bytes());
                        }

                        if has_to_be_directory {
                            result.push(b"");
                        }

                        break;
                    }

                    if del || rel {
                        // Magic link points to magic path.
                        continue;
                    }
                }

                // Invalidate file type before the next round.
                file_type = None;

                //// Symbolic Lnk Loop Detection.
                // SAFETY: SYMLINKS_TO_LOOK_FOR_LOOPS is much smaller than u8::MAX.
                #[allow(clippy::arithmetic_side_effects)]
                if followed_symlinks < SYMLINKS_TO_LOOK_FOR_LOOPS {
                    followed_symlinks += 1;
                } else {
                    let stat = FileInformation::from_link(result.deref())?;
                    if let Some(ref mut visited_files) = visited_files {
                        if !visited_files.insert(stat) {
                            return Err(Errno::ELOOP);
                        }
                    } else {
                        // Allocate the HashSet only when it's really necessary.
                        visited_files = Some(HashSet::from_iter([stat]));
                    }
                }
                ////

                if rel {
                    // SAFETY:
                    // 1. `result` is a normalized absolute path.
                    // 2. `result` does not have a trailing slash.
                    unsafe { result.pop_unchecked() };
                } else {
                    // 1. RootDir as part of resolving a symlink to an absolute path!
                    // 2. `result` is an absolute path so truncating to 1 effectively
                    //    leaves behind `/` only.
                    result.truncate(1);
                }
                path_components2(target.deref(), &mut parts)?;
            }
            Err(Errno::EINVAL) => {
                // Handle trailing slash as part of a symlink target.
                if last && !has_to_be_directory && result.ends_with(b"/") {
                    has_to_be_directory = true;
                    open_flags.insert(OFlag::O_DIRECTORY);
                } else {
                    // Invalidate file type.
                    file_type = None;
                }
            }
            Err(errno) => match miss_mode {
                MissingHandling::Existing => return Err(errno),
                MissingHandling::Normal if !parts.is_empty() => return Err(errno),
                _ => {
                    // Invalidate file type.
                    file_type = None;
                }
            },
        }
    }

    crate::debug!("ctx": "resolve_path", "op": "loop_done",
        "pid": pid.as_raw(),
        "path": &result,
        "type": &file_type,
        "root": &cwd,
        "options": format!("{options:?}"),
        "open_files": filemap.0.len(),
        "resolve_beneath": resolve_beneath,
        "resolve_proc": resolve_proc,
        "resolve_xdev": resolve_xdev,
        "is_dir": has_to_be_directory,
        "follow_last": !no_follow_last,
        "is_split": is_split,
        "open_flags": format!("{open_flags:?}"),
        "miss_mode": format!("{miss_mode:?}"),
        "deny_dotdot": deny_dotdot,
        "restrict_magiclinks": restrict_magiclinks);

    // SAFETY: Deny symbolic links at final component,
    // unless NO_FOLLOW_LAST is set explicitly.
    if options.follow_last()
        && file_type
            .as_ref()
            .map(|typ| typ.is_symlink())
            .unwrap_or(false)
    {
        return Err(Errno::ELOOP);
    }

    // Check for RESOLVE_BENEATH and RESOLVE_NO_XDEV.
    if resolve_beneath {
        if let Some(ref cwd) = cwd {
            if !result.deref().descendant_of(cwd.as_bytes()) {
                return Err(Errno::EXDEV);
            }
        } else {
            return Err(Errno::EXDEV);
        }
    }

    // SAFETY: Handle trailing slash.
    // 1. Keep trailing slash as necessary.
    // 2. Add trailing slash for directories to assert file type.
    if has_to_be_directory {
        if matches!(
            miss_mode,
            MissingHandling::Existing | MissingHandling::Normal
        ) && !matches!(
            file_type.as_ref(),
            None | Some(FileType::Dir | FileType::MagicLnk(_, _))
        ) {
            return Err(Errno::ENOTDIR);
        }
        result.append_byte(b'/');
    }

    if let Some(mnt_id) = mnt_id {
        // Open last component.
        let my_mnt_id = match (
            safe_stat_mount_id(&result, &mut filemap, file_type),
            miss_mode,
        ) {
            (Ok(mnt_id), _) => mnt_id,
            (Err(Errno::ELOOP), _) => {
                // SAFETY: symlink appeared out-of-nowhere, deny!
                return Err(Errno::ELOOP);
            }
            (Err(Errno::ENOENT), MissingHandling::Existing) => {
                return Err(Errno::ENOENT);
            }
            (Err(Errno::ENOTDIR), MissingHandling::Existing | MissingHandling::Normal)
                if has_to_be_directory =>
            {
                return Err(Errno::ENOTDIR);
            }
            _ => return Err(Errno::EXDEV),
        };

        if my_mnt_id != mnt_id {
            return Err(Errno::EXDEV);
        }
    }

    // SAFETY: Symbolic link resolution is no-longer needed/wanted.
    open_flags |= OFlag::O_NOFOLLOW;

    crate::debug!("ctx": "resolve_path", "op": "resolve_done",
        "pid": pid.as_raw(),
        "path": &path,
        "root": &cwd,
        "options": format!("{options:?}"),
        "open_files": filemap.0.len(),
        "resolve_beneath": resolve_beneath,
        "resolve_proc": resolve_proc,
        "resolve_xdev": resolve_xdev,
        "is_dir": has_to_be_directory,
        "is_split": is_split,
        "follow_last": !no_follow_last,
        "open_flags": format!("{open_flags:?}"),
        "miss_mode": format!("{miss_mode:?}"),
        "deny_dotdot": deny_dotdot,
        "restrict_magiclinks": restrict_magiclinks);

    // SAFETY: Open a file descriptor to the canonical path, without
    // resolving symbolic links anymore. This brings safety against
    // TOCTTOU attacks.
    CanonicalPath::new_map(result, file_type, options, filemap)
}

/// Searches for a name within a directory.
///
/// `name` is matched literally and exactly against file names.
/// Directory entries are appended a trailing slash before matching.
/// Symlink entries are appended an `@` character before matching.
#[allow(clippy::disallowed_methods)]
pub fn grep(dir: &XPath, name: &[u8]) -> Option<XPathBuf> {
    let dir = File::open(dir.as_path()).ok()?;
    let name = XPath::from_bytes(name);
    loop {
        let mut entries = match getdents64(&dir, 128) {
            Ok(entries) => entries,
            Err(_) => return None,
        };
        for entry in &mut entries {
            let mut path = XPathBuf::from(entry.name_bytes());
            // Append a trailing slash for directories.
            if entry.is_dir() {
                path.append_byte(b'/');
            } else if entry.is_symlink() {
                path.append_byte(b'@');
            } else if entry.is_block_device() {
                path.append_byte(b'!');
            } else if entry.is_char_device() {
                path.append_byte(b'$');
            } else if entry.is_fifo() {
                path.append_byte(b'|');
            } else if entry.is_socket() {
                path.append_byte(b'~');
            }
            if *path == *name || (name.len() == 1 && path.ends_with(name.as_bytes())) {
                return Some(path);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::{
        fs::{self, OpenOptions},
        os::{
            fd::AsRawFd,
            unix::{
                fs::{symlink, OpenOptionsExt},
                net::UnixStream,
            },
        },
        process::{exit, Command},
        thread::sleep,
        time::{Duration, SystemTime},
    };

    use nix::{
        fcntl::open,
        sched::{unshare, CloneFlags},
        sys::{
            signal::{kill, Signal},
            stat::Mode,
            wait::waitpid,
        },
        unistd::{chdir, close, fchdir, fork, getcwd, mkdir, pause, ForkResult},
    };

    use super::*;
    use crate::xpath;

    fn setup() -> bool {
        let _ = crate::log::log_init_simple(crate::syslog::LogLevel::Warn);

        if let Err(error) = crate::config::proc_init() {
            eprintln!("Failed to initialize proc: {error:?}");
            return false;
        }

        true
    }

    // A helper function to create a deep directory structure.
    fn setup_deep_directory_structure(name: &XPath, depth: usize) -> Result<(), nix::Error> {
        // Tests may run in parallel, so ensure we don't share CWD.
        unshare(CloneFlags::CLONE_FS).unwrap();

        // Save the current directory by opening it
        let fd = safe_open_raw::<BorrowedFd>(
            None,
            XPath::from_bytes(b"."),
            OFlag::O_PATH | OFlag::O_DIRECTORY,
        )?;

        // Create a deep directory structure starting from the current directory
        for _ in 0..depth {
            mkdir(name, Mode::S_IRWXU)?;
            chdir(name)?;
        }

        // After setup, restore the original directory
        fchdir(fd)?;
        let _ = close(fd);

        Ok(())
    }

    // A helper function to get the current atime of a file
    fn get_atime<P: AsRef<Path>>(path: P) -> SystemTime {
        let metadata = fs::metadata(path).expect("Failed to get metadata");
        metadata.accessed().expect("Failed to get accessed time")
    }

    // Helper function to assert that the atime of a file or directory has not changed
    fn assert_atime_unchanged<'a, P: AsRef<Path>, F>(path: P, func: F)
    where
        F: FnOnce() -> Result<CanonicalPath<'a>, Errno>,
    {
        let original_atime_f = get_atime(&path);
        let original_atime_p = get_atime(path.as_ref().parent().unwrap());
        sleep(Duration::from_secs(7));
        assert!(
            func().is_ok(),
            "canonicalize {} failed",
            path.as_ref().display()
        );
        // We allow a 1-second tolerance since some filesystems do not have nanosecond precision.
        let new_atime_f = get_atime(&path);
        let new_atime_p = get_atime(path.as_ref().parent().unwrap());
        assert!(
            new_atime_f <= original_atime_f + Duration::new(1, 0),
            "The atime of the file should not have significantly changed."
        );
        assert!(
            new_atime_p <= original_atime_p + Duration::new(1, 0),
            "The atime of the parent dir should not have significantly changed."
        );
    }

    // std::fs::remove_dir_all stops on the first error.
    // we need something more forceful.
    fn remove_dir_all<P: AsRef<Path>>(path: P) -> std::io::Result<()> {
        let status = Command::new("rm")
            .arg("-rf")
            .arg(path.as_ref().to_string_lossy().to_string())
            .status()?;
        if status.success() {
            Ok(())
        } else {
            Err(std::io::Error::new(
                std::io::ErrorKind::Other,
                format!("Failed to remove directory: {}", path.as_ref().display()),
            ))
        }
    }

    // Helper function to create a symlink chain that eventually loops back to an earlier link
    fn setup_symlink_loop(tmp_dir: &XPath, links: &[(&str, &str)]) {
        for &(src, dst) in links {
            let src_path = tmp_dir.join(src.as_bytes());

            // Check and create parent directory for the source if necessary
            let src_parent = src_path.parent();
            if !src_parent.exists(false) {
                fs::create_dir_all(src_parent.as_path()).unwrap();
            }

            // The destination is given relative to the source
            let dst_path = XPath::from_bytes(&dst.as_bytes());

            // Avoid creating a symlink if the source already exists
            if src_path.exists(false) {
                fs::remove_file(src_path.as_path()).unwrap();
            }

            // If the destination is an absolute path or starts with '/', we strip the '/' and prefix with tmp_dir
            let full_dst_path = if dst_path.is_absolute() {
                tmp_dir.join(dst_path.strip_prefix(b"/").unwrap().as_bytes())
            } else {
                src_parent.join(dst_path.as_bytes()).into()
            };

            // Create parent directories for the destination if they don't exist
            let dst_parent = full_dst_path.parent();
            if !dst_parent.exists(false) {
                fs::create_dir_all(dst_parent.as_path()).unwrap();
            }

            // Create the symlink
            symlink(full_dst_path.as_path(), src_path.as_path())
                .expect(&format!("Unable to symlink {src_path} -> {full_dst_path}",));
        }
    }

    fn tempdir() -> Result<XPathBuf, Box<dyn std::error::Error>> {
        let tmp = tempfile::Builder::new().keep(true).tempdir_in(".")?;
        let _ = OpenOptions::new()
            .write(true)
            .create(true)
            .mode(0o600)
            .open(tmp.path().join("test"))?;
        Ok(tmp
            .path()
            .to_path_buf()
            .file_name()
            .unwrap()
            .as_bytes()
            .into())
    }

    // Changes the current directory to `dir` handling arbitrarily long pathnames.
    fn chdir_long(dir: &XPath) -> Result<(), Errno> {
        let mut path_buf = dir.as_bytes();
        let mut current_dir_fd = -2;

        loop {
            // Attempt to change directory.
            let dir = XPath::from_bytes(path_buf);
            if path_buf.is_empty() || chdir(dir).is_ok() {
                if current_dir_fd >= 0 {
                    let _ = close(current_dir_fd);
                }
                return Ok(());
            }

            if !matches!(Errno::last(), Errno::ENAMETOOLONG | Errno::ENOMEM)
                || dir.len() < PATH_MAX - 1
            {
                break;
            }

            // Handle long path by trying to split at a directory boundary
            let mut boundary = path_buf.len().min(PATH_MAX - 1);
            while boundary > 0 && path_buf[boundary] != b'/' {
                boundary -= 1;
            }

            if boundary == 0 {
                break;
            }

            // Attempt to temporarily change to the subdirectory.
            if current_dir_fd == -2 {
                // Open current directory.
                current_dir_fd = open(".", OFlag::O_PATH | OFlag::O_DIRECTORY, Mode::empty())?;
            }

            let dir = XPath::from_bytes(&path_buf[..boundary]);
            if chdir(dir).is_err() {
                break;
            }

            // Move to the next component.
            path_buf = &path_buf[boundary + 1..];
        }

        // Save last errno to return from the function.
        let errno = match Errno::last() {
            Errno::UnknownErrno => Errno::ENAMETOOLONG,
            errno => errno,
        };

        // Attempt to restore the original directory if there was a failure.
        if current_dir_fd >= 0 {
            let result = fchdir(current_dir_fd);
            let _ = close(current_dir_fd);

            return if result.is_ok() {
                Err(errno)
            } else {
                Err(Errno::ENOTRECOVERABLE)
            };
        }

        Err(if current_dir_fd == -2 {
            errno
        } else {
            Errno::ENOTRECOVERABLE
        })
    }

    #[test]
    fn test_canonicalize_empty_path() {
        if !setup() {
            return;
        }

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b""),
            FsFlags::empty(),
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b""),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b""),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b""),
            FsFlags::NO_FOLLOW_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b""),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b""),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");
    }

    #[test]
    fn test_canonicalize_repetitive_root() {
        if !setup() {
            return;
        }

        let root = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b"//"),
            FsFlags::empty(),
            Flags::empty(),
        )
        .unwrap();
        assert_eq!(root.abs.as_bytes(), b"/");
        assert_eq!(root.typ, Some(FileType::Dir));
    }

    #[test]
    fn test_canonicalize_repetitive_slashes() {
        if !setup() {
            return;
        }

        let result_test = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b"/etc/passwd"),
            FsFlags::empty(),
            Flags::empty(),
        )
        .unwrap()
        .abs;
        let paths = vec![
            "/etc/passwd",
            "/etc//passwd",
            "/etc///passwd",
            "//etc/passwd",
            "//etc//passwd",
            "//etc///passwd",
            "///etc/passwd",
            "///etc//passwd",
            "///etc///passwd",
        ];
        for path in &paths {
            let path = XPathBuf::from(path.to_string());
            let result = safe_canonicalize(
                Pid::this(),
                None,
                &path.deref(),
                FsFlags::empty(),
                Flags::empty(),
            )
            .unwrap()
            .abs;
            assert_eq!(result, result_test);
        }
    }

    #[test]
    fn test_canonicalize_dots_slashes() {
        if !setup() {
            return;
        }

        let cwd = XPathBuf::from(std::env::current_dir().unwrap());
        let tmp = tempdir().unwrap();

        let path = xpath!("{tmp}//./..//{tmp}/test");
        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::empty(),
            Flags::empty(),
        );
        assert!(result.is_ok(), "{path}->{result:?}");
        let result1 = result.unwrap().abs;
        let path = xpath!("{cwd}/{tmp}//./..//{tmp}/test");
        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{path}->{result:?}");
        let result2 = result.unwrap().abs;

        assert!(!result1.is_empty(), "result:{result1}");
        assert!(!result2.is_empty(), "result:{result2}");
        assert_eq!(result1, result2);
    }

    #[test]
    fn test_canonicalize_non_directory_with_slash() {
        if !setup() {
            return;
        }

        let path = tempdir().unwrap();
        let test = xpath!("{path}/test/");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &test.deref(),
            FsFlags::empty(),
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOTDIR)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &test.deref(),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOTDIR)), "{result:?}");

        //SAFETY: Missing is handled by read_path*.
        assert!(safe_canonicalize(
            Pid::this(),
            None,
            &test.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        )
        .is_ok());

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &test.deref(),
            FsFlags::NO_FOLLOW_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOTDIR)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &test.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOTDIR)), "{result:?}");

        //SAFETY: Missing is handled by read_path*.
        assert!(safe_canonicalize(
            Pid::this(),
            None,
            &test.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        )
        .is_ok());
    }

    /// FIXME: The asserts return success rather than failure.
    /// Bug or feature.unwrap()
    #[test]
    fn test_canonicalize_missing_directory_returns_enoent() {
        if !setup() {
            return;
        }

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b"/zzz/.."),
            FsFlags::empty(),
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b"/zzz/.."),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b"/zzz/.."),
            FsFlags::NO_FOLLOW_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b"/zzz/.."),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");
    }

    #[test]
    fn test_relative_symlink_resolution() {
        if !setup() {
            return;
        }

        // Setup
        let root_test_dir = &XPath::from_bytes(b"test_root_relative_symlink_resolution");
        let deep_dir = root_test_dir.join(b"a/b/c");
        let _ = remove_dir_all(&root_test_dir);
        fs::create_dir_all(&root_test_dir.join(b"d")).unwrap();
        fs::create_dir_all(&deep_dir).unwrap();

        // Create a symlink in "b" that points upwards to "a"
        let rel_link = root_test_dir.join(b"a/b/rel_link");
        symlink("../..", &rel_link).unwrap();

        // Append /proc/self/cwd to get an absolute path to our symlinked path
        let abs_link_path = &XPath::from_bytes(b"/proc/self/cwd")
            .join(root_test_dir.join(b"a/b/rel_link/d").as_bytes());

        // Call canonicalize
        let result = safe_canonicalize(
            Pid::this(),
            None,
            &abs_link_path.deref(),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(
            result.is_ok(),
            "canonicalize:{abs_link_path} result:{result:?}",
        );
        let resolved_path = result.unwrap().abs;

        // We expect the path to be resolved to "test_root/a/d", but we need to canonicalize it
        let expected_path = fs::canonicalize(
            &XPath::from_bytes(b"/proc/self/cwd").join(root_test_dir.join(b"d").as_bytes()),
        )
        .unwrap();

        // Cleanup:
        // Note, remove_dir_all cannot remove a directory
        // tree if it spots a symbolic link loop unlike
        // `rm -rf`.
        // let _ = remove_dir_all(&root_test_dir);
        Command::new("/bin/rm")
            .arg("-rf")
            .arg(&root_test_dir)
            .status()
            .expect("rm -rf tmpdir");

        assert_eq!(resolved_path, XPathBuf::from(expected_path));
    }

    // FIXME: This test broke after we removed normalize()
    // The question: Is the test incorrect or is canonicalize().unwrap()
    #[ignore]
    #[test]
    fn test_complex_interplay_symlinks_dots() {
        if !setup() {
            return;
        }

        // Setup
        let cwd = XPathBuf::from(Path::new("/proc/self/cwd").canonicalize().unwrap());
        let root_test_dir = cwd.join(b"test_root_complex_interplay_symlinks_dots");
        let _ = remove_dir_all(&root_test_dir);
        fs::create_dir_all(root_test_dir.join(b"a/b/c")).unwrap();
        fs::create_dir(root_test_dir.join(b"d")).unwrap();
        fs::create_dir(root_test_dir.join(b"e")).unwrap();
        fs::create_dir(root_test_dir.join(b"x")).unwrap();

        // Create several symlinks
        symlink("./a", root_test_dir.join(b"link_to_a")).unwrap();
        symlink("e", root_test_dir.join(b"link_to_e")).unwrap();
        symlink("a/b", root_test_dir.join(b"link_to_b")).unwrap();
        symlink("../../x", root_test_dir.join(b"a/b/rel_link")).unwrap();

        let path = root_test_dir.join(b"link_to_a/../link_to_b/rel_link/../..");
        let resolved_path = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::MUST_PATH,
            Flags::empty(),
        )
        .unwrap()
        .abs;

        // Cleanup
        let _ = remove_dir_all(&root_test_dir);

        // Assertion
        assert_eq!(resolved_path, XPathBuf::from(root_test_dir));
    }

    #[test]
    fn test_trailing_slash_handling() {
        // Spawn a new process which will inherit the fds.
        // Note we cannot use the current process here,
        // as XPath::check will think it's Syd and deny
        // access.
        let child = match unsafe { fork() } {
            Ok(ForkResult::Parent { child }) => child,
            Ok(ForkResult::Child) => {
                pause();
                exit(127);
            }
            Err(errno) => exit(errno as i32),
        };

        if !setup() {
            kill(child, Signal::SIGKILL).unwrap();
            waitpid(child, None).unwrap();
            return;
        }

        let path = XPath::from_bytes(b"/usr/");
        let pexp = path;
        let path = safe_canonicalize(child, None, &path, FsFlags::empty(), Flags::empty()).unwrap();
        assert_eq!(pexp, path.abs.deref(), "{pexp} != {path:?}");
        eprintln!("ok 1");

        let parg = XPath::from_bytes(b"/proc/self/");
        let pexp = xpath!("/proc/{child}/");

        let path = safe_canonicalize(child, None, &parg, FsFlags::empty(), Flags::empty()).unwrap();
        assert_eq!(path.abs, pexp, "{pexp} != {path:?}");
        eprintln!("ok 2 step 1");

        let path =
            safe_canonicalize(child, None, &parg, FsFlags::NO_FOLLOW_LAST, Flags::empty()).unwrap();
        assert_eq!(path.abs, pexp, "{pexp} != {path:?}");
        eprintln!("ok 2 step 2");

        kill(child, Signal::SIGKILL).unwrap();
        waitpid(child, None).unwrap();
    }

    #[test]
    fn test_canonicalize_no_atime_change_normal() {
        if !setup() {
            return;
        }

        let cdir = XPathBuf::from(std::env::current_dir().unwrap());
        let base = cdir.join(tempdir().unwrap().as_bytes());
        let path = base.join(b"file");
        fs::File::create(&path).unwrap();

        assert_atime_unchanged(&path, || {
            safe_canonicalize(
                Pid::this(),
                None,
                &path.deref(),
                FsFlags::empty(),
                Flags::empty(),
            )
        });

        let _ = remove_dir_all(&base);
    }

    #[test]
    fn test_canonicalize_no_atime_change_existing() {
        if !setup() {
            return;
        }

        let cdir = XPathBuf::from(std::env::current_dir().unwrap());
        let base = cdir.join(&tempdir().unwrap().as_bytes());
        let path = base.join(b"file");
        fs::File::create(&path).unwrap();

        assert_atime_unchanged(&path, || {
            safe_canonicalize(
                Pid::this(),
                None,
                &path.deref(),
                FsFlags::MUST_PATH,
                Flags::empty(),
            )
        });

        let _ = remove_dir_all(&base);
    }

    #[test]
    fn test_canonicalize_symlink_loop() {
        if !setup() {
            return;
        }

        let tmp_dir = tempfile::Builder::new()
            .keep(true)
            .tempdir()
            .expect("Failed to create temp dir");
        let dir_path = XPathBuf::from(tmp_dir.path().to_path_buf());

        // Create a symlink loop: link_a -> link_b -> link_a
        let mut link_a = dir_path.join(b"link_a");
        let mut link_b = dir_path.join(b"link_b");
        symlink(&link_b, &link_a).expect("Failed to create symlink a");
        symlink(&link_a, &link_b).expect("Failed to create symlink b");

        // Now check that canonicalize detects the loop correctly
        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link_a.deref(),
            FsFlags::NO_FOLLOW_LAST,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link_a.deref(),
            FsFlags::empty(),
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link_a.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link_a.deref(),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link_a.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        //SAFETY: Missing is handled by read_path*.
        //assert_eq!(result, Err(Errno::EEXIST));
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link_a.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        // Add a trailing slash and retest.
        link_a.push(b"");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link_a.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link_a.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        // Add a trailing slash and retest.
        link_b.push(b"");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link_b.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link_b.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");
    }

    #[test]
    fn test_canonicalize_nonexistent_final_component() {
        if !setup() {
            return;
        }

        let tmp_dir = tempfile::Builder::new()
            .keep(true)
            .tempdir()
            .expect("Failed to create temp dir");
        let dir_path = XPathBuf::from(tmp_dir.path().to_path_buf());

        // Create a valid symlink to a non-existent final component
        let mut valid_link = dir_path.join(b"valid_link");
        let nonexistent_target = dir_path.join(b"nonexistent");
        symlink(&nonexistent_target, &valid_link)
            .expect("Failed to create symlink to non-existent target");

        // Now check that canonicalize handles the non-existent final component correctly.
        let result = safe_canonicalize(
            Pid::this(),
            None,
            &valid_link.deref(),
            FsFlags::NO_FOLLOW_LAST,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &valid_link.deref(),
            FsFlags::empty(),
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &valid_link.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &valid_link.deref(),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &valid_link.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        //SAFETY: Missing is handled by read_path*.
        //assert_eq!(result, Err(Errno::EEXIST));
        assert!(result.is_ok(), "{result:?}");

        // FIXME: Why oh why.unwrap()
        let result = safe_canonicalize(
            Pid::this(),
            None,
            &valid_link.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");
        // should be: assert_eq!(result, Err(Errno::EEXIST));

        // Add a trailing slash and retest.
        valid_link.push(b"");

        // FIXME: Why oh why.unwrap()
        let result = safe_canonicalize(
            Pid::this(),
            None,
            &valid_link.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");
        // should be: assert_eq!(result, Err(Errno::EEXIST));

        // FIXME: Why oh why?
        let result = safe_canonicalize(
            Pid::this(),
            None,
            &valid_link.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");
        // should be: assert_eq!(result, Err(Errno::EEXIST));
    }

    #[test]
    fn test_canonicalize_self_referential_symlink() {
        if !setup() {
            return;
        }

        let tmp_dir = tempfile::Builder::new()
            .keep(true)
            .tempdir()
            .expect("Failed to create temp dir");
        let dir_path = XPathBuf::from(tmp_dir.path().to_path_buf());
        let mut symlink_path = dir_path.join(b"self_link");
        symlink(symlink_path.as_path(), symlink_path.as_path())
            .expect("Failed to create self-referential symlink");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::NO_FOLLOW_LAST,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::empty(),
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        //SAFETY: Missing is handled by read_path*.
        //assert_eq!(result, Err(Errno::EEXIST));
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        // Add a trailing slash and retest.
        symlink_path.push(b"");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");
    }

    #[test]
    fn test_canonicalize_broken_symlink() {
        if !setup() {
            return;
        }

        let tmp_dir = tempfile::Builder::new()
            .keep(true)
            .tempdir()
            .expect("Failed to create temp dir");
        let dir_path = XPathBuf::from(tmp_dir.path().to_path_buf());
        let mut broken_link = dir_path.join(b"broken_link");
        let nonexistent_target = dir_path.join(b"nonexistent_target");
        symlink(nonexistent_target.as_path(), broken_link.as_path())
            .expect("Failed to create broken symlink");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &broken_link.deref(),
            FsFlags::NO_FOLLOW_LAST,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");
        eprintln!("ok 1");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &broken_link.deref(),
            FsFlags::empty(),
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");
        eprintln!("ok 2");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &broken_link.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");
        eprintln!("ok 3");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &broken_link.deref(),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");
        eprintln!("ok 4");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &broken_link.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        //SAFETY: Missing is handled by read_path*.
        //assert_eq!(result, Err(Errno::EEXIST));
        assert!(result.is_ok(), "{result:?}");
        eprintln!("ok 5");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &broken_link.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");
        eprintln!("ok 6");

        // Add a trailing slash and retest.
        broken_link.push(b"");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &broken_link.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");
        eprintln!("ok 7");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &broken_link.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{result:?}");
        eprintln!("ok 8");
    }

    #[test]
    fn test_canonicalize_symlink_to_directory() {
        if !setup() {
            return;
        }

        let tmp_dir = tempfile::Builder::new()
            .keep(true)
            .tempdir()
            .expect("Failed to create temp dir");
        let tmp_path = XPathBuf::from(tmp_dir.path().to_path_buf());
        let dir = tmp_path.join(b"dir");
        fs::create_dir(&dir).expect("Failed to create directory");

        let symlink_path = tmp_path.join(b"dir_link");
        symlink(dir.as_path(), symlink_path.as_path())
            .expect("Failed to create symlink to directory");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::NO_FOLLOW_LAST,
            Flags::empty(),
        );
        let result_repr = format!("{result:?}");
        assert!(result.is_ok(), "{result_repr}");
        assert!(result.unwrap().typ.unwrap().is_symlink(), "{result_repr}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::empty(),
            Flags::empty(),
        );
        let result_repr = format!("{result:?}");
        assert!(result.is_ok(), "{result_repr}");
        assert!(result.unwrap().typ.unwrap().is_dir(), "{result_repr}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Flags::empty(),
        );
        let result_repr = format!("{result:?}");
        assert!(result.is_ok(), "{result_repr}");
        assert!(result.unwrap().typ.unwrap().is_symlink(), "{result_repr}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        let result_repr = format!("{result:?}");
        assert!(result.is_ok(), "{result_repr}");
        assert!(result.unwrap().typ.unwrap().is_dir(), "{result_repr}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        //SAFETY: Missing is handled by read_path*.
        //assert_eq!(result, Err(Errno::EEXIST));
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        //SAFETY: Missing is handled by read_path*.
        //assert_eq!(result, Err(Errno::EEXIST));
        assert!(result.is_ok(), "{result:?}");
    }

    #[test]
    fn test_canonicalize_symlink_chain() {
        if !setup() {
            return;
        }

        let tmp_dir = tempfile::Builder::new()
            .keep(true)
            .tempdir()
            .expect("Failed to create temp dir");
        let dir_path = XPathBuf::from(tmp_dir.path().to_path_buf());
        let link1 = dir_path.join(b"link1");
        let link2 = dir_path.join(b"link2");
        let link3 = dir_path.join(b"link3");
        let file = dir_path.join(b"file");
        fs::write(file.as_path(), "content").expect("Failed to write file");

        // Create a chain of symlinks: link1 -> link2 -> link3 -> file
        symlink(link2.as_path(), link1.as_path()).expect("Failed to create link1");
        symlink(link3.as_path(), link2.as_path()).expect("Failed to create link2");
        symlink(file.as_path(), link3.as_path()).expect("Failed to create link3");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link1.deref(),
            FsFlags::NO_FOLLOW_LAST,
            Flags::empty(),
        );
        let result_repr = format!("{result:?}");
        assert!(result.is_ok(), "{result_repr}");
        assert!(result.unwrap().typ.unwrap().is_symlink(), "{result_repr}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link1.deref(),
            FsFlags::empty(),
            Flags::empty(),
        );
        let result_repr = format!("{result:?}");
        assert!(result.is_ok(), "{result_repr}");
        assert!(result.unwrap().typ.unwrap().is_file(), "{result_repr}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link1.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Flags::empty(),
        );
        let result_repr = format!("{result:?}");
        assert!(result.is_ok(), "{result_repr}");
        assert!(result.unwrap().typ.unwrap().is_symlink(), "{result_repr}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link1.deref(),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        let result_repr = format!("{result:?}");
        assert!(result.is_ok(), "{result_repr}");
        assert!(result.unwrap().typ.unwrap().is_file(), "{result_repr}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link1.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        //SAFETY: Missing is handled by read_path*.
        //assert_eq!(result, Err(Errno::EEXIST));
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link1.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        //SAFETY: Missing is handled by read_path*.
        //assert_eq!(result, Err(Errno::EEXIST));
        assert!(result.is_ok(), "{result:?}");
    }

    #[test]
    fn test_safe_canonicalize_complex_symlink_loop_with_intermediate_components() {
        if !setup() {
            return;
        }

        let tmp_dir = tempfile::Builder::new()
            .keep(true)
            .tempdir()
            .expect("Failed to create temp dir");
        let dir_path = XPathBuf::from(tmp_dir.path().to_path_buf());

        // Setting up a complex symlink scenario
        setup_symlink_loop(
            &dir_path.deref(),
            &[("a", "b/c"), ("b/c", "d"), ("b/d", "../e"), ("e", "f/../a")],
        );

        let mut path = dir_path.join(b"a");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST,
            Flags::empty(),
        );
        let result_repr = format!("{result:?}");
        assert!(result.is_ok(), "{result_repr}");
        assert!(result.unwrap().typ.unwrap().is_symlink(), "{result_repr}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::empty(),
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Flags::empty(),
        );
        let result_repr = format!("{result:?}");
        assert!(result.is_ok(), "{result_repr}");
        assert!(result.unwrap().typ.unwrap().is_symlink(), "{result_repr}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        //SAFETY: Missing is handled by read_path*.
        //assert_eq!(result, Err(Errno::EEXIST));
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        // Add a trailing slash and retest.
        path.push(b"");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        // Add a final component and retest.
        path.push(b"foo");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");
    }

    #[test]
    fn test_safe_canonicalize_symlinks_with_dot_and_dotdot_components() {
        if !setup() {
            return;
        }

        let tmp_dir = tempfile::Builder::new()
            .keep(true)
            .tempdir()
            .expect("Failed to create temp dir");

        // Create a complex directory structure with dots and symlinks
        fs::create_dir_all(tmp_dir.path().join("b")).expect("Failed to create directory b");
        symlink("b", tmp_dir.path().join("a")).expect("Failed to create symlink a -> b");
        symlink("..///e", tmp_dir.path().join("b").join("d"))
            .expect("Failed to create symlink b/d -> ../e");
        symlink("b/.///./d", tmp_dir.path().join("e")).expect("Failed to create symlink e -> b/d");

        let mut path = XPathBuf::from(tmp_dir.path().join("a").join(".").join("d"));

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{path}->{result:?}");
        let result = result.unwrap();
        assert!(result.abs.exists(false), "{path}->{result:?}");
        assert!(!result.abs.exists(true), "{path}->{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::empty(),
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(result.is_ok(), "{path}->{result:?}");
        let result = result.unwrap();
        assert!(result.abs.exists(false), "{path}->{result:?}");
        assert!(!result.abs.exists(true), "{path}->{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::MUST_PATH,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        //SAFETY: Missing is handled by read_path*.
        //assert_eq!(result, Err(Errno::EEXIST));
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        // Add a trailing slash and retest.
        path.push(b"");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        // Add a final component and retest.
        path.push(b"foo");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::MISS_LAST,
            Flags::empty(),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");
    }

    #[test]
    fn test_canonicalize_proc_self() {
        if !setup() {
            return;
        }

        let pid = Pid::this();
        let path = safe_canonicalize(
            pid,
            None,
            &XPath::from_bytes(b"/proc/self"),
            FsFlags::NO_FOLLOW_LAST,
            Flags::empty(),
        )
        .expect("canonicalize /proc/self");
        assert!(
            path.typ
                .as_ref()
                .map(|typ| typ.is_symlink())
                .unwrap_or(false),
            "path:{path:?}"
        );
        assert_eq!(
            path.abs.deref(),
            XPath::from_bytes(b"/proc/self"),
            "path:{path:?}"
        );
        match path.typ {
            Some(FileType::Lnk) => {}
            _ => panic!("path:{path:?}"),
        }
    }

    #[test]
    fn test_canon_glob_std() {
        if !setup() {
            return;
        }

        // Note we cannot assume the FDs {0,1,2} are open here.
        let fd = open("/dev/null", OFlag::O_RDONLY, Mode::empty()).unwrap();
        // SAFETY: open returns a valid FD.
        let fd = unsafe { OwnedFd::from_raw_fd(fd) };
        let fd = xpath!("/proc/self/fd/{}", fd.as_raw_fd());
        let pid = Pid::this();

        let result = safe_canonicalize(pid, None, &fd.deref(), FsFlags::empty(), Flags::empty());
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(pid, None, &fd.deref(), FsFlags::MUST_PATH, Flags::empty());
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(pid, None, &fd.deref(), FsFlags::MISS_LAST, Flags::empty());
        //SAFETY: Missing is handled by read_path*.
        //assert_eq!(result, Err(Errno::EEXIST));
        assert!(result.is_ok(), "{result:?}");
    }

    #[test]
    fn test_canon_glob_pipe() {
        // Create a socket pair.
        let (read_end, write_end) = UnixStream::pair().unwrap();

        // Spawn a new process which will inherit the fds.
        // Note we cannot use the current process here,
        // as XPath::check will think it's Syd and deny
        // access.
        let child = match unsafe { fork() } {
            Ok(ForkResult::Parent { child }) => child,
            Ok(ForkResult::Child) => {
                pause();
                exit(127);
            }
            Err(errno) => exit(errno as i32),
        };

        if !setup() {
            kill(child, Signal::SIGKILL).unwrap();
            waitpid(child, None).unwrap();
            return;
        }

        let fd = read_end.as_raw_fd();
        let path = xpath!("/proc/{child}/fd/{fd}");
        let result =
            safe_canonicalize(child, None, &path.deref(), FsFlags::empty(), Flags::empty());
        assert!(result.is_ok(), "{path}->{result:?}");

        let fd = write_end.as_raw_fd();
        let path = xpath!("/proc/{child}/fd/{fd}");
        let result =
            safe_canonicalize(child, None, &path.deref(), FsFlags::empty(), Flags::empty());
        assert!(result.is_ok(), "{path}->{result:?}");

        kill(child, Signal::SIGKILL).unwrap();
        waitpid(child, None).unwrap();
    }

    #[test]
    fn test_path_components_empty_path() {
        let path = XPath::from_bytes(b"");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(components, VecDeque::new());
        assert!(has_trailing_slash);
    }

    #[test]
    fn test_path_components_only_parent_dir() {
        let path = XPath::from_bytes(b"..");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(components, VecDeque::from([PathComponent::ParentDir]));
        assert!(has_trailing_slash);
    }

    #[test]
    fn test_path_components_multiple_parent_dir() {
        let path = XPath::from_bytes(b"../..");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(
            components,
            VecDeque::from([PathComponent::ParentDir, PathComponent::ParentDir])
        );
        assert!(has_trailing_slash);
    }

    #[test]
    fn test_path_components_parent_dir_with_normal_components() {
        let path = XPath::from_bytes(b"../foo/../bar");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(
            components,
            VecDeque::from([
                PathComponent::ParentDir,
                PathComponent::Normal(XPathBuf::from("foo")),
                PathComponent::ParentDir,
                PathComponent::Normal(XPathBuf::from("bar")),
            ])
        );
        assert!(!has_trailing_slash);
    }

    #[test]
    fn test_path_components_trailing_slash_with_parent_dir() {
        let path = XPath::from_bytes(b"../foo/..");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(
            components,
            VecDeque::from([
                PathComponent::ParentDir,
                PathComponent::Normal(XPathBuf::from("foo")),
                PathComponent::ParentDir,
            ])
        );
        assert!(has_trailing_slash);
    }

    #[test]
    fn test_path_components_leading_slashes_are_skipped() {
        let path = XPath::from_bytes(b"////..////bar");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(
            components,
            VecDeque::from([
                PathComponent::ParentDir,
                PathComponent::Normal(XPathBuf::from("bar")),
            ])
        );
        assert!(!has_trailing_slash);
    }

    #[test]
    fn test_path_components_path_with_mixed_components_and_trailing_slash() {
        let path = XPath::from_bytes(b"../foo/../bar/");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(
            components,
            VecDeque::from([
                PathComponent::ParentDir,
                PathComponent::Normal(XPathBuf::from("foo")),
                PathComponent::ParentDir,
                PathComponent::Normal(XPathBuf::from("bar")),
            ])
        );
        assert!(has_trailing_slash);
    }

    #[test]
    fn test_path_components_complex_path_with_leading_parent_dir() {
        let path = XPath::from_bytes(b"../foo/bar/../../baz/..");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(
            components,
            VecDeque::from([
                PathComponent::ParentDir,
                PathComponent::Normal(XPathBuf::from("foo")),
                PathComponent::Normal(XPathBuf::from("bar")),
                PathComponent::ParentDir,
                PathComponent::ParentDir,
                PathComponent::Normal(XPathBuf::from("baz")),
                PathComponent::ParentDir,
            ])
        );
        assert!(has_trailing_slash);
    }

    #[test]
    fn test_path_components_root_path_is_handled_externally() {
        let path = XPath::from_bytes(b"/..");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(components, VecDeque::from([PathComponent::ParentDir]));
        assert!(has_trailing_slash);
    }

    #[test]
    fn test_chdir_long() {
        // Create a deep directory structure.
        const MAX_DEPTH: usize = 128;
        let o = "o".repeat(200);
        let name = XPathBuf::from(format!("syd_test_chdir_l{o}ng.dir"));
        setup_deep_directory_structure(&name, MAX_DEPTH).unwrap();

        // Save current working directory.
        let fd = open(".", OFlag::O_PATH | OFlag::O_DIRECTORY, Mode::empty()).unwrap();

        // Attempt to change dir into it.
        let mut lname = name.clone();
        for _ in 0..MAX_DEPTH - 1 {
            lname.push(name.as_bytes());
        }
        let result = chdir_long(&lname);

        // Restore current working directory.
        fchdir(fd).unwrap();
        let _ = close(fd);

        // Clean up after the test.
        Command::new("rm").arg("-rf").arg(name).status().unwrap();

        assert!(result.is_ok(), "chdir_long failed: {result:?}");
    }

    #[test]
    fn test_getdir_long_with_deep_structure() {
        // Create a deep directory structure.
        const MAX_DEPTH: usize = 128;
        let o = "o".repeat(200);
        let name = XPathBuf::from(format!("syd_test_getdir_l{o}ng_with_deep_structure.dir"));
        setup_deep_directory_structure(&name, MAX_DEPTH).unwrap();

        // Save current working directory.
        let fd = open(".", OFlag::O_PATH | OFlag::O_DIRECTORY, Mode::empty()).unwrap();
        let mut cwd = getcwd().map(XPathBuf::from).unwrap();

        // Attempt to change dir into it.
        let max = cwd.depth() + MAX_DEPTH + 1;
        for _ in 0..MAX_DEPTH {
            cwd.push(name.as_bytes());
        }
        let result = chdir_long(&cwd);

        // Get current working directory.
        let result_cwd = if result.is_ok() {
            let cwd_fd = open(".", OFlag::O_PATH | OFlag::O_DIRECTORY, Mode::empty()).unwrap();

            let result_cwd = Some(getdir_long(cwd_fd, max));

            let _ = close(cwd_fd);
            result_cwd
        } else {
            None
        };

        // Restore current working directory.
        fchdir(fd).unwrap();
        let _ = close(fd);

        // Clean up after the test.
        Command::new("rm").arg("-rf").arg(name).status().unwrap();

        // Check results.
        assert!(result.is_ok(), "chdir_long failed: {result:?}");

        let result_cwd = result_cwd.unwrap();
        assert!(result_cwd.is_ok(), "getdir_long failed: {result_cwd:?}");

        let result_cwd = result_cwd.unwrap();
        assert_eq!(cwd, result_cwd, "getdir_long returned incorrect directory");
    }

    #[test]
    fn test_getdir_long_limit_max_components() {
        // Create a deep directory structure.
        const MAX_DEPTH: usize = 128;
        let o = "o".repeat(200);
        let name = XPathBuf::from(format!("syd_test_getdir_l{o}ng_limit_max_components.dir"));
        setup_deep_directory_structure(&name, MAX_DEPTH).unwrap();

        // Save current working directory.
        let fd = open(".", OFlag::O_PATH | OFlag::O_DIRECTORY, Mode::empty()).unwrap();
        let mut cwd = getcwd().map(XPathBuf::from).unwrap();

        // Attempt to change dir into it.
        let max = cwd.depth() + MAX_DEPTH;
        for _ in 0..MAX_DEPTH {
            cwd.push(name.as_bytes());
        }
        let result = chdir_long(&cwd);

        // Get current working directory.
        let result_cwd = if result.is_ok() {
            let cwd_fd = open(".", OFlag::O_PATH | OFlag::O_DIRECTORY, Mode::empty()).unwrap();

            let result_cwd = Some(getdir_long(cwd_fd, max));

            let _ = close(cwd_fd);
            result_cwd
        } else {
            None
        };

        // Restore current working directory.
        fchdir(fd).unwrap();
        let _ = close(fd);

        // Clean up after the test.
        Command::new("rm").arg("-rf").arg(name).status().unwrap();

        // Check results.
        assert!(result.is_ok(), "chdir_long failed: {result:?}");

        let result_cwd = result_cwd.unwrap();
        assert_eq!(
            result_cwd,
            Err(Errno::ERANGE),
            "getdir_long did not fail as expected: {result_cwd:?}"
        );
    }
}
