Make std::env::current_dir work for path names longer than 2048 bytes on non-Windows

This commit is contained in:
Tobias Bucher 2015-07-08 21:36:46 +02:00
parent 50df2a09b8
commit c8a5b1368e
3 changed files with 49 additions and 10 deletions

View File

@ -36,7 +36,6 @@ use sys::os as os_imp;
///
/// * Current directory does not exist.
/// * There are insufficient permissions to access the current directory.
/// * The internal buffer is not large enough to hold the path.
///
/// # Examples
///

View File

@ -75,6 +75,41 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
}
}
// Some system functions expect the user to pass a appropiately-sized buffer
// without specifying its size. They will only report back whether the buffer
// was large enough or not.
//
// The callback is yielded a (pointer, len) pair which can be
// passed to a syscall. The `ptr` is valid for `len` items (i8 in this case).
// The closure is expected to return `None` if the space was insufficient and
// `Some(r)` if the syscall did not fail due to insufficient space.
fn fill_bytes_buf<F, T>(mut f: F) -> io::Result<T>
where F: FnMut(*mut i8, libc::size_t) -> Option<io::Result<T>>,
{
// Start off with a stack buf but then spill over to the heap if we end up
// needing more space.
let mut stack_buf = [0i8; os::BUF_BYTES];
let mut heap_buf = Vec::new();
unsafe {
let mut n = stack_buf.len();
loop {
let buf = if n <= stack_buf.len() {
&mut stack_buf[..]
} else {
heap_buf.set_len(0);
heap_buf.reserve(n);
heap_buf.set_len(n);
&mut heap_buf[..]
};
match f(buf.as_mut_ptr(), n as libc::size_t) {
None => n *= 2,
Some(r) => return r,
}
}
}
}
pub fn cvt<T: One + PartialEq + Neg<Output=T>>(t: T) -> io::Result<T> {
let one: T = T::one();
if t == -one {

View File

@ -22,15 +22,15 @@ use io;
use iter;
use libc::{self, c_int, c_char, c_void};
use mem;
use ptr;
use path::{self, PathBuf};
use ptr;
use slice;
use str;
use sys::c;
use sys::fd;
use vec;
const BUF_BYTES: usize = 2048;
pub const BUF_BYTES: usize = 2048;
const TMPBUF_SZ: usize = 128;
fn bytes2path(b: &[u8]) -> PathBuf {
@ -102,14 +102,19 @@ pub fn error_string(errno: i32) -> String {
}
pub fn getcwd() -> io::Result<PathBuf> {
let mut buf = [0 as c_char; BUF_BYTES];
unsafe {
if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
Err(io::Error::last_os_error())
} else {
Ok(bytes2path(CStr::from_ptr(buf.as_ptr()).to_bytes()))
super::fill_bytes_buf(|buf, len| {
unsafe {
Some(if !libc::getcwd(buf, len).is_null() {
Ok(bytes2path(CStr::from_ptr(buf).to_bytes()))
} else {
let error = io::Error::last_os_error();
if error.raw_os_error().unwrap() == libc::ERANGE {
return None;
}
Err(error)
})
}
}
})
}
pub fn chdir(p: &path::Path) -> io::Result<()> {