Skip to content
Open
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
45 changes: 45 additions & 0 deletions src/process/chdir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,48 @@ fn _getcwd(mut buffer: Vec<u8>) -> io::Result<CString> {
}
}
}

/// Whether `getcwd_raw` uses the existing allocation-free Linux-raw syscall.
///
/// This is build availability only, not a cwd, resource, or authority witness.
#[cfg(all(feature = "alloc", feature = "fs"))]
pub const GETCWD_RAW_SUPPORTED: bool = cfg!(linux_raw);

/// Read the current directory into caller-provided storage without allocating.
///
/// On Linux-raw, returns the sealed buffer output for bytes including the NUL.
/// Initialized byte slices return their initialized byte count.
/// Empty or insufficient storage is an error. This never grows the buffer or
/// falls back through libc or procfs. Other backends return `Errno::NOSYS`.
#[cfg(all(feature = "alloc", feature = "fs"))]
#[allow(unsafe_code)]
#[inline]
pub fn getcwd_raw<Buf: crate::buffer::Buffer<u8>>(buf: Buf) -> io::Result<Buf::Output> {
#[cfg(linux_raw)]
{
let mut buf = buf;
let (ptr, capacity) = buf.parts_mut();
if capacity == 0 {
return Err(io::Errno::RANGE);
}
// SAFETY: the sealed Buffer implementation supplies a valid uniquely
// borrowed byte region for capacity bytes. MaybeUninit<u8> has the same
// layout/alignment as u8; this borrow neither reads nor owns its bytes.
let uninit = unsafe {
core::slice::from_raw_parts_mut(ptr.cast::<core::mem::MaybeUninit<u8>>(), capacity)
};
let initialized = backend::process::syscalls::getcwd(uninit)?;
if initialized == 0 || initialized > capacity {
return Err(io::Errno::IO);
}
// SAFETY: successful Linux getcwd initialized exactly this bounded
// prefix, including NUL. The syscall borrow ended before this sealed
// Buffer operation publishes its initialized prefix; no growth occurs.
unsafe { Ok(buf.assume_init(initialized)) }
}
#[cfg(not(linux_raw))]
{
let _ = buf;
Err(io::Errno::NOSYS)
}
}
20 changes: 20 additions & 0 deletions tests/process/working_directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,23 @@ fn test_changing_working_directory() {
"The cwd wasn't changed back to the its original position"
);
}

#[test]
fn test_getcwd_raw() {
let mut buf = [0u8; 4096];
if rustix::process::GETCWD_RAW_SUPPORTED {
let len = rustix::process::getcwd_raw(&mut buf[..]).expect("getcwd_raw should succeed");
let expected = rustix::process::getcwd(Vec::new()).expect("getcwd should succeed");
assert_eq!(&buf[..len], expected.to_bytes_with_nul());
let mut short = [0u8; 1];
assert_eq!(
rustix::process::getcwd_raw(&mut short[..]),
Err(rustix::io::Errno::RANGE)
);
} else {
assert_eq!(
rustix::process::getcwd_raw(&mut buf[..]),
Err(rustix::io::Errno::NOSYS)
);
}
}
Loading