@@ -376,13 +376,19 @@ impl fmt::Debug for File {
376
376
377
377
#[ cfg( target_os = "macos" ) ]
378
378
fn get_path ( fd : c_int ) -> Option < PathBuf > {
379
+ // FIXME: The use of PATH_MAX is generally not encouraged, but it
380
+ // is inevitable in this case because OS X defines `fcntl` with
381
+ // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
382
+ // alternatives. If a better method is invented, it should be used
383
+ // instead.
379
384
let mut buf = vec ! [ 0 ; libc:: PATH_MAX as usize ] ;
380
385
let n = unsafe { libc:: fcntl ( fd, libc:: F_GETPATH , buf. as_ptr ( ) ) } ;
381
386
if n == -1 {
382
387
return None ;
383
388
}
384
389
let l = buf. iter ( ) . position ( |& c| c == 0 ) . unwrap ( ) ;
385
390
buf. truncate ( l as usize ) ;
391
+ buf. shrink_to_fit ( ) ;
386
392
Some ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
387
393
}
388
394
@@ -466,18 +472,27 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
466
472
pub fn readlink ( p : & Path ) -> io:: Result < PathBuf > {
467
473
let c_path = try!( cstr ( p) ) ;
468
474
let p = c_path. as_ptr ( ) ;
469
- let mut len = unsafe { libc:: pathconf ( p as * mut _ , libc:: _PC_NAME_MAX) } ;
470
- if len < 0 {
471
- len = 1024 ; // FIXME: read PATH_MAX from C ffi?
472
- }
473
- let mut buf: Vec < u8 > = Vec :: with_capacity ( len as usize ) ;
474
- unsafe {
475
- let n = try!( cvt ( {
476
- libc:: readlink ( p, buf. as_ptr ( ) as * mut c_char , len as size_t )
477
- } ) ) ;
478
- buf. set_len ( n as usize ) ;
475
+
476
+ let mut buf = Vec :: with_capacity ( 256 ) ;
477
+
478
+ loop {
479
+ let buf_read = try!( cvt ( unsafe {
480
+ libc:: readlink ( p, buf. as_mut_ptr ( ) as * mut _ , buf. capacity ( ) as libc:: size_t )
481
+ } ) ) as usize ;
482
+
483
+ unsafe { buf. set_len ( buf_read) ; }
484
+
485
+ if buf_read != buf. capacity ( ) {
486
+ buf. shrink_to_fit ( ) ;
487
+
488
+ return Ok ( PathBuf :: from ( OsString :: from_vec ( buf) ) ) ;
489
+ }
490
+
491
+ // Trigger the internal buffer resizing logic of `Vec` by requiring
492
+ // more space than the current capacity. The length is guaranteed to be
493
+ // the same as the capacity due to the if statement above.
494
+ buf. reserve ( 1 ) ;
479
495
}
480
- Ok ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
481
496
}
482
497
483
498
pub fn symlink ( src : & Path , dst : & Path ) -> io:: Result < ( ) > {
@@ -514,15 +529,15 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> {
514
529
515
530
pub fn canonicalize ( p : & Path ) -> io:: Result < PathBuf > {
516
531
let path = try!( CString :: new ( p. as_os_str ( ) . as_bytes ( ) ) ) ;
517
- let mut buf = vec ! [ 0u8 ; 16 * 1024 ] ;
532
+ let buf;
518
533
unsafe {
519
- let r = c:: realpath ( path. as_ptr ( ) , buf . as_mut_ptr ( ) as * mut _ ) ;
534
+ let r = c:: realpath ( path. as_ptr ( ) , ptr :: null_mut ( ) ) ;
520
535
if r. is_null ( ) {
521
536
return Err ( io:: Error :: last_os_error ( ) )
522
537
}
538
+ buf = CStr :: from_ptr ( r) . to_bytes ( ) . to_vec ( ) ;
539
+ libc:: free ( r as * mut _ ) ;
523
540
}
524
- let p = buf. iter ( ) . position ( |i| * i == 0 ) . unwrap ( ) ;
525
- buf. truncate ( p) ;
526
541
Ok ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
527
542
}
528
543
0 commit comments