Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 56 additions & 7 deletions crates/fspy_nostd/src/fs/linux.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,59 @@
use core::{mem::MaybeUninit, slice};

use crate::{AsRawFd as _, BorrowedFd, CStr, Error, Fat, Result, Thin};
use rustix::fd::FromRawFd as _;

use crate::{
AsRawFd as _, BorrowedFd, CStr, Error, Fat, OwnedFd, Result, Thin,
fs::{AtFlags, Mode, OFlags},
};

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

#[expect(clippy::needless_pass_by_value, reason = "CStr is a borrowed value type")]
pub(super) fn openat<R>(
dirfd: BorrowedFd<'_>,
path: CStr<'_, R>,
flags: OFlags,
mode: Mode,
) -> Result<OwnedFd> {
// SAFETY: `dirfd` remains borrowed and `path` is NUL-terminated. The
// kernel receives all four syscall arguments explicitly.
let fd = unsafe {
syscalls::syscall!(
syscalls::Sysno::openat,
dirfd.as_raw_fd(),
path.as_ptr(),
flags.bits(),
mode.bits()
)
}
.map_err(|errno| Error::from_raw_os_error(errno.into_raw()))?;

// This should not fail with a well-behaved kernel: `openat` returns a
// nonnegative `c_int` file descriptor.
let fd = i32::try_from(fd).map_err(|_| Error::OVERFLOW)?;

// SAFETY: a successful `openat` returns a new owned descriptor.
Ok(unsafe { OwnedFd::from_raw_fd(fd) })
}

#[expect(clippy::needless_pass_by_value, reason = "CStr is a borrowed value type")]
pub(super) fn unlinkat<R>(dirfd: BorrowedFd<'_>, path: CStr<'_, R>, flags: AtFlags) -> Result<()> {
// SAFETY: `dirfd` remains borrowed and `path` is NUL-terminated for the
// syscall.
unsafe {
syscalls::syscall!(
syscalls::Sysno::unlinkat,
dirfd.as_raw_fd(),
path.as_ptr(),
flags.bits()
)
}
.map_err(|errno| Error::from_raw_os_error(errno.into_raw()))?;
Ok(())
}

/// Reads the target of `path` relative to `dirfd` into `buf`.
///
/// The returned bytes borrow the initialized prefix of `buf`. As with the
Expand All @@ -25,12 +74,12 @@ pub fn readlinkat<'buf>(
// is writable for `buf.len()` bytes. `readlinkat` returns the initialized
// byte count.
let initialized = unsafe {
syscalls::syscall4(
syscalls::syscall!(
syscalls::Sysno::readlinkat,
(dirfd.as_raw_fd() as isize).cast_unsigned(),
path.as_ptr().addr(),
buf.as_mut_ptr().addr(),
buf.len(),
dirfd.as_raw_fd(),
path.as_ptr(),
buf.as_mut_ptr(),
buf.len()
)
}
.map_err(|errno| Error::from_raw_os_error(errno.into_raw()))?;
Expand All @@ -46,7 +95,7 @@ pub(super) fn getcwd(buf: &mut [MaybeUninit<u8>]) -> Result<CStr<'_, Fat>> {
// writes no more than that and returns the initialized length including
// its terminating NUL.
let initialized =
unsafe { syscalls::syscall2(syscalls::Sysno::getcwd, buf.as_mut_ptr().addr(), buf.len()) }
unsafe { syscalls::syscall!(syscalls::Sysno::getcwd, buf.as_mut_ptr(), buf.len()) }
.map_err(|errno| Error::from_raw_os_error(errno.into_raw()))?;

// SAFETY: the syscall initialized this prefix through its terminating NUL.
Expand Down
23 changes: 20 additions & 3 deletions crates/fspy_nostd/src/fs/mac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ use core::{mem::MaybeUninit, slice};

use rustix::{
fd::{AsFd as _, AsRawFd as _, FromRawFd as _, OwnedFd},
fs::{Mode, OFlags},
fs::{AtFlags, Mode, OFlags},
};

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

pub(super) const PATH_MAX: usize = libc::PATH_MAX as usize;
// Darwin UAPI `MAXPATHLEN`.
pub(super) const PATH_MAX: usize = 1024;
const _: () = assert!(libc::PATH_MAX == 1024);

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

#[expect(clippy::needless_pass_by_value, reason = "CStr is a borrowed value type")]
pub(super) fn unlinkat<R>(dirfd: BorrowedFd<'_>, path: CStr<'_, R>, flags: AtFlags) -> Result<()> {
// SAFETY: `dirfd` remains borrowed and `path` is NUL-terminated for the
// call.
let result = unsafe {
libc::unlinkat(dirfd.as_raw_fd(), path.as_ptr().cast(), flags.bits().cast_signed())
};
if result == -1 {
// SAFETY: libSystem stored this call's error before returning -1.
Err(Error::from_raw_os_error(unsafe { *libc::__error() }))
} else {
Ok(())
}
}

/// Gets the path associated with `fd`.
///
/// `F_GETPATH` writes a NUL-terminated path into its `MAXPATHLEN` buffer but
Expand Down
27 changes: 26 additions & 1 deletion crates/fspy_nostd/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

use core::mem::MaybeUninit;

use crate::{CStr, Fat, Result};
pub use rustix::fs::{AtFlags, Mode, OFlags, fstat, ftruncate};

use crate::{BorrowedFd, CStr, Fat, OwnedFd, Result};

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

/// Opens `path` relative to `dirfd` and returns its owned descriptor.
///
/// # Errors
///
/// Returns the error reported by `openat`.
pub fn openat<R>(
dirfd: BorrowedFd<'_>,
path: CStr<'_, R>,
flags: OFlags,
mode: Mode,
) -> Result<OwnedFd> {
imp::openat(dirfd, path, flags, mode)
}

/// Removes `path` relative to `dirfd`.
///
/// # Errors
///
/// Returns the error reported by `unlinkat`.
pub fn unlinkat<R>(dirfd: BorrowedFd<'_>, path: CStr<'_, R>, flags: AtFlags) -> Result<()> {
imp::unlinkat(dirfd, path, flags)
}

/// Writes the absolute pathname of the current working directory into `buf`.
///
/// The returned C string borrows `buf`, starts at the same address as `buf`,
Expand Down
2 changes: 1 addition & 1 deletion crates/fspy_nostd/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ macro_rules! wide_cstr {

#[cfg(unix)]
pub use rustix::{
fd::{AsRawFd, BorrowedFd},
fd::{AsRawFd, BorrowedFd, OwnedFd},
fs::CWD,
io::Errno as Error,
};
Expand Down
2 changes: 1 addition & 1 deletion crates/fspy_nostd/src/mm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
//! pre-libc startup) and the crate-level backend check, which guarantees
//! they cannot silently turn into libc calls on Linux.

pub use rustix::mm::{MapFlags, MprotectFlags, ProtFlags, mmap_anonymous, mprotect, munmap};
pub use rustix::mm::{MapFlags, MprotectFlags, ProtFlags, mmap, mmap_anonymous, mprotect, munmap};
7 changes: 6 additions & 1 deletion crates/fspy_shm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ publish = false
rust-version.workspace = true

[dependencies]
memmap2 = { workspace = true }
uuid = { workspace = true, features = ["v4"] }

[target.'cfg(unix)'.dependencies]
fspy_nostd = { workspace = true }

[target.'cfg(windows)'.dependencies]
memmap2 = { workspace = true }

[target.'cfg(target_os = "windows")'.dependencies]
windows-sys = { workspace = true, features = [
"Win32_Foundation",
Expand Down
Loading
Loading