File tree Expand file tree Collapse file tree 3 files changed +49
-10
lines changed Expand file tree Collapse file tree 3 files changed +49
-10
lines changed Original file line number Diff line number Diff 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///
Original file line number Diff line number Diff 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+
78113pub fn cvt < T : One + PartialEq + Neg < Output =T > > ( t : T ) -> io:: Result < T > {
79114 let one: T = T :: one ( ) ;
80115 if t == -one {
Original file line number Diff line number Diff line change @@ -22,15 +22,15 @@ use io;
2222use iter;
2323use libc:: { self , c_int, c_char, c_void} ;
2424use mem;
25- use ptr;
2625use path:: { self , PathBuf } ;
26+ use ptr;
2727use slice;
2828use str;
2929use sys:: c;
3030use sys:: fd;
3131use vec;
3232
33- const BUF_BYTES : usize = 2048 ;
33+ pub const BUF_BYTES : usize = 2048 ;
3434const TMPBUF_SZ : usize = 128 ;
3535
3636fn bytes2path ( b : & [ u8 ] ) -> PathBuf {
@@ -102,14 +102,19 @@ pub fn error_string(errno: i32) -> String {
102102}
103103
104104pub 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
115120pub fn chdir ( p : & path:: Path ) -> io:: Result < ( ) > {
You can’t perform that action at this time.
0 commit comments