From 463986ed08311e13aa40adc9b7d57fcc7ee055db Mon Sep 17 00:00:00 2001 From: Rain Date: Thu, 19 Sep 2024 19:42:33 -0700 Subject: [PATCH] [cap-primitives] add support for illumos Get the cap-primitives library building and passing all tests on illumos. There were just a couple of minor tweaks required. I also ran into an issue where the minimum version of `ipnet` required was too old, so I took the liberty to bump it to 2.5.0 which has `IpNet::new`. The note in `dir_entry.rs` is copied over from Rust's std: https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_type --- cap-primitives/Cargo.toml | 4 ++-- cap-primitives/src/fs/dir_entry.rs | 6 ++++++ cap-primitives/src/rustix/fs/dir_entry_inner.rs | 13 +++++++++++-- cap-primitives/src/rustix/fs/dir_utils.rs | 2 ++ cap-primitives/src/rustix/fs/mod.rs | 10 +++++++--- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/cap-primitives/Cargo.toml b/cap-primitives/Cargo.toml index 070c17d5..bcb30b88 100644 --- a/cap-primitives/Cargo.toml +++ b/cap-primitives/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" [dependencies] ambient-authority = "0.0.2" arbitrary = { version = "1.0.0", optional = true, features = ["derive"] } -ipnet = "2.3.0" +ipnet = "2.5.0" maybe-owned = "0.3.4" fs-set-times = "0.20.0" io-extras = "0.18.0" @@ -25,7 +25,7 @@ io-lifetimes = { version = "2.0.0", default-features = false } cap-tempfile = { path = "../cap-tempfile" } [target.'cfg(not(windows))'.dependencies] -rustix = { version = "0.38.32", features = ["fs", "process", "procfs", "termios", "time"] } +rustix = { version = "0.38.38", features = ["fs", "process", "procfs", "termios", "time"] } [target.'cfg(windows)'.dependencies] winx = "0.36.0" diff --git a/cap-primitives/src/fs/dir_entry.rs b/cap-primitives/src/fs/dir_entry.rs index 51ee1f10..22dcae9b 100644 --- a/cap-primitives/src/fs/dir_entry.rs +++ b/cap-primitives/src/fs/dir_entry.rs @@ -82,6 +82,12 @@ impl DirEntry { /// Returns the file type for the file that this entry points at. /// /// This corresponds to [`std::fs::DirEntry::file_type`]. + /// + /// # Platform-specific behavior + /// + /// On Windows and most Unix platforms this function is free (no extra system calls needed), but + /// some Unix platforms may require the equivalent call to `metadata` to learn about the target + /// file type. #[inline] pub fn file_type(&self) -> io::Result { self.inner.file_type() diff --git a/cap-primitives/src/rustix/fs/dir_entry_inner.rs b/cap-primitives/src/rustix/fs/dir_entry_inner.rs index 35923880..5b82b624 100644 --- a/cap-primitives/src/rustix/fs/dir_entry_inner.rs +++ b/cap-primitives/src/rustix/fs/dir_entry_inner.rs @@ -1,6 +1,5 @@ use crate::fs::{ - FileType, FollowSymlinks, ImplFileTypeExt, Metadata, MetadataExt, OpenOptions, ReadDir, - ReadDirInner, + FileType, FollowSymlinks, Metadata, MetadataExt, OpenOptions, ReadDir, ReadDirInner, }; use rustix::fs::DirEntry; use std::ffi::{OsStr, OsString}; @@ -41,9 +40,12 @@ impl DirEntryInner { self.read_dir.remove_dir(self.file_name_bytes()) } + #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] #[inline] #[allow(clippy::unnecessary_wraps)] pub(crate) fn file_type(&self) -> io::Result { + use crate::fs::ImplFileTypeExt; + Ok(match self.rustix.file_type() { rustix::fs::FileType::Directory => FileType::dir(), rustix::fs::FileType::RegularFile => FileType::file(), @@ -58,6 +60,13 @@ impl DirEntryInner { }) } + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[inline] + pub(crate) fn file_type(&self) -> io::Result { + // These platforms don't have the file type on the dirent, so we must lstat the file. + self.metadata().map(|m| m.file_type()) + } + #[inline] pub(crate) fn file_name(&self) -> OsString { self.file_name_bytes().to_os_string() diff --git a/cap-primitives/src/rustix/fs/dir_utils.rs b/cap-primitives/src/rustix/fs/dir_utils.rs index f5db324b..5e29133a 100644 --- a/cap-primitives/src/rustix/fs/dir_utils.rs +++ b/cap-primitives/src/rustix/fs/dir_utils.rs @@ -143,6 +143,8 @@ pub(crate) const fn target_o_path() -> OFlags { target_os = "netbsd", target_os = "openbsd", target_os = "wasi", + target_os = "illumos", + target_os = "solaris", ))] { OFlags::empty() diff --git a/cap-primitives/src/rustix/fs/mod.rs b/cap-primitives/src/rustix/fs/mod.rs index 1dd74412..a872b0a7 100644 --- a/cap-primitives/src/rustix/fs/mod.rs +++ b/cap-primitives/src/rustix/fs/mod.rs @@ -142,10 +142,13 @@ fn tty_path() { #[cfg(unix)] use std::os::unix::fs::FileTypeExt; - // On FreeBSD, /dev/{tty,stdin,stdout,stderr} are aliases to different real - // devices. let paths: &[&str] = if cfg!(target_os = "freebsd") { + // On FreeBSD, /dev/{tty,stdin,stdout,stderr} are aliases to different + // real devices. &["/dev/ttyv0", "/dev/pts/0"] + } else if cfg!(target_os = "illumos") { + // On illumos, /dev/std{in,out,err} only exist if they're open. + &["/dev/tty", "/dev/pts/0"] } else { &["/dev/tty", "/dev/stdin", "/dev/stdout", "/dev/stderr"] }; @@ -162,7 +165,8 @@ fn tty_path() { .as_ref() .map(std::fs::canonicalize) .map(Result::unwrap), - Some(canonical) + Some(canonical), + "for path {path}, file_path matches canonicalized path" ); } }