//
// Syd: rock-solid application kernel
// src/lookup.rs: Path lookup and canonicalization utilities
//
// Copyright (c) 2023, 2024, 2025, 2026 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

use std::{
    borrow::Cow,
    ffi::CStr,
    fmt,
    fs::File,
    hash::Hash,
    ops::Deref,
    os::{
        fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd},
        unix::ffi::OsStrExt,
    },
    sync::Arc,
};

use bitflags::bitflags;
use libc::{c_char, c_uint, openat, AT_EMPTY_PATH, AT_SYMLINK_NOFOLLOW, S_ISVTX, S_IWGRP, S_IWOTH};
use memchr::arch::all::memchr::One;
use nix::{
    errno::Errno,
    fcntl::{OFlag, AT_FDCWD},
    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,
    },
    sys::stat::Mode,
    unistd::Pid,
    NixPath,
};
use serde::{ser::SerializeMap, Serialize, Serializer};
use tinyvec::TinyVec;

use crate::{
    compat::{
        fstatx, getdents64, openat2, statx, FileStatx, OpenHow, ResolveFlag, STATX_INO,
        STATX_MNT_ID, STATX_MNT_ID_UNIQUE, STATX_MODE, STATX_NLINK, STATX_SIZE, STATX_TYPE,
    },
    config::*,
    cookie::safe_openat2,
    error,
    fd::{is_huge_file, AT_BADFD},
    filemap::FileMap,
    fs::{format_oflags, readlinkat, readlinkfd},
    io::WriteFd,
    kernel::sandbox_path,
    magic::ProcMagic,
    path::{dotdot_with_nul, XPath, XPathBuf, PATH_MAX},
    proc::proc_tgid,
    retry::retry_on_eintr,
    sandbox::{Capability, Sandbox},
};

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

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

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

    /// Convert statx information to FileInfo.
    ///
    /// 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,
        }
    }

    /// Return masks for statx(2) required to attain file information.
    pub fn mask() -> 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;
        /// Treat the directory referred to by dirfd as the root
        /// directory while resolving path.  Absolute symbolic
        /// links are interpreted relative to dirfd.  If a
        /// prefix component of path equates to dirfd, then an
        /// immediately following .. component likewise equates
        /// to dirfd (just as /.. is traditionally equivalent to
        /// /).  If path is absolute, it is also interpreted
        /// relative to dirfd.
        ///
        /// The effect of this flag is as though the calling
        /// process had used chroot(2) to (temporarily) modify
        /// its root directory (to the directory referred to by
        /// dirfd).  However, unlike chroot(2) (which changes
        /// the filesystem root permanently for a process),
        /// RESOLVE_IN_ROOT allows a program to efficiently
        /// restrict path resolution on a per-open basis.
        ///
        /// Currently, this flag also disables magic-link
        /// resolution.  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_IN_ROOT = 1 << 4;
        /// Do not resolve symbolic links for any of the path components.
        const NO_RESOLVE_PATH = 1 << 5;
        /// Do not resolve proc magic symbolic links.
        const NO_RESOLVE_PROC = 1 << 6;
        /// Do not traverse through mount points.
        const NO_RESOLVE_XDEV = 1 << 7;
        /// Do not traverse through `..` components.
        const NO_RESOLVE_DOTDOT = 1 << 8;
        /// 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 << 9;
        ///
        /// 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 << 10;
    }
}

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 components 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::NO_RESOLVE_PATH | Self::NO_RESOLVE_PROC) {
            Errno::ELOOP
        } else if self.intersects(Self::RESOLVE_BENEATH | Self::RESOLVE_IN_ROOT) {
            Errno::EXDEV
        } 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_PATH
                | Self::NO_RESOLVE_PROC
                | Self::RESOLVE_BENEATH
                | Self::RESOLVE_IN_ROOT,
        )
    }

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

    /// Return true if read mode is requested.
    pub fn want_read(self) -> bool {
        self.contains(Self::WANT_READ)
    }

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

    /// Return true if the base path is requested.
    pub fn want_base(self) -> bool {
        self.contains(Self::WANT_BASE)
    }
}

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::RESOLVE_BENEATH) {
            flags.push("resolve-beneath");
        }
        if self.contains(Self::RESOLVE_IN_ROOT) {
            flags.push("resolve-in-root");
        }
        if self.contains(Self::NO_RESOLVE_PATH) {
            flags.push("resolve-no-symlinks");
        }
        if self.contains(Self::NO_RESOLVE_PROC) {
            flags.push("resolve-no-magiclinks");
        }
        if self.contains(Self::NO_RESOLVE_XDEV) {
            flags.push("resolve-no-xdev");
        }
        if self.contains(Self::NO_RESOLVE_DOTDOT) {
            flags.push("resolve-no-dotdot");
        }
        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::WANT_BASE) {
            flags.push("want-base");
        }
        if self.contains(Self::WANT_READ) {
            flags.push("want-read");
        }

        serializer.collect_seq(flags)
    }
}

/// 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
    MagicLnk(ProcMagic),
    /// Represents a memory file descriptor.
    Mfd,
    /// 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(magic) => {
                if let Ok(p) = magic.link_path() {
                    format!("mgc@{p}")
                } else {
                    "mgc@?".to_string()
                }
            }
            Self::Mfd => "memfd".to_string(),
            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 {
        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(magic) if magic.want_dir())
    }

    /// Test whether file type represents a memory fd.
    pub fn is_memory_fd(self) -> bool {
        self == Self::Mfd
    }

    /// 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
    }

    /// Returns the file type as `mode_t`.
    ///
    /// Returns `None` if file type can't be represented as `mode_t`.
    pub fn mode(self) -> Option<mode_t> {
        match self {
            Self::Blk => Some(S_IFBLK),
            Self::Chr => Some(S_IFCHR),
            Self::Dir => Some(S_IFDIR),
            Self::Fifo => Some(S_IFIFO),
            Self::Lnk => Some(S_IFLNK),
            Self::Reg => Some(S_IFREG),
            Self::Sock => Some(S_IFSOCK),
            _ => None,
        }
    }
}

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.
pub fn file_type<Fd: AsFd>(
    fd: Fd,
    p: Option<&XPath>,
    follow_symlinks: bool,
) -> Result<FileType, Errno> {
    if let Some(p) = p {
        statx(
            fd,
            p,
            if p.is_empty() {
                AT_EMPTY_PATH
            } else if follow_symlinks {
                0
            } else {
                AT_SYMLINK_NOFOLLOW
            },
            STATX_TYPE,
        )
    } else {
        fstatx(fd, STATX_TYPE)
    }
    .map(|statx| FileType::from(mode_t::from(statx.stx_mode)))
}

/// 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<Fd: AsFd, P: NixPath + ?Sized>(
    fd: Fd,
    base: &P,
) -> Result<(File, FileStatx), Errno> {
    // Open the file with O_PATH.
    let fd = safe_open_path(fd, base, OFlag::O_NOFOLLOW, ResolveFlag::empty())?;

    // 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(mode_t::from(statx.stx_mode));
    if !ftype.is_file() {
        return Err(Errno::ENOEXEC);
    }

    // Reopen the file safely via /proc/thread-self/fd.
    // Note, we cannot use RESOLVE_NO_{MAGIC,SYM}LINKS or O_NOFOLLOW here.
    let pfd = XPathBuf::from_self_fd(fd.as_raw_fd())?;

    let flags = OFlag::O_RDONLY | OFlag::O_NOCTTY | OFlag::O_CLOEXEC;
    let file = safe_open_msym(PROC_FILE(), &pfd, flags, ResolveFlag::empty()).map(File::from)?;

    // Return the File and FileStatx.
    Ok((file, 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, P>(dst: &mut F, src: &P) -> Result<u64, Errno>
where
    F: WriteFd,
    P: NixPath + ?Sized,
{
    let how = safe_open_how(OFlag::O_PATH, ResolveFlag::empty());

    // SAFETY: This function is only called before sandboxing.
    #[expect(clippy::disallowed_methods)]
    let fd = if let Ok(fd) = retry_on_eintr(|| openat2(AT_FDCWD, src, how)) {
        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(mode_t::from(statx.stx_mode));
    if !ftype.is_file() {
        return Err(Errno::ENOEXEC);
    }

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

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

    // SAFETY: This function is only called before sandboxing.
    #[expect(clippy::disallowed_methods)]
    let mut src = if let Ok(src) = retry_on_eintr(|| openat2(AT_FDCWD, &pfd, how).map(File::from)) {
        src
    } else {
        return Ok(0);
    };

    crate::io::copy(&mut src, dst)
}

/// Return a safe OpenHow structure.
pub fn safe_open_how(flags: OFlag, rflags: ResolveFlag) -> 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(
            rflags
                | 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, rflags: ResolveFlag) -> 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(rflags | ResolveFlag::RESOLVE_NO_MAGICLINKS | ResolveFlag::RESOLVE_NO_SYMLINKS)
}

/// Return a safe OpenHow structure without O_NOFOLLOW,
/// RESOLVE_NO_MAGICLINKS and RESOLVE_NO_SYMLINKS.
pub fn safe_open_how_msym(flags: OFlag, rflags: ResolveFlag) -> 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)
        .resolve(rflags)
}

/// Open a path safely using O_PATH and return an OwnedFd.
pub fn safe_open_path<Fd: AsFd, P: NixPath + ?Sized>(
    fd: Fd,
    base: &P,
    flags: OFlag,
    rflags: ResolveFlag,
) -> Result<OwnedFd, Errno> {
    safe_open(fd, base, OFlag::O_PATH | flags, rflags)
}

/// Open a path safely and return an OwnedFd.
pub fn safe_open<Fd: AsFd, P: NixPath + ?Sized>(
    fd: Fd,
    base: &P,
    flags: OFlag,
    rflags: ResolveFlag,
) -> Result<OwnedFd, Errno> {
    let how = safe_open_how(flags, rflags);
    base.with_nix_path(|cstr| {
        let xp = XPath::from_bytes(cstr.to_bytes());
        let (fd, base) = if xp.is_relative() {
            (fd.as_fd(), cstr)
        } else if xp.is_rootfs() {
            unreachable!("BUG: Attempt to reopen /");
        } else {
            // SAFETY:
            // Skip initial slashes, and open wrt. the static root-fd.
            // This ensures this function cannot be misused to escape rootfs.
            let n = xp
                .as_bytes()
                .iter()
                .position(|&b| b != b'/')
                .ok_or(Errno::ENOENT)?;
            let xp = &cstr.to_bytes_with_nul()[n..];
            // SAFETY: `with_nix_path` ensures:
            // 1. `xp` is null terminated.
            // 2. `xp` does not contain any interior null bytes.
            let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(xp) };
            (ROOT_FILE(), cstr)
        };
        retry_on_eintr(|| safe_openat2(fd, base, how))
    })?
}

