diff options
author | Alex Saveau <saveau.alexandre@gmail.com> | 2022-02-02 19:40:50 -0800 |
---|---|---|
committer | Alex Saveau <saveau.alexandre@gmail.com> | 2022-02-27 13:22:07 -0800 |
commit | 378a66dd1837a634ef714166f657cb7111c291ec (patch) | |
tree | 0c2b2031444621bd8d42738baba4cbf5da6238e5 /src/lib.rs | |
parent | 15af9b6d8116924c64fe07a730c71d61683c04a4 (diff) | |
download | nix-378a66dd1837a634ef714166f657cb7111c291ec.zip |
Remove `PATH_MAX` restriction from `with_nix_path`
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 47 |
1 files changed, 28 insertions, 19 deletions
@@ -156,19 +156,11 @@ feature! { #[allow(missing_docs)] pub mod unistd; -/* - * - * ===== Result / Error ===== - * - */ - -use libc::PATH_MAX; - -use std::{ptr, result, slice}; -use std::ffi::{CStr, OsStr}; +use std::ffi::{CStr, CString, OsStr}; use std::mem::MaybeUninit; use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; +use std::{ptr, result, slice}; use errno::Errno; @@ -242,12 +234,9 @@ impl NixPath for CStr { } fn with_nix_path<T, F>(&self, f: F) -> Result<T> - where F: FnOnce(&CStr) -> T { - // Equivalence with the [u8] impl. - if self.len() >= PATH_MAX as usize { - return Err(Errno::ENAMETOOLONG) - } - + where + F: FnOnce(&CStr) -> T, + { Ok(f(self)) } } @@ -265,11 +254,19 @@ impl NixPath for [u8] { where F: FnOnce(&CStr) -> T, { - if self.len() >= PATH_MAX as usize { - return Err(Errno::ENAMETOOLONG); + // The real PATH_MAX is typically 4096, but it's statistically unlikely to have a path + // longer than ~300 bytes. See the the PR description to get stats for your own machine. + // https://github.com/nix-rust/nix/pull/1656 + // + // By being smaller than a memory page, we also avoid the compiler inserting a probe frame: + // https://docs.rs/compiler_builtins/latest/compiler_builtins/probestack/index.html + const MAX_STACK_ALLOCATION: usize = 1024; + + if self.len() >= MAX_STACK_ALLOCATION { + return with_nix_path_allocating(self, f); } - let mut buf = MaybeUninit::<[u8; PATH_MAX as usize]>::uninit(); + let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit(); let buf_ptr = buf.as_mut_ptr() as *mut u8; unsafe { @@ -284,6 +281,18 @@ impl NixPath for [u8] { } } +#[cold] +#[inline(never)] +fn with_nix_path_allocating<T, F>(from: &[u8], f: F) -> Result<T> +where + F: FnOnce(&CStr) -> T, +{ + match CString::new(from) { + Ok(s) => Ok(f(&s)), + Err(_) => Err(Errno::EINVAL), + } +} + impl NixPath for Path { fn is_empty(&self) -> bool { NixPath::is_empty(self.as_os_str()) |