From 50e9d982601b1f4e1d574c10a8f6c5f502e53f62 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 1 Jan 2026 02:36:25 +0100 Subject: [PATCH] Make vfs::tree::Kind pointer-sized By using impossible pointer values of AStr as the representation of the 'Regular' and 'Directory' kinds. --- crates/vfs/src/tree/builder.rs | 16 ++-- crates/vfs/src/tree/kind.rs | 135 +++++++++++++++++++++++++++++++++ crates/vfs/src/tree/mod.rs | 21 +---- moss/src/client/mod.rs | 6 +- 4 files changed, 148 insertions(+), 30 deletions(-) create mode 100644 crates/vfs/src/tree/kind.rs diff --git a/crates/vfs/src/tree/builder.rs b/crates/vfs/src/tree/builder.rs index adc58543e..b28f768cc 100644 --- a/crates/vfs/src/tree/builder.rs +++ b/crates/vfs/src/tree/builder.rs @@ -8,7 +8,7 @@ use std::collections::BTreeMap; use astr::{AStr, CowAStr}; use crate::path; -use crate::tree::{Kind, Tree}; +use crate::tree::Tree; use super::{BlitFile, Error, File}; @@ -94,7 +94,7 @@ impl TreeBuilder { // Resolve symlinks-to-dirs for link in self.explicit.iter() { - if let Kind::Symlink(target) = &link.kind { + if let Some(target) = link.kind.as_symlink() { // Resolve the link. let target = if target.starts_with('/') { CowAStr::Borrowed(target) @@ -156,7 +156,7 @@ mod tests { fn from(value: AStr) -> Self { Self { path: value, - kind: Kind::Directory, + kind: Kind::DIRECTORY, id: "Virtual".into(), } } @@ -191,27 +191,27 @@ mod tests { let paths = vec![ CustomFile { path: "/usr/bin/nano".into(), - kind: Kind::Regular, + kind: Kind::REGULAR, id: "nano".into(), }, CustomFile { path: "/usr/bin/rnano".into(), - kind: Kind::Symlink("nano".into()), + kind: Kind::symlink("nano".into()), id: "nano".into(), }, CustomFile { path: "/usr/share/nano".into(), - kind: Kind::Directory, + kind: Kind::DIRECTORY, id: "nano".into(), }, CustomFile { path: "/var/run/lock".into(), - kind: Kind::Symlink("/run/lock".into()), + kind: Kind::symlink("/run/lock".into()), id: "baselayout".into(), }, CustomFile { path: "/var/run/lock/subsys/1".into(), - kind: Kind::Regular, + kind: Kind::REGULAR, id: "baselayout".into(), }, ]; diff --git a/crates/vfs/src/tree/kind.rs b/crates/vfs/src/tree/kind.rs new file mode 100644 index 000000000..5b01ea8e6 --- /dev/null +++ b/crates/vfs/src/tree/kind.rs @@ -0,0 +1,135 @@ +use std::mem::ManuallyDrop; + +use astr::AStr; + +const _: () = { + // AStr must contain as its first field a pointer to an Arc allocation + // (one with alignment 4 or larger) for the REGULAR and DIRECTORY values + // to definitely not overlap with any valid AStr value. + // + // Since we can't really assert on this, assert that it's pointer-sized + // for now. + assert!(size_of::() == size_of::>()); +}; + +pub union Kind { + addr_or_tag: usize, + symlink_target: ManuallyDrop, +} + +impl Kind { + /// Regular path + pub const REGULAR: Self = Self { addr_or_tag: 0x1 }; + /// Directory (parenting node) + pub const DIRECTORY: Self = Self { addr_or_tag: 0x2 }; + + pub fn symlink(target: AStr) -> Self { + Self { + symlink_target: ManuallyDrop::new(target), + } + } + + fn addr_or_tag(&self) -> usize { + // Safety: We asserted that the two fields in the union are of the same + // size at the start of the file. We know AStr is a pointer, so there's + // no padding bytes involved. Reading either usize or a pointer as a + // usize is always valid. + unsafe { self.addr_or_tag } + } + + pub fn is_regular(&self) -> bool { + self.addr_or_tag() == 0x1 + } + + pub fn is_directory(&self) -> bool { + self.addr_or_tag() == 0x2 + } + + pub fn is_symlink(&self) -> bool { + self.addr_or_tag() >= 0x8 + } + + pub fn as_symlink(&self) -> Option<&AStr> { + self.is_symlink().then(|| unsafe { &*self.symlink_target }) + } +} + +impl Clone for Kind { + fn clone(&self) -> Self { + if let Some(target) = self.as_symlink() { + let symlink_target = ManuallyDrop::new(AStr::clone(target)); + Self { symlink_target } + } else { + let addr_or_tag = self.addr_or_tag(); + Self { addr_or_tag } + } + } +} + +impl Default for Kind { + fn default() -> Self { + Self::DIRECTORY + } +} + +impl Drop for Kind { + fn drop(&mut self) { + if self.is_symlink() { + unsafe { + ManuallyDrop::drop(&mut self.symlink_target); + } + } + } +} + +mod debug_impl { + use std::fmt; + + #[derive(Debug)] + #[allow(dead_code)] + enum Kind<'a> { + Regular, + Directory, + Symlink(&'a str), + } + + impl super::Kind { + fn to_enum(&self) -> Kind<'_> { + if self.is_regular() { + Kind::Regular + } else if let Some(target) = self.as_symlink() { + Kind::Symlink(target) + } else { + Kind::Directory + } + } + } + + impl fmt::Debug for super::Kind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.to_enum().fmt(f) + } + } +} + +// Run through miri to validate unsafe code. +#[cfg(test)] +mod tests { + use crate::tree::Kind; + + #[test] + fn clone_drop_symlink() { + let kind = Kind::symlink("/test/thing".into()); + let kind2 = kind.clone(); + drop(kind); + drop(kind2); + } + + #[test] + fn clone_drop_regular() { + let kind = Kind::REGULAR; + let kind2 = kind.clone(); + drop(kind); + drop(kind2); + } +} diff --git a/crates/vfs/src/tree/mod.rs b/crates/vfs/src/tree/mod.rs index 409f7568b..854d4aa7b 100644 --- a/crates/vfs/src/tree/mod.rs +++ b/crates/vfs/src/tree/mod.rs @@ -15,26 +15,9 @@ use snafu::Snafu; use crate::path::{self, VfsPath}; pub mod builder; +mod kind; -#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum Kind { - // Regular path - Regular, - - // Directory (parenting node) - #[default] - Directory, - - // Symlink to somewhere else. - Symlink(AStr), -} - -impl Kind { - #[must_use] - pub fn is_directory(&self) -> bool { - matches!(self, Self::Directory) - } -} +pub use self::kind::Kind; /// Simple generic interface for blittable files while retaining details. /// diff --git a/moss/src/client/mod.rs b/moss/src/client/mod.rs index dae0c49ea..87d558a39 100644 --- a/moss/src/client/mod.rs +++ b/moss/src/client/mod.rs @@ -1133,9 +1133,9 @@ impl BlitFile for PendingFile { /// Match internal kind to minimalist vfs kind fn kind(&self) -> vfs::tree::Kind { match &self.layout.entry { - layout::Entry::Symlink(source, _) => vfs::tree::Kind::Symlink(source.clone()), - layout::Entry::Directory(_) => vfs::tree::Kind::Directory, - _ => vfs::tree::Kind::Regular, + layout::Entry::Symlink(source, _) => vfs::tree::Kind::symlink(source.clone()), + layout::Entry::Directory(_) => vfs::tree::Kind::DIRECTORY, + _ => vfs::tree::Kind::REGULAR, } }