8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
+ use libc;
11
12
use std:: io;
12
- use std:: env;
13
- #[ allow( deprecated) ] use std:: old_path:: { self , GenericPath } ;
14
- #[ allow( deprecated) ] use std:: old_io;
15
13
use std:: path:: { Path , PathBuf } ;
16
14
17
- /// Returns an absolute path in the filesystem that `path` points to. The
18
- /// returned path does not contain any symlinks in its hierarchy.
19
- #[ allow( deprecated) ] // readlink is deprecated
15
+ #[ cfg( windows) ]
20
16
pub fn realpath ( original : & Path ) -> io:: Result < PathBuf > {
21
- let old = old_path:: Path :: new ( original. to_str ( ) . unwrap ( ) ) ;
22
- match old_realpath ( & old) {
23
- Ok ( p) => Ok ( PathBuf :: from ( p. as_str ( ) . unwrap ( ) ) ) ,
24
- Err ( e) => Err ( io:: Error :: new ( io:: ErrorKind :: Other , e) )
17
+ use std:: fs:: File ;
18
+ use std:: ffi:: OsString ;
19
+ use std:: os:: windows:: prelude:: * ;
20
+
21
+ extern "system" {
22
+ fn GetFinalPathNameByHandleW ( hFile : libc:: HANDLE ,
23
+ lpszFilePath : libc:: LPCWSTR ,
24
+ cchFilePath : libc:: DWORD ,
25
+ dwFlags : libc:: DWORD ) -> libc:: DWORD ;
25
26
}
26
- }
27
-
28
- #[ allow( deprecated) ]
29
- fn old_realpath ( original : & old_path:: Path ) -> old_io:: IoResult < old_path:: Path > {
30
- use std:: old_io:: fs;
31
- const MAX_LINKS_FOLLOWED : usize = 256 ;
32
- let original = old_path:: Path :: new ( env:: current_dir ( ) . unwrap ( )
33
- . to_str ( ) . unwrap ( ) ) . join ( original) ;
34
27
35
- // Right now lstat on windows doesn't work quite well
36
- if cfg ! ( windows) {
37
- return Ok ( original)
28
+ let mut v = Vec :: with_capacity ( 16 * 1024 ) ;
29
+ let f = try!( File :: open ( original) ) ;
30
+ unsafe {
31
+ let ret = GetFinalPathNameByHandleW ( f. as_raw_handle ( ) ,
32
+ v. as_mut_ptr ( ) ,
33
+ v. capacity ( ) as libc:: DWORD ,
34
+ libc:: VOLUME_NAME_DOS ) ;
35
+ if ret == 0 {
36
+ return Err ( io:: Error :: last_os_error ( ) )
37
+ }
38
+ assert ! ( ret as usize < v. capacit( ) ) ;
39
+ v. set_len ( ret) ;
38
40
}
41
+ Ok ( PathBuf :: from ( OsString :: from_wide ( & v) ) )
42
+ }
39
43
40
- let result = original. root_path ( ) ;
41
- let mut result = result. expect ( "make_absolute has no root_path" ) ;
42
- let mut followed = 0 ;
43
-
44
- for part in original. components ( ) {
45
- result. push ( part) ;
44
+ #[ cfg( unix) ]
45
+ pub fn realpath ( original : & Path ) -> io:: Result < PathBuf > {
46
+ use std:: os:: unix:: prelude:: * ;
47
+ use std:: ffi:: { OsString , CString } ;
46
48
47
- loop {
48
- if followed == MAX_LINKS_FOLLOWED {
49
- return Err ( old_io :: standard_error ( old_io :: InvalidInput ) )
50
- }
49
+ extern {
50
+ fn realpath ( pathname : * const libc :: c_char , resolved : * mut libc :: c_char )
51
+ -> * mut libc :: c_char ;
52
+ }
51
53
52
- match fs:: lstat ( & result) {
53
- Err ( ..) => break ,
54
- Ok ( ref stat) if stat. kind != old_io:: FileType :: Symlink => break ,
55
- Ok ( ..) => {
56
- followed += 1 ;
57
- let path = try!( fs:: readlink ( & result) ) ;
58
- result. pop ( ) ;
59
- result. push ( path) ;
60
- }
61
- }
54
+ let path = try!( CString :: new ( original. as_os_str ( ) . as_bytes ( ) ) ) ;
55
+ let mut buf = vec ! [ 0u8 ; 16 * 1024 ] ;
56
+ unsafe {
57
+ let r = realpath ( path. as_ptr ( ) , buf. as_mut_ptr ( ) as * mut _ ) ;
58
+ if r. is_null ( ) {
59
+ return Err ( io:: Error :: last_os_error ( ) )
62
60
}
63
61
}
64
-
65
- return Ok ( result) ;
62
+ let p = buf. iter ( ) . position ( |i| * i == 0 ) . unwrap ( ) ;
63
+ buf. truncate ( p) ;
64
+ Ok ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
66
65
}
67
66
68
67
#[ cfg( all( not( windows) , test) ) ]
69
68
mod test {
70
- use std:: old_io;
71
- use std:: old_io:: fs:: { File , symlink, mkdir, mkdir_recursive} ;
72
- use super :: old_realpath as realpath;
73
- use std:: old_io:: TempDir ;
74
- use std:: old_path:: { Path , GenericPath } ;
69
+ use tempdir:: TempDir ;
70
+ use std:: fs:: { self , File } ;
71
+ use std:: path:: { Path , PathBuf } ;
75
72
76
73
#[ test]
77
74
fn realpath_works ( ) {
@@ -83,15 +80,15 @@ mod test {
83
80
let linkdir = tmpdir. join ( "test3" ) ;
84
81
85
82
File :: create ( & file) . unwrap ( ) ;
86
- mkdir ( & dir, old_io :: USER_RWX ) . unwrap ( ) ;
87
- symlink ( & file, & link) . unwrap ( ) ;
88
- symlink ( & dir, & linkdir) . unwrap ( ) ;
89
-
90
- assert ! ( realpath( & tmpdir) . unwrap( ) == tmpdir) ;
91
- assert ! ( realpath( & file) . unwrap( ) == file) ;
92
- assert ! ( realpath( & link) . unwrap( ) == file) ;
93
- assert ! ( realpath( & linkdir) . unwrap( ) == dir) ;
94
- assert ! ( realpath( & linkdir. join( "link" ) ) . unwrap( ) == file) ;
83
+ fs :: create_dir ( & dir) . unwrap ( ) ;
84
+ fs :: soft_link ( & file, & link) . unwrap ( ) ;
85
+ fs :: soft_link ( & dir, & linkdir) . unwrap ( ) ;
86
+
87
+ assert_eq ! ( realpath( & tmpdir) . unwrap( ) , tmpdir) ;
88
+ assert_eq ! ( realpath( & file) . unwrap( ) , file) ;
89
+ assert_eq ! ( realpath( & link) . unwrap( ) , file) ;
90
+ assert_eq ! ( realpath( & linkdir) . unwrap( ) , dir) ;
91
+ assert_eq ! ( realpath( & linkdir. join( "link" ) ) . unwrap( ) , file) ;
95
92
}
96
93
97
94
#[ test]
@@ -106,13 +103,13 @@ mod test {
106
103
let e = d. join ( "e" ) ;
107
104
let f = a. join ( "f" ) ;
108
105
109
- mkdir_recursive ( & b, old_io :: USER_RWX ) . unwrap ( ) ;
110
- mkdir_recursive ( & d, old_io :: USER_RWX ) . unwrap ( ) ;
106
+ fs :: create_dir_all ( & b) . unwrap ( ) ;
107
+ fs :: create_dir_all ( & d) . unwrap ( ) ;
111
108
File :: create ( & f) . unwrap ( ) ;
112
- symlink ( & Path :: new ( "../d/e" ) , & c) . unwrap ( ) ;
113
- symlink ( & Path :: new ( "../f" ) , & e) . unwrap ( ) ;
109
+ fs :: soft_link ( "../d/e" , & c) . unwrap ( ) ;
110
+ fs :: soft_link ( "../f" , & e) . unwrap ( ) ;
114
111
115
- assert ! ( realpath( & c) . unwrap( ) == f) ;
116
- assert ! ( realpath( & e) . unwrap( ) == f) ;
112
+ assert_eq ! ( realpath( & c) . unwrap( ) , f) ;
113
+ assert_eq ! ( realpath( & e) . unwrap( ) , f) ;
117
114
}
118
115
}
0 commit comments