Skip to content

Commit b3034ff

Browse files
wan9chicodex
andcommitted
refactor(fspy-shm): adopt fspy_nostd on Unix
Co-authored-by: GPT-5 Codex <codex@openai.com>
1 parent 367f651 commit b3034ff

8 files changed

Lines changed: 223 additions & 43 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/fspy_nostd/src/fs/linux.rs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,61 @@
11
use core::{mem::MaybeUninit, slice};
22

3-
use crate::{AsRawFd as _, BorrowedFd, CStr, Error, Fat, Result, Thin};
3+
use rustix::fd::FromRawFd as _;
4+
5+
use crate::{
6+
AsRawFd as _, BorrowedFd, CStr, Error, Fat, OwnedFd, Result, Thin,
7+
fs::{AtFlags, Mode, OFlags},
8+
};
49

510
// Linux UAPI `PATH_MAX`.
611
pub(super) const PATH_MAX: usize = 4096;
712

13+
fn syscall_fd(fd: BorrowedFd<'_>) -> Result<usize> {
14+
let fd = isize::try_from(fd.as_raw_fd()).map_err(|_| Error::OVERFLOW)?;
15+
Ok(fd.cast_unsigned())
16+
}
17+
18+
#[expect(clippy::needless_pass_by_value, reason = "CStr is a borrowed value type")]
19+
pub(super) fn openat<R>(
20+
dirfd: BorrowedFd<'_>,
21+
path: CStr<'_, R>,
22+
flags: OFlags,
23+
mode: Mode,
24+
) -> Result<OwnedFd> {
25+
// SAFETY: `dirfd` remains borrowed and `path` is NUL-terminated. The
26+
// kernel receives all four syscall arguments explicitly.
27+
let fd = unsafe {
28+
syscalls::syscall4(
29+
syscalls::Sysno::openat,
30+
syscall_fd(dirfd)?,
31+
path.as_ptr().addr(),
32+
usize::try_from(flags.bits()).map_err(|_| Error::INVAL)?,
33+
usize::try_from(mode.bits()).map_err(|_| Error::INVAL)?,
34+
)
35+
}
36+
.map_err(|errno| Error::from_raw_os_error(errno.into_raw()))?;
37+
let fd = i32::try_from(fd).map_err(|_| Error::OVERFLOW)?;
38+
39+
// SAFETY: a successful `openat` returns a new owned descriptor.
40+
Ok(unsafe { OwnedFd::from_raw_fd(fd) })
41+
}
42+
43+
#[expect(clippy::needless_pass_by_value, reason = "CStr is a borrowed value type")]
44+
pub(super) fn unlinkat<R>(dirfd: BorrowedFd<'_>, path: CStr<'_, R>, flags: AtFlags) -> Result<()> {
45+
// SAFETY: `dirfd` remains borrowed and `path` is NUL-terminated for the
46+
// syscall.
47+
unsafe {
48+
syscalls::syscall3(
49+
syscalls::Sysno::unlinkat,
50+
syscall_fd(dirfd)?,
51+
path.as_ptr().addr(),
52+
usize::try_from(flags.bits()).map_err(|_| Error::INVAL)?,
53+
)
54+
}
55+
.map_err(|errno| Error::from_raw_os_error(errno.into_raw()))?;
56+
Ok(())
57+
}
58+
859
/// Reads the target of `path` relative to `dirfd` into `buf`.
960
///
1061
/// The returned bytes borrow the initialized prefix of `buf`. As with the
@@ -27,7 +78,7 @@ pub fn readlinkat<'buf>(
2778
let initialized = unsafe {
2879
syscalls::syscall4(
2980
syscalls::Sysno::readlinkat,
30-
(dirfd.as_raw_fd() as isize).cast_unsigned(),
81+
syscall_fd(dirfd)?,
3182
path.as_ptr().addr(),
3283
buf.as_mut_ptr().addr(),
3384
buf.len(),

crates/fspy_nostd/src/fs/mac.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ use core::{mem::MaybeUninit, slice};
22

33
use rustix::{
44
fd::{AsFd as _, AsRawFd as _, FromRawFd as _, OwnedFd},
5-
fs::{Mode, OFlags},
5+
fs::{AtFlags, Mode, OFlags},
66
};
77

88
use crate::{BorrowedFd, CStr, CWD, Error, Fat, Result, Thin};
99

10-
pub(super) const PATH_MAX: usize = libc::PATH_MAX as usize;
10+
// Darwin UAPI `MAXPATHLEN`.
11+
pub(super) const PATH_MAX: usize = 1024;
12+
const _: () = assert!(libc::PATH_MAX == 1024);
1113

1214
#[expect(clippy::needless_pass_by_value, reason = "CStr is a borrowed value type")]
13-
fn openat<R>(
15+
pub(super) fn openat<R>(
1416
dirfd: BorrowedFd<'_>,
1517
path: CStr<'_, R>,
1618
flags: OFlags,
@@ -35,6 +37,21 @@ fn openat<R>(
3537
Ok(unsafe { OwnedFd::from_raw_fd(fd) })
3638
}
3739

40+
#[expect(clippy::needless_pass_by_value, reason = "CStr is a borrowed value type")]
41+
pub(super) fn unlinkat<R>(dirfd: BorrowedFd<'_>, path: CStr<'_, R>, flags: AtFlags) -> Result<()> {
42+
// SAFETY: `dirfd` remains borrowed and `path` is NUL-terminated for the
43+
// call.
44+
let result = unsafe {
45+
libc::unlinkat(dirfd.as_raw_fd(), path.as_ptr().cast(), flags.bits().cast_signed())
46+
};
47+
if result == -1 {
48+
// SAFETY: libSystem stored this call's error before returning -1.
49+
Err(Error::from_raw_os_error(unsafe { *libc::__error() }))
50+
} else {
51+
Ok(())
52+
}
53+
}
54+
3855
/// Gets the path associated with `fd`.
3956
///
4057
/// `F_GETPATH` writes a NUL-terminated path into its `MAXPATHLEN` buffer but

crates/fspy_nostd/src/fs/mod.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
33
use core::mem::MaybeUninit;
44

5-
use crate::{CStr, Fat, Result};
5+
pub use rustix::fs::{AtFlags, Mode, OFlags, fstat, ftruncate};
6+
7+
use crate::{BorrowedFd, CStr, Fat, OwnedFd, Result};
68

79
#[cfg(target_os = "linux")]
810
mod linux;
@@ -21,6 +23,29 @@ pub use mac::fcntl_getpath;
2123
/// The platform's maximum pathname size, including the terminating NUL.
2224
pub const PATH_MAX: usize = imp::PATH_MAX;
2325

26+
/// Opens `path` relative to `dirfd` and returns its owned descriptor.
27+
///
28+
/// # Errors
29+
///
30+
/// Returns the error reported by `openat`.
31+
pub fn openat<R>(
32+
dirfd: BorrowedFd<'_>,
33+
path: CStr<'_, R>,
34+
flags: OFlags,
35+
mode: Mode,
36+
) -> Result<OwnedFd> {
37+
imp::openat(dirfd, path, flags, mode)
38+
}
39+
40+
/// Removes `path` relative to `dirfd`.
41+
///
42+
/// # Errors
43+
///
44+
/// Returns the error reported by `unlinkat`.
45+
pub fn unlinkat<R>(dirfd: BorrowedFd<'_>, path: CStr<'_, R>, flags: AtFlags) -> Result<()> {
46+
imp::unlinkat(dirfd, path, flags)
47+
}
48+
2449
/// Writes the absolute pathname of the current working directory into `buf`.
2550
///
2651
/// The returned C string borrows `buf`, starts at the same address as `buf`,

crates/fspy_nostd/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ macro_rules! wide_cstr {
6565

6666
#[cfg(unix)]
6767
pub use rustix::{
68-
fd::{AsRawFd, BorrowedFd},
68+
fd::{AsRawFd, BorrowedFd, OwnedFd},
6969
fs::CWD,
7070
io::Errno as Error,
7171
};

crates/fspy_nostd/src/mm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
//! pre-libc startup) and the crate-level backend check, which guarantees
99
//! they cannot silently turn into libc calls on Linux.
1010
11-
pub use rustix::mm::{MapFlags, MprotectFlags, ProtFlags, mmap_anonymous, mprotect, munmap};
11+
pub use rustix::mm::{MapFlags, MprotectFlags, ProtFlags, mmap, mmap_anonymous, mprotect, munmap};

crates/fspy_shm/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@ publish = false
88
rust-version.workspace = true
99

1010
[dependencies]
11-
memmap2 = { workspace = true }
1211
uuid = { workspace = true, features = ["v4"] }
1312

13+
[target.'cfg(unix)'.dependencies]
14+
fspy_nostd = { workspace = true }
15+
16+
[target.'cfg(windows)'.dependencies]
17+
memmap2 = { workspace = true }
18+
1419
[target.'cfg(target_os = "windows")'.dependencies]
1520
windows-sys = { workspace = true, features = [
1621
"Win32_Foundation",

0 commit comments

Comments
 (0)