/// Open an absolute path safely using O_PATH and return an OwnedFd.
pub fn safe_open_path_abs<P: NixPath + ?Sized>(
    path: &P,
    flags: OFlag,
    rflags: ResolveFlag,
) -> Result<OwnedFd, Errno> {
    safe_open_abs(path, OFlag::O_PATH | flags, rflags)
}

/// Open an absolute path safely and return an OwnedFd.
pub fn safe_open_abs<P: NixPath + ?Sized>(
    path: &P,
    flags: OFlag,
    rflags: ResolveFlag,
) -> Result<OwnedFd, Errno> {
    let how = safe_open_how_abs(flags, rflags);
    path.with_nix_path(|cstr| {
        // SAFETY: Ensure path is an absolute path.
        let xp = XPath::from_bytes(cstr.to_bytes());
        if xp.is_relative() {
            return Err(Errno::EINVAL);
        }

        #[expect(clippy::disallowed_methods)]
        retry_on_eintr(|| openat2(AT_FDCWD, cstr, how))
    })?
}

/// Open a magic symlink safely using O_PATH and return an OwnedFd.
pub fn safe_open_path_msym<Fd: AsFd, P: NixPath + ?Sized>(
    fd: Fd,
    base: &P,
    flags: OFlag,
    rflags: ResolveFlag,
) -> Result<OwnedFd, Errno> {
    safe_open_msym(fd, base, OFlag::O_PATH | flags, rflags)
}

/// Open a magic symlink safely and return an OwnedFd.
pub fn safe_open_msym<Fd: AsFd, P: NixPath + ?Sized>(
    fd: Fd,
    base: &P,
    flags: OFlag,
    rflags: ResolveFlag,
) -> Result<OwnedFd, Errno> {
    let how = safe_open_how_msym(flags, rflags);
    base.with_nix_path(|cstr| {
        let xp = XPath::from_bytes(cstr.to_bytes());
        let (fd, base) = if xp.is_relative() {
            (fd.as_fd(), cstr)
        } else if xp.is_rootfs() {
            unreachable!("BUG: Attempt to reopen /");
        } else {
            // SAFETY:
            // Skip initial slashes, and open wrt. the static root-fd.
            // This ensures this function cannot be misused to escape rootfs.
            let n = xp
                .as_bytes()
                .iter()
                .position(|&b| b != b'/')
                .ok_or(Errno::ENOENT)?;
            let xp = &cstr.to_bytes_with_nul()[n..];
            // SAFETY: `with_nix_path` ensures:
            // 1. `xp` is null terminated.
            // 2. `xp` does not contain any interior null bytes.
            let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(xp) };
            (ROOT_FILE(), cstr)
        };
        retry_on_eintr(|| safe_openat2(fd, base, how))
    })?
}

// We handle {Root,Cur}Dir transparently for efficiency.
// `None` stands for `ParentDir` which allows us to avoid an oversized enum.
#[derive(Debug, Default, PartialEq)]
struct PathComponent<'a>(Option<Cow<'a, XPath>>);

type PathComponentVec<'a> = TinyVec<[PathComponent<'a>; 48]>;

impl PathComponent<'_> {
    const PARENT_DIR: Self = Self(None);
}

impl Serialize for PathComponent<'_> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        // SAFETY: XPath masks control characters in log output.
        let comp = match self.0.as_ref() {
            Some(p) => p,
            None => XPath::dotdot(),
        };

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

// Generates a TinyVec of path components in reverse order.
// - 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.
fn path_components(path: &XPath) -> Result<(PathComponentVec<'_>, bool), Errno> {
    // Create a new searcher for the '/' character.
    let path = path.as_os_str().as_bytes();
    let searcher = One::new(b'/');

    let mut off = 0;
    let mut components = TinyVec::new();
    #[expect(clippy::arithmetic_side_effects)]
    for pos in searcher.iter(path) {
        let len = pos - off;
        match len {
            0 => {}                      // Skip empty component.
            1 if path[off] == b'.' => {} // Skip current directory component.
            2 if path[off] == b'.' && path[off + 1] == b'.' => {
                components.push(PathComponent::PARENT_DIR);
            }
            1..PATH_MAX => {
                components.push(PathComponent(Some(Cow::Borrowed(XPath::from_bytes(
                    &path[off..pos],
                )))));
            }
            _ => return Err(Errno::ENAMETOOLONG),
        }
        off = pos + 1; // Move past the '/'.
    }

    // Handle the last component if it's not ended by a slash.
    #[expect(clippy::arithmetic_side_effects)]
    let slash = if off < path.len() {
        let len = path.len() - off;
        match len {
            // 0 => unreachable!(),
            1 if path[off] == b'.' => {
                // Skip current directory component.
                components.is_empty() || (off >= 1 && path[off - 1] == b'/')
            }
            2 if path[off] == b'.' && path[off + 1] == b'.' => {
                components.push(PathComponent::PARENT_DIR);
                true
            }
            1..PATH_MAX => {
                components.push(PathComponent(Some(Cow::Borrowed(XPath::from_bytes(
                    &path[off..],
                )))));
                false
            }
            _ => return Err(Errno::ENAMETOOLONG),
        }
    } else {
        true
    };

    // Reverse so pop() returns components in forward order.
    components.reverse();

    Ok((components, slash))
}

