From 2442430d17d0936580df8818ce9e9c554f7dcc69 Mon Sep 17 00:00:00 2001 From: wan9chi Date: Tue, 11 Aug 2026 11:18:34 +0800 Subject: [PATCH] refactor(fspy-shm): stat backing files through sigsafe Co-authored-by: GPT-5 Codex --- crates/fspy_shm/src/unix.rs | 31 ++++++++++++++++++------------- crates/sigsafe/src/fs/mod.rs | 2 +- crates/sigsafe/src/lib.rs | 2 +- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/crates/fspy_shm/src/unix.rs b/crates/fspy_shm/src/unix.rs index 8b9829b2..166c3074 100644 --- a/crates/fspy_shm/src/unix.rs +++ b/crates/fspy_shm/src/unix.rs @@ -4,7 +4,7 @@ use std::{ ffi::OsStr, fs::{self, File, OpenOptions}, io, - os::unix::{ffi::OsStrExt as _, fs::OpenOptionsExt as _, io::FromRawFd as _}, + os::unix::{ffi::OsStrExt as _, fs::OpenOptionsExt as _, io::IntoRawFd as _}, path::PathBuf, }; @@ -24,7 +24,7 @@ pub struct ShmKeeper { /// [`map`](Self::map) can be called more than once; every call returns another /// view of the same bytes. Drop the handle once the mappings exist. pub struct ShmHandle { - file: File, + file: sigsafe::OwnedFd, size: usize, } @@ -71,6 +71,7 @@ pub fn create(path: &OsStr, size: usize) -> io::Result<(ShmKeeper, ShmHandle)> { // Every byte reads as zero because the file is all holes. file.set_len(size_u64)?; + let file = into_sigsafe_fd(file); Ok((keeper, ShmHandle { file, size })) } @@ -86,15 +87,15 @@ pub fn open(path: &OsStr) -> io::Result { // If another process shrinks the file before `map`, mapping fails. If it // resizes afterwards, nothing here touches the mapped pages. A concurrent // resize cannot make a mapping access invalid memory. - let size = usize::try_from(file.metadata()?.len()) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid shared-memory size"))?; + let size = usize::try_from(sigsafe::fs::fstat(&file).map_err(errno_to_io)?.st_size) + .map_err(|_| io::ErrorKind::InvalidData)?; if size == 0 { - return Err(io::Error::new(io::ErrorKind::InvalidData, "shared-memory size is zero")); + return Err(io::ErrorKind::InvalidData.into()); } Ok(ShmHandle { file, size }) } -fn open_file(path: &OsStr) -> io::Result { +fn open_file(path: &OsStr) -> io::Result { let path_bytes = path.as_bytes(); let len_with_nul = path_bytes.len().checked_add(1).ok_or(io::ErrorKind::InvalidInput)?; let mut path_buf = [0_u8; sigsafe::fs::PATH_MAX]; @@ -103,23 +104,26 @@ fn open_file(path: &OsStr) -> io::Result { .ok_or_else(|| io::Error::from_raw_os_error(sigsafe::Errno::NAMETOOLONG.raw_os_error()))?; path[..path_bytes.len()].copy_from_slice(path_bytes); let path = sigsafe::CStr::from_bytes_with_nul(path).map_err(|_| io::ErrorKind::InvalidInput)?; - let fd = sigsafe::fs::openat( + sigsafe::fs::openat( sigsafe::CWD, path, sigsafe::fs::OFlags::RDWR | sigsafe::fs::OFlags::CLOEXEC, sigsafe::fs::Mode::empty(), ) - .map_err(errno_to_io)?; - let fd = sigsafe::IntoRawFd::into_raw_fd(fd); - // SAFETY: ownership of the descriptor returned by `openat` transfers to - // this `File` without closing or duplicating it. - Ok(unsafe { File::from_raw_fd(fd) }) + .map_err(errno_to_io) } fn errno_to_io(errno: sigsafe::Errno) -> io::Error { io::Error::from_raw_os_error(errno.raw_os_error()) } +fn into_sigsafe_fd(file: File) -> sigsafe::OwnedFd { + let fd = file.into_raw_fd(); + // SAFETY: ownership of `file`'s descriptor transfers without closing or + // duplicating it. + unsafe { sigsafe::FromRawFd::from_raw_fd(fd) } +} + impl Drop for ShmKeeper { fn drop(&mut self) { let _ = fs::remove_file(&self.path); @@ -133,7 +137,8 @@ impl ShmHandle { /// /// Returns an error if the mapping cannot be established. pub fn map(&self) -> io::Result { - Ok(Mapping { raw: MmapOptions::new().len(self.size).map_raw(&self.file)? }) + let file = sigsafe::AsRawFd::as_raw_fd(&self.file); + Ok(Mapping { raw: MmapOptions::new().len(self.size).map_raw(file)? }) } } diff --git a/crates/sigsafe/src/fs/mod.rs b/crates/sigsafe/src/fs/mod.rs index 3ab71432..9d46bad8 100644 --- a/crates/sigsafe/src/fs/mod.rs +++ b/crates/sigsafe/src/fs/mod.rs @@ -2,7 +2,7 @@ use core::mem::MaybeUninit; -pub use rustix::fs::{Mode, OFlags}; +pub use rustix::fs::{Mode, OFlags, Stat, fstat}; use crate::{BorrowedFd, CStr, Fat, OwnedFd, Result}; diff --git a/crates/sigsafe/src/lib.rs b/crates/sigsafe/src/lib.rs index 5be7bc45..71c4ad57 100644 --- a/crates/sigsafe/src/lib.rs +++ b/crates/sigsafe/src/lib.rs @@ -23,7 +23,7 @@ pub mod param; pub use c_str::{Bytes, CStr, Fat, Thin}; pub use rustix::{ - fd::{AsRawFd, BorrowedFd, IntoRawFd, OwnedFd}, + fd::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd}, fs::CWD, io::{Errno, Errno as Error, Result}, };