Skip to content

Commit c8a5b13

Browse files
committed
Make std::env::current_dir work for path names longer than 2048 bytes on non-Windows
1 parent 50df2a0 commit c8a5b13

File tree

3 files changed

+49
-10
lines changed

3 files changed

+49
-10
lines changed

src/libstd/env.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ use sys::os as os_imp;
3636
///
3737
/// * Current directory does not exist.
3838
/// * There are insufficient permissions to access the current directory.
39-
/// * The internal buffer is not large enough to hold the path.
4039
///
4140
/// # Examples
4241
///

src/libstd/sys/unix/mod.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,41 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
7575
}
7676
}
7777

78+
// Some system functions expect the user to pass a appropiately-sized buffer
79+
// without specifying its size. They will only report back whether the buffer
80+
// was large enough or not.
81+
//
82+
// The callback is yielded a (pointer, len) pair which can be
83+
// passed to a syscall. The `ptr` is valid for `len` items (i8 in this case).
84+
// The closure is expected to return `None` if the space was insufficient and
85+
// `Some(r)` if the syscall did not fail due to insufficient space.
86+
fn fill_bytes_buf<F, T>(mut f: F) -> io::Result<T>
87+
where F: FnMut(*mut i8, libc::size_t) -> Option<io::Result<T>>,
88+
{
89+
// Start off with a stack buf but then spill over to the heap if we end up
90+
// needing more space.
91+
let mut stack_buf = [0i8; os::BUF_BYTES];
92+
let mut heap_buf = Vec::new();
93+
unsafe {
94+
let mut n = stack_buf.len();
95+
loop {
96+
let buf = if n <= stack_buf.len() {
97+
&mut stack_buf[..]
98+
} else {
99+
heap_buf.set_len(0);
100+
heap_buf.reserve(n);
101+
heap_buf.set_len(n);
102+
&mut heap_buf[..]
103+
};
104+
105+
match f(buf.as_mut_ptr(), n as libc::size_t) {
106+
None => n *= 2,
107+
Some(r) => return r,
108+
}
109+
}
110+
}
111+
}
112+
78113
pub fn cvt<T: One + PartialEq + Neg<Output=T>>(t: T) -> io::Result<T> {
79114
let one: T = T::one();
80115
if t == -one {

src/libstd/sys/unix/os.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ use io;
2222
use iter;
2323
use libc::{self, c_int, c_char, c_void};
2424
use mem;
25-
use ptr;
2625
use path::{self, PathBuf};
26+
use ptr;
2727
use slice;
2828
use str;
2929
use sys::c;
3030
use sys::fd;
3131
use vec;
3232

33-
const BUF_BYTES: usize = 2048;
33+
pub const BUF_BYTES: usize = 2048;
3434
const TMPBUF_SZ: usize = 128;
3535

3636
fn bytes2path(b: &[u8]) -> PathBuf {
@@ -102,14 +102,19 @@ pub fn error_string(errno: i32) -> String {
102102
}
103103

104104
pub fn getcwd() -> io::Result<PathBuf> {
105-
let mut buf = [0 as c_char; BUF_BYTES];
106-
unsafe {
107-
if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
108-
Err(io::Error::last_os_error())
109-
} else {
110-
Ok(bytes2path(CStr::from_ptr(buf.as_ptr()).to_bytes()))
105+
super::fill_bytes_buf(|buf, len| {
106+
unsafe {
107+
Some(if !libc::getcwd(buf, len).is_null() {
108+
Ok(bytes2path(CStr::from_ptr(buf).to_bytes()))
109+
} else {
110+
let error = io::Error::last_os_error();
111+
if error.raw_os_error().unwrap() == libc::ERANGE {
112+
return None;
113+
}
114+
Err(error)
115+
})
111116
}
112-
}
117+
})
113118
}
114119

115120
pub fn chdir(p: &path::Path) -> io::Result<()> {

0 commit comments

Comments
 (0)