// Adds path components from a symlink target to the component stack in reverse order.
fn path_components2(path: &XPath, components: &mut PathComponentVec) -> Result<(), Errno> {
    // Create a new searcher for the '/' character.
    let path = path.as_os_str().as_bytes();
    let searcher = One::new(b'/');

    let mut off = 0;
    let mut new_components: PathComponentVec = TinyVec::new();
    #[expect(clippy::arithmetic_side_effects)]
    for pos in searcher.iter(path) {
        let len = pos - off;
        match len {
            0 => {}                      // Skip empty components.
            1 if path[off] == b'.' => {} // Skip current directory component.
            2 if path[off] == b'.' && path[off + 1] == b'.' => {
                new_components.push(PathComponent::PARENT_DIR);
            }
            1..PATH_MAX => {
                new_components.push(PathComponent(Some(Cow::Owned(path[off..pos].into()))));
            }
            _ => return Err(Errno::ENAMETOOLONG),
        }
        off = pos + 1; // Move past the '/'.
    }

    // Handle the last component if it's not ended by a slash.
    #[expect(clippy::arithmetic_side_effects)]
    if off < path.len() {
        let len = path.len() - off;
        match len {
            1 if path[off] == b'.' => {} // Skip current directory component.
            2 if path[off] == b'.' && path[off + 1] == b'.' => {
                new_components.push(PathComponent::PARENT_DIR);
            }
            1..PATH_MAX => {
                // Preserve trailing slash for directory assertion.
                let mut component: XPathBuf = path[off..].into();
                if path.ends_with(b"/") {
                    component.append_byte(b'/');
                }
                new_components.push(PathComponent(Some(Cow::Owned(component))));
            }
            _ => return Err(Errno::ENAMETOOLONG),
        }
    }

    // Reverse new components to match storage order,
    // and append to the end of components, which is
    // the logical front with reversed storage.
    new_components.reverse();

    components.extend(new_components);

    Ok(())
}

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

    let mut dir: Box<dyn AsFd> = Box::new(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 {
                openat(
                    dir.as_fd().as_raw_fd(),
                    dotdot_with_nul() as *const c_char,
                    flags,
                    0,
                )
            })
        })
        .map(|fd| {
            // SAFETY: openat returns a valid FD on success.
            unsafe { OwnedFd::from_raw_fd(fd) }
        })?;
        dir = Box::new(fd);

        let info = FileInfo::from_fd(&dir)?;
        if info == pinfo {
            // Current file information and parent are the same:
            // We have reached the root directory.
            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);
        }

        // There's no guarantee on the order of items returned by getdents64(2).
        // Therefore we must potentially check each element for dot or dotdot,
        // until we actually see one.
        let mut found = false;
        let mut seen_dot = false;
        let mut seen_dotdot = false;
        let new_device = info.mnt != pinfo.mnt;
        'main: loop {
            let mut entries = match getdents64(&dir, DIRENT_BUF_SIZE) {
                Ok(entries) => entries,
                Err(Errno::ECANCELED) => break, // EOF or empty directory
                Err(errno) => return Err(errno),
            };

            for entry in &mut entries {
                if !seen_dot && entry.is_dot() {
                    seen_dot = true;
                    continue;
                }
                if !seen_dotdot && entry.is_dotdot() {
                    seen_dotdot = true;
                    continue;
                }

                if !new_device && entry.ino() != pinfo.ino {
                    // This is not our directory entry, continue.
                    continue;
                }
                if pinfo
                    != statx(
                        &dir,
                        entry.as_xpath(),
                        AT_SYMLINK_NOFOLLOW,
                        FileInfo::mask(),
                    )
                    .map(FileInfo::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 {
            return Err(Errno::ENOENT);
        }
    }

    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 AsFd for MaybeFd {
    fn as_fd(&self) -> BorrowedFd<'_> {
        match self {
            MaybeFd::Owned(owned) => owned.as_fd(),
            // SAFETY: RawFd is alive as long as MaybeFd.
            MaybeFd::RawFd(fd) => unsafe { BorrowedFd::borrow_raw(*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 Default for MaybeFd {
    fn default() -> Self {
        Self::RawFd(AT_BADFD.as_raw_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, Clone, Default)]
pub(crate) struct FileMapEntry {
    pub(crate) fd: MaybeFd,
    f_type: Option<FileType>,
    f_mode: Option<u16>,
    mnt_id: Option<u64>,
    pub(crate) target: Option<Result<Arc<XPathBuf>, Errno>>,
    nvisit: u8, // symlink visit count, used for loop detection.
}

impl FileMapEntry {
    pub(crate) fn new(
        fd: MaybeFd,
        f_type: Option<FileType>,
        f_mode: Option<u16>,
        mnt_id: Option<u64>,
        target: Option<Result<Arc<XPathBuf>, Errno>>,
    ) -> Self {
        Self {
            fd,
            f_type,
            f_mode,
            mnt_id,
            target,
            nvisit: 1,
        }
    }

    pub(crate) fn from_magic_link(
        magic: ProcMagic,
        want_dir: bool,
        sandbox: Option<&Sandbox>,
    ) -> Result<(Self, Arc<XPathBuf>), Errno> {
        // Create path to symlink.
        let remote_sym = magic.link_path()?;

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

        let fd = safe_open_msym(PROC_FILE(), &remote_sym, flags, ResolveFlag::empty())?;
        let sym = XPathBuf::from_self_fd(fd.as_raw_fd())?;

        // Step 2: Try to readlink().
        let (target, is_deleted, is_mfd) = match readlinkat(PROC_FILE(), &sym) {
            Ok(mut p) => {
                if p.is_relative() {
                    // /proc/1/fd/42 -> pipe:[4242], socket:[4242]
                    if magic.want_dir() {
                        return Err(Errno::EBADF);
                    }

                    // 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, false)
                } else if p.ends_with(b" (deleted)") {
                    if p.starts_with(b"/memfd:") {
                        // Memory file descriptor:
                        // 1. Truncate deleted suffix
                        // 2. Change root slash to !
                        // This is used in access check as
                        // !memfd:* or !memfd-hugetlb:*
                        p.truncate(
                            p.len()
                                .checked_sub(b" (deleted)".len())
                                .ok_or(Errno::EOVERFLOW)?,
                        );
                        p.set(0, b'!');
                        (Some(p), false, true)
                    } else {
                        // /proc/1/cwd -> /path/to/foo (deleted)
                        //
                        // This may be a deleted file,
                        // or a file whose name funnily
                        // ends with a genuine " (deleted)" string.
                        //
                        // We will statx(2) and check nlink to tell.
                        (Some(p), true, false)
                    }
                } else {
                    // Genuine file descriptor that points to a valid directory.
                    (Some(p), false, false)
                }
            }
            Err(Errno::ENAMETOOLONG) => (None, false, false),
            Err(errno) => return Err(errno),
        };

        // Ensure magic symlink is /proc prefixed.
        let mut sym = XPathBuf::from("/proc");
        // SAFETY: We do not use XPathBuf::push here
        // to append to the path. `remote_sym` is
        // returned by the host Linux kernel, therefore
        // this is safe against path traversals.
        sym.append_byte(b'/');
        sym.append_bytes(remote_sym.as_bytes());

        if let Some(mut target) = target {
            // SAFETY: Prevent hidden path pass-through via magic symlinks.
            // Passing through root is OK.
            if !target.is_root() && target.is_absolute() {
                if let Some(sandbox) = sandbox {
                    sandbox_path(
                        None,
                        sandbox,
                        magic.pid(),
                        target.deref(),
                        Capability::CAP_WALK,
                        false,
                        "walk",
                    )?;
                }
            }

            // We managed to successfully readlink.
            //
            // Check for deleted entries.
            if is_deleted {
                let stx = retry_on_eintr(|| fstatx(&fd, STATX_TYPE | STATX_NLINK))?;
                let f_type = FileType::from(mode_t::from(stx.stx_mode));

                if stx.stx_nlink == 0 {
                    // File is deleted, strip the deleted suffix.
                    target.truncate(
                        target
                            .len()
                            .checked_sub(b" (deleted)".len())
                            .ok_or(Errno::EOVERFLOW)?,
                    );
                }

                let entry = Self {
                    fd: fd.into(),
                    f_type: Some(f_type),
                    f_mode: None,
                    mnt_id: None,
                    target: Some(Ok(Arc::new(target))),
                    nvisit: 0,
                };

                return Ok((entry, Arc::new(sym)));
            }

            let f_type = if is_mfd {
                // Check for MFD_HUGETLB.
                if is_huge_file(&fd).unwrap_or(false) {
                    target.replace_prefix(MFD_NAME_PREFIX, MFD_HUGETLB_NAME_PREFIX)?;
                }
                Some(FileType::Mfd)
            } else if magic.want_dir() {
                Some(FileType::Dir)
            } else {
                file_type(&fd, None, false).ok()
            };

            let entry = Self {
                fd: fd.into(),
                f_type,
                f_mode: None,
                mnt_id: None,
                target: Some(Ok(Arc::new(target))),
                nvisit: 0,
            };

            return Ok((entry, Arc::new(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 = getdir_long(&fd, PATH_MAX_COMP)?;

        // SAFETY: Prevent hidden path pass-through via magic symlinks.
        // Part 2: Prevent bypass via too-long paths.
        // Passing through root is OK.
        if !target.is_root() && target.is_absolute() {
            if let Some(sandbox) = sandbox {
                sandbox_path(
                    None,
                    sandbox,
                    magic.pid(),
                    target.deref(),
                    Capability::CAP_WALK,
                    false,
                    "walk",
                )?;
            }
        }

        let entry = Self {
            fd: fd.into(),
            f_type: Some(FileType::Dir),
            f_mode: None,
            mnt_id: None,
            target: Some(Ok(Arc::new(target))),
            nvisit: 0,
        };

        Ok((entry, Arc::new(sym)))
    }

    // Return the file information of an entry safely.
    // This is currently only used for symlinks post-readlink
    // for symbolic link detection.
    #[expect(clippy::cast_possible_truncation)]
    fn get_mode(&mut self) -> Result<u16, Errno> {
        // Return mode if we've saved it before.
        if let Some(mode) = self.f_mode {
            return Ok(mode);
        }

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

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

        // Save and return file mode.
        let mode = stx.stx_mode & !(S_IFMT as u16);
        self.f_mode = Some(mode);

        Ok(mode)
    }

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

// Extension methods for FileMap that require lookup-specific types
impl FileMap {
    fn remove(&mut self, path: &XPath) -> Option<FileMapEntry> {
        if path.is_static() {
            self.as_ref().get(path).cloned()
        } else {
            self.as_mut().remove(path)
        }
    }

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

    fn open(
        &mut self,
        pid: Pid,
        path: &XPath,
        options: FsFlags,
        filetyp: Option<FileType>,
        sandbox: Option<&Sandbox>,
    ) -> Result<&mut FileMapEntry, Errno> {
        // SAFETY: Opening a component which is hidden
        // would let us obtain metadata and then
        // resolve through it. Reject early.
        // Passing through root is OK.
        if !path.is_root() {
            if let Some(sandbox) = sandbox {
                sandbox_path(
                    None,
                    sandbox,
                    pid,
                    path,
                    Capability::CAP_WALK,
                    false,
                    "walk",
                )?;
            }
        }

        // SAFETY: rootfs and procfs views must be identical!
        let (parent, base) = path.split();
        let (parent_fd, base) = if let Some(parent_entry) = self.get(parent) {
            (parent_entry.fd.as_fd(), base)
        } else if path.starts_with(b"/proc/") {
            // Avoid multi-component resolution under /proc.
            // Open the immediate parent under /proc as O_PATH|O_DIRECTORY,
            // then open the last component relative to that FD.
            let pfd = if let Some(pfd) = self.get(parent) {
                pfd.fd.as_fd()
            } else {
                // Open /proc-relative parent in a single hop.
                let parent = XPath::from_bytes(&parent.as_bytes()[b"/proc/".len()..]);
                let dfd: MaybeFd = if parent.is_empty() {
                    PROC_FD().into()
                } else {
                    safe_open_path(
                        PROC_FILE(),
                        parent,
                        OFlag::O_DIRECTORY,
                        ResolveFlag::empty(),
                    )?
                    .into()
                };

                // All good, insert entry and return FD.
                self.try_insert(
                    Arc::new(parent.to_owned()),
                    FileMapEntry::new(dfd, Some(FileType::Dir), None, None, None),
                )?;
                // We just inserted, unwrap must return Some.
                #[expect(clippy::disallowed_methods)]
                {
                    self.get(parent).unwrap().fd.as_fd()
                }
            };

            (pfd, base)
        } else {
            let base = XPath::from_bytes(&path.as_bytes()[1..]);
            (ROOT_FILE(), base)
        };

        // SAFETY:
        // 1. Force RESOLVE_NO_XDEV as necessary.
        // 2. RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS | RESOLVE_SYMLINKS
        //    are already enforced by safe_open_path.
        let rflags = if options.contains(FsFlags::NO_RESOLVE_XDEV) {
            ResolveFlag::RESOLVE_NO_XDEV
        } else {
            ResolveFlag::empty()
        };
        let fd = safe_open_path(parent_fd, base, OFlag::O_NOFOLLOW, rflags)?;

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

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

    // Resolve a symbolic link honouring magic proc links.
    #[expect(clippy::cognitive_complexity)]
    fn readlink(
        &mut self,
        path: &XPath,
        pid: Pid,
        options: FsFlags,
        filetyp: Option<FileType>,
        sandbox: Option<&Sandbox>,
    ) -> Result<Arc<XPathBuf>, Errno> {
        if path.is_static() {
            // Static paths are not symlinks.
            return Err(Errno::EINVAL);
        }

        // Check if we have queried this file before.
        let entry = if let Some(entry) = self.as_mut().get_mut(path) {
            match entry.target.as_ref() {
                Some(Ok(target)) => {
                    #[expect(clippy::arithmetic_side_effects)]
                    return if entry.nvisit >= MAXSYMLINKS {
                        // Symbolic link loop detected.
                        Err(Errno::ELOOP)
                    } else {
                        entry.nvisit += 1;
                        Ok(Arc::clone(target))
                    };
                }
                Some(Err(errno)) => {
                    // File is not a symbolic link.
                    return Err(*errno);
                }
                None => entry,
            }
        } else {
            self.open(pid, path, options, filetyp, sandbox)?
        };

        // All done, resolve symbolic link.
        let target = match readlinkfd(&entry.fd) {
            Ok(target) => target,
            Err(errno) => {
                // Mark resolve fail in target.
                entry.target = Some(Err(errno));
                return Err(errno);
            }
        };

        let force_no_symlinks = sandbox
            .map(|sb| sb.flags.force_no_symlinks())
            .unwrap_or(false);
        if force_no_symlinks || !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.
        let target = Arc::new(target);
        entry.target = Some(Ok(Arc::clone(&target)));

        // SAFETY:
        // Restrictions a la CONFIG_GRKERNSEC_LINK:
        // Do not follow symbolic links if the parent directory
        // has either one of the following:
        // 1. sticky-bit set.
        // 2. world-writable.
        // 3. group-writable.
        let restrict_symlinks = sandbox
            .map(|sb| !sb.flags.allow_unsafe_symlinks())
            .unwrap_or(false);
        if restrict_symlinks {
            // FIXME: This check is going to be bypassed
            // in case parent is not open yet, which is
            // indeed possible under some circumstances.
            if let Some(entry) = self.as_mut().get_mut(path.parent()) {
                let mut err = None;
                let mode: u32 = entry.get_mode()?.into();
                if mode & S_ISVTX != 0 {
                    err = Some("parent directory has sticky bit set");
                } else if mode & S_IWOTH != 0 {
                    err = Some("parent directory is world writable");
                } else if mode & S_IWGRP != 0 {
                    err = Some("parent directory is group writable");
                }

                if let Some(msg) = err {
                    error!("ctx": "trusted_symlinks", "path": path,
                        "pid": pid.as_raw(), "rflags": options,
                        "msg": format!("follow for untrusted symlink blocked: {msg}"),
                        "tip": "fix parent directory permissions or use `trace/allow_unsafe_symlinks:1'");
                    return Err(Errno::ELOOP);
                }
            }
        }

        // RESOLVE_NO_MAGICLINKS is handled by ProcMagic::check_link() in canonicalize().
        Ok(target)
    }

    // Return the mount id and file type of a path safely.
    fn get_mnt_id(
        &mut self,
        path: &XPath,
        pid: Pid,
        options: FsFlags,
        filetyp: Option<FileType>,
        sandbox: Option<&Sandbox>,
    ) -> 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) = self.as_mut().get_mut(path) {
            entry
        } else {
            self.open(pid, path, options, filetyp, sandbox)?
        };

        // 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 f_type = FileType::from(mode_t::from(stx.stx_mode));
            entry.f_type = Some(f_type);
        }

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

        Ok(mnt_id)
    }
}

/// Return value of `safe_canonicalize`.
#[derive(Debug)]
pub struct CanonicalPath {
    /// 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.
    pub abs: XPathBuf,

    /// The index of the final, base component of the path.
    ///
    /// This is an index into the `abs` element.
    /// This may be 0 in which case `dir` must be used.
    pub base_offset: usize,

    /// 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 CanonicalPath {
    /// 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 memory fd.
    pub fn is_memory_fd(&self) -> bool {
        self.typ
            .as_ref()
            .map(|typ| typ.is_memory_fd())
            .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.
    pub fn abs(&self) -> &XPath {
        self.abs.as_ref()
    }

    /// Returns a reference to the final, base, component of path.
    ///
    /// This may be empty in which case `dir` must be used.
    pub fn base(&self) -> &XPath {
        if self.base_offset > 0 {
            XPath::from_bytes(&self.abs.0.as_slice()[self.base_offset..])
        } else {
            XPath::empty()
        }
    }

    /// Returns a reference to the parent 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.
    pub fn parent(&self) -> &XPath {
        self.abs().split().0
    }

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

    /// Set the absolute path of the given `CanonicalPath`.
    ///
    /// Panics if `base` is not empty to prevent dangling references.
    pub fn set_abs(&mut self, path: XPathBuf) {
        assert_eq!(
            self.base_offset, 0,
            "BUG: set_abs called with base index {}!",
            self.base_offset
        );
        self.abs = path;
    }

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

    /// Create a new `CanonicalPath` for (saved) `/proc`.
    ///
    /// This fd is opened at startup.
    pub fn new_proc() -> CanonicalPath {
        Self {
            abs: XPathBuf::from("/proc"),
            base_offset: 0,
            dir: Some(PROC_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 {
        Self {
            abs: virtual_path,
            base_offset: 0,
            dir: Some(NULL_FD().into()),
            typ: Some(FileType::Chr),
        }
    }

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

    /// Create a new `CanonicalPath` for the given mask path.
    pub fn new_mask(mask: &XPath, abs: &XPath) -> Result<CanonicalPath, Errno> {
        let base = XPath::from_bytes(&mask.as_bytes()[b"/".len()..]);
        let fd = safe_open_path(ROOT_FILE(), base, OFlag::O_NOFOLLOW, ResolveFlag::empty())?;
        let typ = file_type(&fd, None, false)?;

        Ok(Self {
            abs: abs.to_owned(), // Points to the original path.
            base_offset: 0,
            dir: Some(fd.into()), // Points to the mask path.
            typ: Some(typ),
        })
    }

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

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

        Ok(Self {
            abs,
            base_offset: 0,
            dir: Some(fd.into()),
            typ: Some(FileType::Chr),
        })
    }

    /// Create a new `CanonicalPath` from a crypt file descriptor.
    pub fn new_crypt(fd: MaybeFd, abs: XPathBuf) -> CanonicalPath {
        Self {
            abs,
            base_offset: 0,
            dir: Some(fd),
            typ: Some(FileType::Reg),
        }
    }

    /// 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) -> Result<CanonicalPath, Errno> {
        // Step 1: Open CWD using the magic symlink.
        let cwd = fd.as_raw_fd() == libc::AT_FDCWD;
        if cwd {
            let flags = OFlag::O_PATH | OFlag::O_DIRECTORY;
            let cwd = XPathBuf::from_cwd(pid)?;
            fd = safe_open_msym(PROC_FILE(), &cwd, flags, ResolveFlag::empty())?.into();
        }
        let sym = XPathBuf::from_self_fd(fd.as_raw_fd())?;

        // Step 2: Try to readlink().
        let (target, is_deleted, is_mfd) = match readlinkat(PROC_FILE(), &sym) {
            Ok(mut 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, false)
                } else if p.ends_with(b" (deleted)") {
                    if p.starts_with(b"/memfd:") {
                        // Memory file descriptor:
                        // 1. Truncate deleted suffix
                        // 2. Change root slash to !
                        // This is used in access check as
                        // !memfd:* or !memfd-hugetlb:*
                        p.truncate(
                            p.len()
                                .checked_sub(b" (deleted)".len())
                                .ok_or(Errno::EOVERFLOW)?,
                        );
                        p.set(0, b'!');
                        (Some(p), false, true)
                    } else {
                        // /proc/1/cwd -> /path/to/foo (deleted)
                        //
                        // This may be a deleted file,
                        // or a file whose name funnily
                        // ends with a genuine " (deleted)" string.
                        //
                        // We will statx(2) and check nlink to tell.
                        (Some(p), true, false)
                    }
                } else {
                    // Genuine file descriptor that points to a valid directory.
                    (Some(p), false, false)
                }
            }
            Err(Errno::ENOENT) => return Err(Errno::EBADF),
            Err(Errno::ENAMETOOLONG) => (None, false, false),
            Err(errno) => return Err(errno),
        };

        if let Some(mut path) = target {
            // We managed to successfully readlink.
            //
            // Check for deleted entries.
            if is_deleted {
                // Check if path is really deleted.
                let stx = retry_on_eintr(|| fstatx(&fd, STATX_TYPE | STATX_NLINK))?;
                let f_type = FileType::from(mode_t::from(stx.stx_mode));

                if stx.stx_nlink == 0 {
                    // File is deleted, strip the deleted suffix.
                    #[expect(clippy::arithmetic_side_effects)]
                    path.truncate(path.len() - b" (deleted)".len());
                }

                return Ok(Self {
                    abs: path,
                    base_offset: 0,
                    dir: Some(fd),
                    typ: Some(f_type),
                });
            }

            let file_type = if is_mfd {
                // Check for MFD_HUGETLB.
                if is_huge_file(&fd).unwrap_or(false) {
                    path.replace_prefix(MFD_NAME_PREFIX, MFD_HUGETLB_NAME_PREFIX)?;
                }
                Some(FileType::Mfd)
            } else if cwd {
                Some(FileType::Dir)
            } else {
                file_type(&fd, None, false).ok()
            };

            return Ok(Self {
                abs: path,
                base_offset: 0,
                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 PATH_MAX_COMP so the sandbox
        //    process cannot create arbitrarily long directories and
        //    crash Syd.
        let path = getdir_long(&fd, PATH_MAX_COMP)?;

        Ok(Self {
            abs: path,
            base_offset: 0,
            dir: Some(fd),
            typ: Some(FileType::Dir),
        })
    }

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

        let follow_last = options.follow_last();
        let (mut is_magic_link, magic_base) = match typ {
            Some(FileType::MagicLnk(magic @ (ProcMagic::Pid { .. } | ProcMagic::Tid { .. }))) => {
                if follow_last {
                    (false, magic.base()?)
                } else {
                    (true, None)
                }
            }
            Some(FileType::MagicLnk(ref magic)) => (true, magic.base()?),
            _ => (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 {
            #[expect(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 mut is_magic_dot: bool = false;
        let (parent, mut base) = abs.split();

        // SAFETY: magic links are _always_ prefixed with `/proc`.
        // Hence the `unwrap` in the second branch is fine.
        #[expect(clippy::disallowed_methods)]
        let (parent_fd, has_parent) = if let Some(ref entry) = entry {
            // SAFETY: Use the O_PATH fd to determine file type
            // to avoid TOCTTOU. The file type is going to be used
            // during sandbox access check and therefore it's
            // security critical.
            typ = if let Some(f_type) = entry.f_type {
                Some(f_type)
            } else {
                file_type(&entry.fd, None, false).ok()
            };

            // SAFETY: The arguments we return here are only going to be
            // used in case we're re-opening the file for read. In this case,
            // we fall-back to `/proc/thread-self/fd` indirection to ensure
            // this is TOCTTOU free.
            //
            magic_parent = XPathBuf::from_self_fd(entry.fd.as_raw_fd())?;
            base = &magic_parent;
            is_magic_link = true; // Avoids ELOOP.

            (PROC_FD().into(), false)
        } else 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(f_type)) = entry.as_ref().map(|e| e.f_type) {
                    Some(f_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.len() >= PATH_MAX {
            // Open using dotdot reference.
            let mut child_fd = None;
            let mut n_dotdot = 0;
            for entry in filemap.iter() {
                if let Some(pfx) = entry.0.strip_prefix(abs.as_bytes()) {
                    child_fd = Some(MaybeFd::RawFd(entry.1.fd.as_fd().as_raw_fd()));
                    n_dotdot = pfx.depth();
                    break;
                }
            }
            let child_fd = child_fd.ok_or(Errno::ENAMETOOLONG)?;
            magic_parent = XPathBuf::from("..");
            for _ in 1..n_dotdot {
                magic_parent.append_bytes(b"/..");
            }
            base = &magic_parent;
            typ = Some(FileType::Dir);
            is_magic_dot = true; // Avoids dotdot desync TOCTOU.
            is_magic_link = true; // Avoids EXDEV.
            (child_fd, 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(f_type)) = entry.as_ref().map(|e| e.f_type) {
                    Some(f_type)
                } else {
                    file_type(PROC_FILE(), Some(base), false).ok()
                };
            }

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

            if !is_magic_link {
                typ = if let Some(Some(f_type)) = entry.as_ref().map(|e| e.f_type) {
                    Some(f_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.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);
        }

        // Do we want to open the file or the owning directory?
        let open_parent = options.intersects(FsFlags::MISS_LAST | FsFlags::WANT_BASE)
            || (typ.is_none() && !options.must_exist());

        if open_parent {
            // 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"/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(
                        PROC_FILE(),
                        parent_base,
                        OFlag::O_DIRECTORY,
                        ResolveFlag::empty(),
                    )?
                    .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(
                        ROOT_FILE(),
                        parent_base,
                        OFlag::O_DIRECTORY,
                        ResolveFlag::empty(),
                    )?
                    .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();

            // Preserve trailing slash to assert directory
            // after sandbox path hide check.
            if has_trailing_slash {
                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.
            //
            // When parent is "/", parent_len == 1 and we must NOT skip another byte.
            // For all other parents we skip the separating '/'.
            #[expect(clippy::arithmetic_side_effects)]
            let base_offset = parent_len + usize::from(parent_len > 1);

            return Ok(Self {
                abs,
                base_offset,
                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)
        };

        // If the original path had a trailing slash,
        // require a directory on the final open
        // including magic symlinks.
        if has_trailing_slash || matches!(typ, Some(FileType::Dir)) {
            flags.insert(OFlag::O_DIRECTORY);
        }

        // 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.
        //
        // This restriction may be relaxed using trace/allow_unsafe_mkbdev:1.
        if restrict_mkbdev && is_read && typ.as_ref().map(|t| t.is_block_device()).unwrap_or(false)
        {
            return Err(Errno::ENOENT);
        }

        // If read is not requested return the O_PATH fd we opened.
        if !is_read {
            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'/');
                }

                // Handle O_NOFOLLOW for magic symbolic links.
                let mut magic_fd = None;
                let mut magic_ln = None;
                if !follow_last {
                    if let Some(FileType::MagicLnk(magic)) = entry.f_type {
                        // Create path to symlink.
                        let remote_sym = magic.link_path()?;

                        // Open a O_PATH|O_NOFOLLOW fd to the magiclink.
                        magic_fd = Some(
                            safe_open_path(
                                PROC_FILE(),
                                &remote_sym,
                                OFlag::empty(),
                                ResolveFlag::empty(),
                            )?
                            .into(),
                        );

                        // Prepare absolute path to the magiclink.
                        let mut remote_abs = XPathBuf::from("/proc/");

                        // SAFETY: `remote_sym` is returned by the host Linux kernel:
                        // 1. Link contents are trusted.
                        // 2. Link contents may contain slashes.
                        remote_abs.append_bytes(remote_sym.as_bytes());

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

                        magic_ln = Some(remote_abs);
                    }
                }

                return Ok(Self {
                    abs: magic_ln.unwrap_or(abs),
                    base_offset: 0,
                    dir: Some(magic_fd.unwrap_or(entry.fd)),
                    typ,
                });
            }
        }

        // If we must NOT resolve the last component and it is a regular symlink,
        // we must open the link object with O_PATH (not O_RDONLY).
        if !follow_last && matches!(typ, Some(FileType::Lnk)) {
            flags.remove(OFlag::O_RDONLY | OFlag::O_NONBLOCK | OFlag::O_NOCTTY);
            flags.insert(OFlag::O_PATH | OFlag::O_NOFOLLOW);
            if has_trailing_slash {
                flags.insert(OFlag::O_DIRECTORY);
            }
        }

        // 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_msym(parent_fd, base, flags, ResolveFlag::empty())
        } else {
            // O_NOFOLLOW already set here.
            safe_open(parent_fd, base, flags, ResolveFlag::empty())
        }?;

        // SAFETY: Resync after dotdot open to avoid TOCTOU.
        if is_magic_dot {
            abs = getdir_long(&fd, PATH_MAX_COMP)?;
        }

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

        Ok(Self {
            abs,
            base_offset: 0,
            dir: Some(fd.into()),
            typ,
        })
    }
}

/// 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.
#[expect(clippy::cognitive_complexity)]
pub fn safe_canonicalize(
    pid: Pid,
    fd: Option<RawFd>,
    path: &XPath,
    mut options: FsFlags,
    sandbox: Option<&Sandbox>,
) -> Result<CanonicalPath, Errno> {
    // Safely initialize flags.
    let flags = sandbox.map(|sb| *sb.flags).unwrap_or_default();

    // Validate options.
    let resolve_beneath = options.contains(FsFlags::RESOLVE_BENEATH);
    let resolve_in_root = options.contains(FsFlags::RESOLVE_IN_ROOT);
    if resolve_beneath && resolve_in_root {
        return Err(Errno::EINVAL);
    }

    // Validate path.
    if path.is_empty() {
        return Err(Errno::ENOENT);
    }

    // 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;

    let (mut result, cwd) = if resolve_in_root || path.is_relative() {
        if let Some(fd) = fd {
            let magic = if fd == libc::AT_FDCWD {
                ProcMagic::Cwd { pid }
            } else if fd < 0 {
                return Err(Errno::EBADF);
            } else {
                ProcMagic::Fd { pid, fd }
            };
            let (mut entry, sym) =
                FileMapEntry::from_magic_link(magic, true, sandbox).map_err(|e| {
                    // SAFETY: Return bad-fd rather than no-such-file for genuine fds.
                    if e == Errno::ENOENT {
                        Errno::EBADF
                    } else {
                        e
                    }
                })?;

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

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

            entry.f_type = Some(FileType::Dir);
            filemap.try_insert(Arc::clone(&dir), entry)?;
            filemap.try_insert(sym, entry_sym)?;

            (dir.try_clone()?, Arc::clone(&dir))
        } else {
            let magic = ProcMagic::Cwd { pid };
            let (mut entry, sym) = FileMapEntry::from_magic_link(magic, true, sandbox)?;

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

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

            entry.f_type = Some(FileType::Dir);
            filemap.try_insert(Arc::clone(&dir), entry)?;
            filemap.try_insert(sym, entry_sym)?;

            (dir.try_clone()?, Arc::clone(&dir))
        }
    } 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_procfs() {
        // Special case, `/proc` is never a symlink.
        // This must be done after the RESOLVE_BENEATH check!
        return Ok(CanonicalPath::new_proc());
    } else {
        // Absolute path, CWD is ignored.
        (XPathBuf::from("/"), Arc::new(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 = if flags.force_no_magiclinks() {
        options.insert(FsFlags::NO_RESOLVE_PROC);
        false
    } else {
        options.resolve_proc()
    };
    // Do we want to traverse through mount points?
    //
    // As of version 3.39.0 this may be enforced
    // using the trace/force_no_xdev option.
    let resolve_xdev = if flags.force_no_xdev() {
        options.insert(FsFlags::NO_RESOLVE_XDEV);
        false
    } else {
        !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 symlinks in sticky-bit, group/world-writable dirs.
    let restrict_symlinks = !flags.allow_unsafe_symlinks();

    // Restriction for /proc magic links.
    let restrict_magiclinks = !flags.allow_unsafe_magiclinks();

    // Restriction for block devices.
    let restrict_mkbdev = !flags.allow_unsafe_mkbdev();

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

    // Do we want the base component of the path?
    let want_base = options.want_base();

    // 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:?}"));

    // 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 {
        Some(filemap.get_mnt_id(&cwd, pid, options, file_type, sandbox)?)
    };

    let mut last;
    let mut loop_first = true;
    let mut no_resolve_symlinks;
    while let Some(part) = parts.pop() {
        // 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 one of MISS_LAST or WANT_BASE flags are 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 || want_base);

        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.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,
            "oflags": format_oflags(open_flags),
            "rflags": options,
            "miss_mode": format!("{miss_mode:?}"),
            "want_base": want_base,
            "deny_dotdot": deny_dotdot,
            "restrict_symlinks": restrict_symlinks,
            "restrict_magiclinks": restrict_magiclinks);

        if deny_dotdot && part == PathComponent::PARENT_DIR {
            // 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 && !result.deref().descendant_of(cwd.as_bytes()) {
                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 =
                        filemap.get_mnt_id(&result, pid, options, file_type, sandbox)?;
                    if my_mnt_id != mnt_id {
                        return Err(Errno::EXDEV);
                    }
                }
            }
        } else {
            loop_first = false;
        }

        match part {
            PathComponent(Some(ref p)) => {
                let len = p.len()
                    .checked_add(1) // path-sep
                    .ok_or(Errno::ENAMETOOLONG)?;
                result.try_reserve(len).or(Err(Errno::ENOMEM))?;
                result.push(p.as_bytes());

                // Invalidate file type.
                file_type = None;
            }
            PathComponent::PARENT_DIR => {
                // Check for RESOLVE_IN_ROOT:
                //
                // If a prefix component of path equates to dirfd,
                // then an immediately following .. component likewise
                // equates to dirfd (just as /.. is traditionally
                // equivalent to /).
                if !(result.is_equal(b"/") || resolve_in_root && result.is_equal(cwd.as_bytes())) {
                    // SAFETY:
                    // 1. `result` is a normalized absolute path.
                    // 2. `result` does not have a trailing slash.
                    unsafe { result.pop_unchecked() };
                }

                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 ProcMagic::check_link(pid, result.deref(), restrict_magiclinks)? {
            Some(_) if !resolve_proc && (!last || !no_follow_last) => {
                // NO_SYMLINKS|NO_MAGICLINKS|BENEATH|IN_ROOT.
                return Err(options.magic_errno());
            }
            Some(
                magic @ (ProcMagic::Fd { .. }
                | ProcMagic::Cwd { .. }
                | ProcMagic::Root { .. }
                | ProcMagic::Exe { .. }),
            ) => {
                // Handle /proc/$pid/{fd/<n>,cwd,root,exe} indirection unless
                // this is the final component and NO_FOLLOW_LAST is set.
                let sym = magic.link_path()?;
                file_type = Some(FileType::MagicLnk(magic));

                let target = if let Some(entry) = filemap.get(&sym) {
                    // SAFETY: Magic link target member is always Some.
                    #[expect(clippy::disallowed_methods)]
                    Arc::clone(entry.target.as_ref().unwrap().as_ref().unwrap())
                } else {
                    let (mut entry, _) = FileMapEntry::from_magic_link(magic, !last, sandbox)?;

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

                    let entry_sym = FileMapEntry::new(
                        MaybeFd::RawFd(entry.fd.as_raw_fd()),
                        Some(FileType::MagicLnk(magic)),
                        entry.f_mode,
                        entry.mnt_id,
                        Some(Ok(Arc::clone(&target))),
                    );
                    filemap.try_insert(Arc::new(sym), entry_sym)?;

                    if target.is_absolute() {
                        // entry.target is intentionally None here.
                        filemap.try_insert(Arc::clone(&target), entry)?;
                    }

                    target
                };

                if last && !no_resolve_symlinks {
                    if target.is_relative() {
                        // 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());
                    } else {
                        // Magic link points to genuine path.
                        // Set the result to target, reset file type.
                        result.clear();
                        result.append_bytes(target.as_bytes());
                        file_type = None;
                    }

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

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

                Some(Ok(target))
            }
            Some(magic @ ProcMagic::Ns { .. }) => {
                // Keep magic type so CanonicalPath::new will
                // open via safe_open_msym.
                file_type = Some(FileType::MagicLnk(magic));
                Some(Err(Errno::EINVAL))
            }
            Some(magic @ (ProcMagic::Pid { .. } | ProcMagic::Tid { .. })) => {
                // ProcMagic::check_link does not check for these.
                unreachable!("BUG: ProcMagic::check_link returned invalid magic `{magic:?}'!");
            }
            None if result.is_proc_self(false) => {
                // Handle /proc/self indirection unless
                // this is the final component and NO_FOLLOW_LAST
                // is set. NO_MAGICLINKS allows /proc/self.
                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 magic symlink.
                    file_type = Some(FileType::MagicLnk(ProcMagic::Pid { pid }));
                }

                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. NO_MAGICLINKS allows /proc/thread-self.
                let tgid = proc_tgid(pid)?;
                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(tgid);
                    result.push(b"task");
                    result.push_pid(pid);
                } else if last {
                    // Set file type to magic symlink.
                    file_type = Some(FileType::MagicLnk(ProcMagic::Tid { tgid, pid }));
                }

                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;
        }

        let resolve_result = if let Some(result_magic) = result_magic {
            result_magic
        } else {
            filemap.readlink(&result, pid, options, file_type, sandbox)
        };

        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.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,
            "oflags": format_oflags(open_flags),
            "rflags": options,
            "miss_mode": format!("{miss_mode:?}"),
            "want_base": want_base,
            "deny_dotdot": deny_dotdot,
            "restrict_symlinks": restrict_symlinks,
            "restrict_magiclinks": restrict_magiclinks);

        match resolve_result {
            Ok(target) => {
                // Invalidate file type before the next round.
                file_type = None;

                if target.is_relative() {
                    // SAFETY:
                    // 1. `result` is a normalized absolute path.
                    // 2. `result` does not have a trailing slash.
                    unsafe { result.pop_unchecked() };
                } else if resolve_in_root {
                    // RESOLVE_IN_ROOT: Absolute symlinks are treated relative to dirfd.
                    // `result` is an absolute path so truncating to CWD length is ok.
                    result.truncate(cwd.len());
                } else {
                    // RootDir as part of resolving a symlink to an absolute path:
                    // `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 if !file_type.map(|t| t.is_magic_link()).unwrap_or(false) {
                    // Invalidate only non-magic types;
                    // keep MagicLnk so we open via magicsym.
                    file_type = None;
                }
            }
            Err(errno) => match miss_mode {
                MissingHandling::Existing => return Err(errno),
                _ 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.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,
        "oflags": format_oflags(open_flags),
        "rflags": options,
        "want_base": want_base,
        "miss_mode": format!("{miss_mode:?}"),
        "deny_dotdot": deny_dotdot,
        "restrict_symlinks": restrict_symlinks,
        "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 && !result.deref().descendant_of(cwd.as_bytes()) {
        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 {
        let dir_ok = match file_type {
            Some(FileType::Dir) => true,
            Some(FileType::MagicLnk(ProcMagic::Cwd { .. } | ProcMagic::Root { .. })) => true,
            Some(FileType::MagicLnk(ProcMagic::Pid { .. } | ProcMagic::Tid { .. })) => true,
            // Everything else (Exe/Fd/Ns/other magics) is not directory-typed.
            Some(FileType::MagicLnk(_)) => false,
            // Unknown type: defer to the open() with O_DIRECTORY to decide.
            None => true,
            _ => false,
        };

        if matches!(
            miss_mode,
            MissingHandling::Existing | MissingHandling::Normal
        ) && !dir_ok
        {
            return Err(Errno::ENOTDIR);
        }
        result.append_byte(b'/');
    }

    if let Some(mnt_id) = mnt_id {
        // Open last component.
        let my_mnt_id = match (
            filemap.get_mnt_id(&result, pid, options, file_type, sandbox),
            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;

    // SAFETY: Open a file descriptor to the canonical path, without
    // resolving symbolic links anymore. This brings safety against
    // TOCTTOU attacks.
    let flen = filemap.len();
    let path = CanonicalPath::new(result, file_type, options, filemap, restrict_mkbdev)?;

    crate::debug!("ctx": "resolve_path", "op": "resolve_done",
        "pid": pid.as_raw(),
        "path": &path,
        "root": &*cwd,
        "options": format!("{options:?}"),
        "open_files": flen,
        "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,
        "oflags": format_oflags(open_flags),
        "rflags": options,
        "miss_mode": format!("{miss_mode:?}"),
        "want_base": want_base,
        "deny_dotdot": deny_dotdot,
        "restrict_symlinks": restrict_symlinks,
        "restrict_magiclinks": restrict_magiclinks);

    Ok(path)
}

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

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

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

    // Directory depth enough to trigger capacity checks.
    const MAX_DEPTH: usize = PATH_MAX_COMP * 2;

    fn setup() -> bool {
        umask(Mode::from_bits_truncate(0o7077));

        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_path(AT_FDCWD, ".", OFlag::O_DIRECTORY, ResolveFlag::empty())?;

        // 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)?;

        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, 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()
            .disable_cleanup(true)
            .permissions(Permissions::from_mode(0o700))
            .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())
                    .map(|fd| fd.into_raw_fd())?;
            }

            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(unsafe { BorrowedFd::borrow_raw(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 mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

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

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

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

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b""),
            FsFlags::NO_FOLLOW_LAST,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");
    }

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

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        let root = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b"//"),
            FsFlags::empty(),
            Some(&sandbox),
        )
        .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 mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        let result_test = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b"/etc/passwd"),
            FsFlags::empty(),
            Some(&sandbox),
        )
        .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(),
                Some(&sandbox),
            )
            .unwrap()
            .abs;
            assert_eq!(result, result_test);
        }
    }

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

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        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(),
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        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 mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

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

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &test.deref(),
            FsFlags::empty(),
            Some(&sandbox),
        );
        //SAFETY: File existence check is handled by read_path*
        //assert!(matches!(result, Err(Errno::ENOTDIR)), "{result:?}");
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &test.deref(),
            FsFlags::MUST_PATH,
            Some(&sandbox),
        );
        //SAFETY: File existence check is handled by read_path*
        //assert!(matches!(result, Err(Errno::ENOTDIR)), "{result:?}");
        assert!(result.is_ok(), "{result:?}");

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

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &test.deref(),
            FsFlags::NO_FOLLOW_LAST,
            Some(&sandbox),
        );
        //SAFETY: File existence check is handled by read_path*
        //assert!(matches!(result, Err(Errno::ENOTDIR)), "{result:?}");
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &test.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Some(&sandbox),
        );
        //SAFETY: File existence check is handled by read_path*
        //assert!(matches!(result, Err(Errno::ENOTDIR)), "{result:?}");
        assert!(result.is_ok(), "{result:?}");

        //SAFETY: Missing is handled by read_path*.
        assert!(safe_canonicalize(
            Pid::this(),
            None,
            &test.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Some(&sandbox),
        )
        .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 mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

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

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

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &XPath::from_bytes(b"/zzz/.."),
            FsFlags::NO_FOLLOW_LAST,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        assert!(matches!(result, Err(Errno::ENOENT)), "{result:?}");
    }

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

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        // 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,
            Some(&sandbox),
        );
        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;
        }

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        // 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,
            Some(&sandbox),
        )
        .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() {
        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        // 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(), Some(&sandbox)).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(), Some(&sandbox)).unwrap();
        assert_eq!(path.abs, pexp, "{pexp} != {path:?}");
        eprintln!("ok 2 step 1");

        let path =
            safe_canonicalize(child, None, &parg, FsFlags::NO_FOLLOW_LAST, Some(&sandbox)).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 mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        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(),
                Some(&sandbox),
            )
        });

        let _ = remove_dir_all(&base);
    }

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

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        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,
                Some(&sandbox),
            )
        });

        let _ = remove_dir_all(&base);
    }

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

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        let tmp_dir = tempfile::Builder::new()
            .disable_cleanup(true)
            .permissions(Permissions::from_mode(0o700))
            .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,
            Some(&sandbox),
        );
        assert!(result.is_ok(), "{result:?}");

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

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

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

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link_a.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Some(&sandbox),
        );
        //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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &link_a.deref(),
            FsFlags::MISS_LAST,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

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

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

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        let tmp_dir = tempfile::Builder::new()
            .disable_cleanup(true)
            .permissions(Permissions::from_mode(0o700))
            .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,
            Some(&sandbox),
        );
        assert!(result.is_ok(), "{result:?}");

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

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

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

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &valid_link.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Some(&sandbox),
        );
        //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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        assert!(result.is_ok(), "{result:?}");
        // should be: assert_eq!(result, Err(Errno::EEXIST));
    }

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

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        let tmp_dir = tempfile::Builder::new()
            .disable_cleanup(true)
            .permissions(Permissions::from_mode(0o700))
            .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,
            Some(&sandbox),
        );
        assert!(result.is_ok(), "{result:?}");

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

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

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

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &symlink_path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Some(&sandbox),
        );
        //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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        //SAFETY: Missing is handled by read_path*.
        //assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");
        assert!(result.is_ok(), "{result:?}");

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

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

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        let tmp_dir = tempfile::Builder::new()
            .disable_cleanup(true)
            .permissions(Permissions::from_mode(0o700))
            .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,
            Some(&sandbox),
        );
        assert!(result.is_ok(), "{result:?}");
        eprintln!("ok 1");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &broken_link.deref(),
            FsFlags::empty(),
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        assert!(result.is_ok(), "{result:?}");
        eprintln!("ok 3");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &broken_link.deref(),
            FsFlags::MUST_PATH,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        //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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        assert!(result.is_ok(), "{result:?}");
        eprintln!("ok 7");

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

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

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        let tmp_dir = tempfile::Builder::new()
            .disable_cleanup(true)
            .permissions(Permissions::from_mode(0o700))
            .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,
            Some(&sandbox),
        );
        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(),
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        //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,
            Some(&sandbox),
        );
        //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 mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        let tmp_dir = tempfile::Builder::new()
            .disable_cleanup(true)
            .permissions(Permissions::from_mode(0o700))
            .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,
            Some(&sandbox),
        );
        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(),
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        //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,
            Some(&sandbox),
        );
        //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 mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        let tmp_dir = tempfile::Builder::new()
            .disable_cleanup(true)
            .permissions(Permissions::from_mode(0o700))
            .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,
            Some(&sandbox),
        );
        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(),
            Some(&sandbox),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Some(&sandbox),
        );
        //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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        //SAFETY: Missing is handled by read_path*.
        //assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");
        assert!(result.is_ok(), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::MISS_LAST,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

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

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

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        let tmp_dir = tempfile::Builder::new()
            .disable_cleanup(true)
            .permissions(Permissions::from_mode(0o700))
            .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,
            Some(&sandbox),
        );
        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(),
            Some(&sandbox),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

        let result = safe_canonicalize(
            Pid::this(),
            None,
            &path.deref(),
            FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            Some(&sandbox),
        );
        //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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        //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,
            Some(&sandbox),
        );
        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,
            Some(&sandbox),
        );
        assert!(matches!(result, Err(Errno::ELOOP)), "{result:?}");

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

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

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        let pid = Pid::this();
        let path = safe_canonicalize(
            pid,
            None,
            &XPath::from_bytes(b"/proc/self"),
            FsFlags::NO_FOLLOW_LAST,
            Some(&sandbox),
        )
        .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;
        }

        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

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

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

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

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

    #[test]
    fn test_canon_glob_pipe() {
        let mut sandbox = Sandbox::default();
        sandbox.config("allow/lpath+/***").unwrap();
        sandbox.flags.clear();

        // 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(), Some(&sandbox));
        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(), Some(&sandbox));
        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!(components.is_empty());
        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.len(), 1);
        assert_eq!(components[0], PathComponent::PARENT_DIR);
        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.len(), 2);
        assert_eq!(components[0], PathComponent::PARENT_DIR);
        assert_eq!(components[1], PathComponent::PARENT_DIR);
        assert!(has_trailing_slash);
    }

    #[test]
    fn test_path_components_parent_dir_with_normal_components() {
        // Path: "../foo/../bar" -> reversed: [bar, .., foo, ..]
        let path = XPath::from_bytes(b"../foo/../bar");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(components.len(), 4);
        assert_eq!(
            components[0],
            PathComponent(Some(Cow::Borrowed(XPath::from_bytes(b"bar"))))
        );
        assert_eq!(components[1], PathComponent::PARENT_DIR);
        assert_eq!(
            components[2],
            PathComponent(Some(Cow::Borrowed(XPath::from_bytes(b"foo"))))
        );
        assert_eq!(components[3], PathComponent::PARENT_DIR);
        assert!(!has_trailing_slash);
    }

    #[test]
    fn test_path_components_trailing_slash_with_parent_dir() {
        // Path: "../foo/.." -> reversed: [.., foo, ..]
        let path = XPath::from_bytes(b"../foo/..");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(components.len(), 3);
        assert_eq!(components[0], PathComponent::PARENT_DIR);
        assert_eq!(
            components[1],
            PathComponent(Some(Cow::Borrowed(XPath::from_bytes(b"foo"))))
        );
        assert_eq!(components[2], PathComponent::PARENT_DIR);
        assert!(has_trailing_slash);
    }

    #[test]
    fn test_path_components_leading_slashes_are_skipped() {
        // Path: "////..////bar" -> reversed: [bar, ..]
        let path = XPath::from_bytes(b"////..////bar");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(components.len(), 2);
        assert_eq!(
            components[0],
            PathComponent(Some(Cow::Borrowed(XPath::from_bytes(b"bar"))))
        );
        assert_eq!(components[1], PathComponent::PARENT_DIR);
        assert!(!has_trailing_slash);
    }

    #[test]
    fn test_path_components_path_with_mixed_components_and_trailing_slash() {
        // Path: "../foo/../bar/" -> reversed: [bar, .., foo, ..]
        let path = XPath::from_bytes(b"../foo/../bar/");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(components.len(), 4);
        assert_eq!(
            components[0],
            PathComponent(Some(Cow::Borrowed(XPath::from_bytes(b"bar"))))
        );
        assert_eq!(components[1], PathComponent::PARENT_DIR);
        assert_eq!(
            components[2],
            PathComponent(Some(Cow::Borrowed(XPath::from_bytes(b"foo"))))
        );
        assert_eq!(components[3], PathComponent::PARENT_DIR);
        assert!(has_trailing_slash);
    }

    #[test]
    fn test_path_components_complex_path_with_leading_parent_dir() {
        // Path: "../foo/bar/../../baz/.." -> forward: [.., foo, bar, .., .., baz, ..]
        // Reversed: [.., baz, .., .., bar, foo, ..]
        let path = XPath::from_bytes(b"../foo/bar/../../baz/..");
        let (components, has_trailing_slash) = path_components(&path).unwrap();
        assert_eq!(components.len(), 7);
        assert_eq!(components[0], PathComponent::PARENT_DIR);
        assert_eq!(
            components[1],
            PathComponent(Some(Cow::Borrowed(XPath::from_bytes(b"baz"))))
        );
        assert_eq!(components[2], PathComponent::PARENT_DIR);
        assert_eq!(components[3], PathComponent::PARENT_DIR);
        assert_eq!(
            components[4],
            PathComponent(Some(Cow::Borrowed(XPath::from_bytes(b"bar"))))
        );
        assert_eq!(
            components[5],
            PathComponent(Some(Cow::Borrowed(XPath::from_bytes(b"foo"))))
        );
        assert_eq!(components[6], PathComponent::PARENT_DIR);
        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.len(), 1);
        assert_eq!(components[0], PathComponent::PARENT_DIR);
        assert!(has_trailing_slash);
    }

    #[test]
    fn test_chdir_long() {
        // Create a deep directory structure.
        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();

        // 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.
        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();
            Some(getdir_long(cwd_fd, max))
        } else {
            None
        };

        // Restore current working directory.
        fchdir(fd).unwrap();

        // 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.
        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();
            Some(getdir_long(cwd_fd, max))
        } else {
            None
        };

        // Restore current working directory.
        fchdir(fd).unwrap();

        // 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:?}"
        );
    }

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

        // Create a deep directory structure to verify FileMap capacity check.
        let name = XPathBuf::from("a");
        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();

        // Construct the deep path string.
        for _ in 0..MAX_DEPTH {
            cwd.push(name.as_bytes());
        }

        let result = safe_canonicalize(Pid::this(), None, &cwd, FsFlags::empty(), None);

        // Restore current working directory.
        fchdir(fd).unwrap();

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

        // Now assert the expected error.
        match result {
            Err(Errno::ENAMETOOLONG) => {} // Success
            Err(errno) => panic!("Expected ENAMETOOLONG, got {errno}"),
            Ok(_) => panic!("Expected ENAMETOOLONG, but succeeded"),
        }
    }
}
