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
8 changes: 4 additions & 4 deletions src/ffi/z_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ impl ZString {
}

fn _new(bytes: Vec<u8>) -> Result<ZString, NulError> {
match memchr(0, &bytes) {
match memchr(b'\0', &bytes) {
Some(i) => Err(NulError(i, bytes)),
None => Ok(unsafe { ZString::from_vec_unchecked(bytes) }),
}
Expand Down Expand Up @@ -462,7 +462,7 @@ impl ZString {
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> ZString {
v.reserve_exact(1);
v.push(0);
v.push(b'\0');
ZString {
inner: v.into_boxed_slice(),
}
Expand Down Expand Up @@ -834,7 +834,7 @@ impl ZString {
stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")
)]
pub fn from_vec_with_nul(v: Vec<u8>) -> Result<Self, FromVecWithNulError> {
let nul_pos = memchr(0, &v);
let nul_pos = memchr(b'\0', &v);
match nul_pos {
Some(nul_pos) if nul_pos + 1 == v.len() => {
// SAFETY: We know there is only one nul byte, at the end
Expand Down Expand Up @@ -1354,7 +1354,7 @@ impl ZStr {
/// ```
#[cfg_attr(staged_api, stable(feature = "cstr_from_bytes", since = "1.10.0"))]
pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&ZStr, FromBytesWithNulError> {
let nul_pos = memchr(0, bytes);
let nul_pos = memchr(b'\0', bytes);
if let Some(nul_pos) = nul_pos {
if nul_pos + 1 != bytes.len() {
return Err(FromBytesWithNulError::interior_nul(nul_pos));
Expand Down
7 changes: 5 additions & 2 deletions src/fs/at.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::fs::CloneFlags;
#[cfg(any(linux_raw, all(libc, any(target_os = "android", target_os = "linux"))))]
use crate::fs::RenameFlags;
use crate::io::{self, OwnedFd};
use crate::path::SMALL_PATH_BUFFER_SIZE;
#[cfg(not(target_os = "wasi"))]
use crate::process::{Gid, Uid};
use crate::{imp, path};
Expand Down Expand Up @@ -71,7 +72,8 @@ fn _readlinkat(dirfd: BorrowedFd<'_>, path: &ZStr, mut buffer: Vec<u8>) -> io::R
// This code would benefit from having a better way to read into
// uninitialized memory, but that requires `unsafe`.
buffer.clear();
buffer.resize(256, 0_u8);
buffer.reserve(SMALL_PATH_BUFFER_SIZE);
buffer.resize(buffer.capacity(), 0_u8);

loop {
let nread = imp::syscalls::readlinkat(dirfd, path, &mut buffer)?;
Expand All @@ -82,7 +84,8 @@ fn _readlinkat(dirfd: BorrowedFd<'_>, path: &ZStr, mut buffer: Vec<u8>) -> io::R
buffer.resize(nread, 0_u8);
return Ok(ZString::new(buffer).unwrap());
}
buffer.resize(buffer.len() * 2, 0_u8);
buffer.reserve(1); // use `Vec` reallocation strategy to grow capacity exponentially
buffer.resize(buffer.capacity(), 0_u8);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/imp/linux_raw/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,7 @@ pub(crate) fn ttyname(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> {
if r == buf.len() {
return Err(io::Error::RANGE);
}
buf[r] = 0;
buf[r] = b'\0';

// Check that the path we read refers to the same file as `fd`.
let path = ZStr::from_bytes_with_nul(&buf[..=r]).unwrap();
Expand Down
14 changes: 10 additions & 4 deletions src/io/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ use imp::fd::AsFd;
all(linux_raw, feature = "procfs"),
all(libc, not(any(target_os = "fuchsia", target_os = "wasi")))
))]
use {crate::ffi::ZString, alloc::vec::Vec, imp::fd::BorrowedFd};
use {
crate::ffi::ZString, crate::path::SMALL_PATH_BUFFER_SIZE, alloc::vec::Vec, imp::fd::BorrowedFd,
};

/// `isatty(fd)`—Tests whether a file descriptor refers to a terminal.
///
Expand Down Expand Up @@ -57,13 +59,17 @@ fn _ttyname(dirfd: BorrowedFd<'_>, mut buffer: Vec<u8>) -> io::Result<ZString> {
// This code would benefit from having a better way to read into
// uninitialized memory, but that requires `unsafe`.
buffer.clear();
buffer.resize(256, 0_u8);
buffer.reserve(SMALL_PATH_BUFFER_SIZE);
buffer.resize(buffer.capacity(), 0_u8);

loop {
match imp::syscalls::ttyname(dirfd, &mut buffer) {
Err(imp::io::Error::RANGE) => buffer.resize(buffer.len() * 2, 0_u8),
Err(imp::io::Error::RANGE) => {
buffer.reserve(1); // use `Vec` reallocation strategy to grow capacity exponentially
buffer.resize(buffer.capacity(), 0_u8);
}
Ok(len) => {
buffer.resize(len, 0);
buffer.resize(len, 0_u8);
return Ok(ZString::new(buffer).unwrap());
}
Err(errno) => return Err(errno),
Expand Down
16 changes: 9 additions & 7 deletions src/path/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::ffi::{ZStr, ZString};
use crate::io;
#[cfg(feature = "itoa")]
use crate::path::DecInt;
use crate::path::SMALL_PATH_BUFFER_SIZE;
use alloc::borrow::Cow;
use alloc::string::String;
use alloc::vec::Vec;
Expand Down Expand Up @@ -952,16 +953,17 @@ fn with_z_str<T, F>(bytes: &[u8], f: F) -> io::Result<T>
where
F: FnOnce(&ZStr) -> io::Result<T>,
{
// Most paths are less than this long. The rest can go through the dynamic
// allocation path. If you're opening many files in a directory with a long
// path, consider opening the directory and using openat to open the files
// under it, which will avoid this, and is often faster in the OS as well.
const SIZE: usize = 256;
// Most paths are less than `SMALL_PATH_BUFFER_SIZE` long. The rest can go through
// the dynamic allocation path. If you're opening many files in a directory
// with a long path, consider opening the directory and using `openat` to open
// the files under it, which will avoid this, and is often faster in the OS
// as well.

// Test with >= so that we have room for the trailing NUL.
if bytes.len() >= SIZE {
if bytes.len() >= SMALL_PATH_BUFFER_SIZE {
return with_z_str_slow_path(bytes, f);
}
let mut buffer: [u8; SIZE] = [0_u8; SIZE];
let mut buffer: [u8; SMALL_PATH_BUFFER_SIZE] = [0_u8; SMALL_PATH_BUFFER_SIZE];
// Copy the bytes in; the buffer already has zeros for the trailing NUL.
buffer[..bytes.len()].copy_from_slice(bytes);
f(ZStr::from_bytes_with_nul(&buffer[..=bytes.len()]).map_err(|_cstr_err| io::Error::INVAL)?)
Expand Down
2 changes: 2 additions & 0 deletions src/path/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ mod dec_int;
pub use arg::Arg;
#[cfg(feature = "itoa")]
pub use dec_int::DecInt;

pub(crate) const SMALL_PATH_BUFFER_SIZE: usize = 256;
9 changes: 7 additions & 2 deletions src/process/chdir.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::ffi::ZString;
use crate::path::SMALL_PATH_BUFFER_SIZE;
use crate::{imp, io, path};
use alloc::vec::Vec;
#[cfg(not(target_os = "fuchsia"))]
Expand Down Expand Up @@ -52,11 +53,15 @@ fn _getcwd(mut buffer: Vec<u8>) -> io::Result<ZString> {
// This code would benefit from having a better way to read into
// uninitialized memory, but that requires `unsafe`.
buffer.clear();
buffer.resize(256, 0_u8);
buffer.reserve(SMALL_PATH_BUFFER_SIZE);
buffer.resize(buffer.capacity(), 0_u8);

loop {
match imp::syscalls::getcwd(&mut buffer) {
Err(imp::io::Error::RANGE) => buffer.resize(buffer.len() * 2, 0_u8),
Err(imp::io::Error::RANGE) => {
buffer.reserve(1); // use `Vec` reallocation strategy to grow capacity exponentially
buffer.resize(buffer.capacity(), 0_u8);
}
Ok(_) => {
let len = buffer.iter().position(|x| *x == b'\0').unwrap();
buffer.resize(len, 0_u8);
Expand Down