@@ -1265,20 +1265,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
12651265/// ```
12661266#[ stable( feature = "rust1" , since = "1.0.0" ) ]
12671267pub fn remove_dir_all < P : AsRef < Path > > ( path : P ) -> io:: Result < ( ) > {
1268- _remove_dir_all ( path. as_ref ( ) )
1269- }
1270-
1271- fn _remove_dir_all ( path : & Path ) -> io:: Result < ( ) > {
1272- for child in try!( read_dir ( path) ) {
1273- let child = try!( child) . path ( ) ;
1274- let stat = try!( symlink_metadata ( & * child) ) ;
1275- if stat. is_dir ( ) {
1276- try!( remove_dir_all ( & * child) ) ;
1277- } else {
1278- try!( remove_file ( & * child) ) ;
1279- }
1280- }
1281- remove_dir ( path)
1268+ fs_imp:: remove_dir_all ( path. as_ref ( ) )
12821269}
12831270
12841271/// Returns an iterator over the entries within a directory.
@@ -1489,19 +1476,27 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
14891476
14901477#[ cfg( test) ]
14911478mod tests {
1492- #![ allow( deprecated) ] //rand
1493-
14941479 use prelude:: v1:: * ;
14951480 use io:: prelude:: * ;
14961481
14971482 use env;
14981483 use fs:: { self , File , OpenOptions } ;
14991484 use io:: { ErrorKind , SeekFrom } ;
1500- use path:: PathBuf ;
1501- use path:: Path as Path2 ;
1485+ use path:: { Path , PathBuf } ;
15021486 use rand:: { self , StdRng , Rng } ;
15031487 use str;
15041488
1489+ #[ cfg( windows) ]
1490+ use os:: windows:: fs:: { symlink_dir, symlink_file} ;
1491+ #[ cfg( windows) ]
1492+ use sys:: fs:: symlink_junction;
1493+ #[ cfg( unix) ]
1494+ use os:: unix:: fs:: symlink as symlink_dir;
1495+ #[ cfg( unix) ]
1496+ use os:: unix:: fs:: symlink as symlink_file;
1497+ #[ cfg( unix) ]
1498+ use os:: unix:: fs:: symlink as symlink_junction;
1499+
15051500 macro_rules! check { ( $e: expr) => (
15061501 match $e {
15071502 Ok ( t) => t,
@@ -1525,7 +1520,7 @@ mod tests {
15251520 p. join ( path)
15261521 }
15271522
1528- fn path < ' a > ( & ' a self ) -> & ' a Path2 {
1523+ fn path < ' a > ( & ' a self ) -> & ' a Path {
15291524 let TempDir ( ref p) = * self ;
15301525 p
15311526 }
@@ -1548,6 +1543,27 @@ mod tests {
15481543 TempDir ( ret)
15491544 }
15501545
1546+ // Several test fail on windows if the user does not have permission to
1547+ // create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
1548+ // disabling these test on Windows, use this function to test whether we
1549+ // have permission, and return otherwise. This way, we still don't run these
1550+ // tests most of the time, but at least we do if the user has the right
1551+ // permissions.
1552+ pub fn got_symlink_permission ( tmpdir : & TempDir ) -> bool {
1553+ if cfg ! ( unix) { return true }
1554+ let link = tmpdir. join ( "some_hopefully_unique_link_name" ) ;
1555+
1556+ match symlink_file ( r"nonexisting_target" , link) {
1557+ Ok ( _) => true ,
1558+ Err ( ref err) =>
1559+ if err. to_string ( ) . contains ( "A required privilege is not held by the client." ) {
1560+ false
1561+ } else {
1562+ true
1563+ }
1564+ }
1565+ }
1566+
15511567 #[ test]
15521568 fn file_test_io_smoke_test ( ) {
15531569 let message = "it's alright. have a good time" ;
@@ -1578,8 +1594,9 @@ mod tests {
15781594 if cfg ! ( unix) {
15791595 error ! ( result, "o such file or directory" ) ;
15801596 }
1581- // error!(result, "couldn't open path as file");
1582- // error!(result, format!("path={}; mode=open; access=read", filename.display()));
1597+ if cfg ! ( windows) {
1598+ error ! ( result, "The system cannot find the file specified" ) ;
1599+ }
15831600 }
15841601
15851602 #[ test]
@@ -1592,8 +1609,9 @@ mod tests {
15921609 if cfg ! ( unix) {
15931610 error ! ( result, "o such file or directory" ) ;
15941611 }
1595- // error!(result, "couldn't unlink path");
1596- // error!(result, format!("path={}", filename.display()));
1612+ if cfg ! ( windows) {
1613+ error ! ( result, "The system cannot find the file specified" ) ;
1614+ }
15971615 }
15981616
15991617 #[ test]
@@ -1799,6 +1817,7 @@ mod tests {
17991817 }
18001818
18011819 #[ test]
1820+ #[ allow( deprecated) ]
18021821 fn file_test_walk_dir ( ) {
18031822 let tmpdir = tmpdir ( ) ;
18041823 let dir = & tmpdir. join ( "walk_dir" ) ;
@@ -1855,19 +1874,13 @@ mod tests {
18551874 let result = fs:: create_dir_all ( & file) ;
18561875
18571876 assert ! ( result. is_err( ) ) ;
1858- // error!(result, "couldn't recursively mkdir");
1859- // error!(result, "couldn't create directory");
1860- // error!(result, "mode=0700");
1861- // error!(result, format!("path={}", file.display()));
18621877 }
18631878
18641879 #[ test]
18651880 fn recursive_mkdir_slash ( ) {
1866- check ! ( fs:: create_dir_all( & Path2 :: new( "/" ) ) ) ;
1881+ check ! ( fs:: create_dir_all( & Path :: new( "/" ) ) ) ;
18671882 }
18681883
1869- // FIXME(#12795) depends on lstat to work on windows
1870- #[ cfg( not( windows) ) ]
18711884 #[ test]
18721885 fn recursive_rmdir ( ) {
18731886 let tmpdir = tmpdir ( ) ;
@@ -1879,7 +1892,7 @@ mod tests {
18791892 check ! ( fs:: create_dir_all( & dtt) ) ;
18801893 check ! ( fs:: create_dir_all( & d2) ) ;
18811894 check ! ( check!( File :: create( & canary) ) . write( b"foo" ) ) ;
1882- check ! ( fs :: soft_link ( & d2, & dt. join( "d2" ) ) ) ;
1895+ check ! ( symlink_junction ( & d2, & dt. join( "d2" ) ) ) ;
18831896 check ! ( fs:: remove_dir_all( & d1) ) ;
18841897
18851898 assert ! ( !d1. is_dir( ) ) ;
@@ -1888,8 +1901,8 @@ mod tests {
18881901
18891902 #[ test]
18901903 fn unicode_path_is_dir ( ) {
1891- assert ! ( Path2 :: new( "." ) . is_dir( ) ) ;
1892- assert ! ( !Path2 :: new( "test/stdtest/fs.rs" ) . is_dir( ) ) ;
1904+ assert ! ( Path :: new( "." ) . is_dir( ) ) ;
1905+ assert ! ( !Path :: new( "test/stdtest/fs.rs" ) . is_dir( ) ) ;
18931906
18941907 let tmpdir = tmpdir ( ) ;
18951908
@@ -1907,21 +1920,21 @@ mod tests {
19071920
19081921 #[ test]
19091922 fn unicode_path_exists ( ) {
1910- assert ! ( Path2 :: new( "." ) . exists( ) ) ;
1911- assert ! ( !Path2 :: new( "test/nonexistent-bogus-path" ) . exists( ) ) ;
1923+ assert ! ( Path :: new( "." ) . exists( ) ) ;
1924+ assert ! ( !Path :: new( "test/nonexistent-bogus-path" ) . exists( ) ) ;
19121925
19131926 let tmpdir = tmpdir ( ) ;
19141927 let unicode = tmpdir. path ( ) ;
19151928 let unicode = unicode. join ( & format ! ( "test-각丁ー再见" ) ) ;
19161929 check ! ( fs:: create_dir( & unicode) ) ;
19171930 assert ! ( unicode. exists( ) ) ;
1918- assert ! ( !Path2 :: new( "test/unicode-bogus-path-각丁ー再见" ) . exists( ) ) ;
1931+ assert ! ( !Path :: new( "test/unicode-bogus-path-각丁ー再见" ) . exists( ) ) ;
19191932 }
19201933
19211934 #[ test]
19221935 fn copy_file_does_not_exist ( ) {
1923- let from = Path2 :: new ( "test/nonexistent-bogus-path" ) ;
1924- let to = Path2 :: new ( "test/other-bogus-path" ) ;
1936+ let from = Path :: new ( "test/nonexistent-bogus-path" ) ;
1937+ let to = Path :: new ( "test/other-bogus-path" ) ;
19251938
19261939 match fs:: copy ( & from, & to) {
19271940 Ok ( ..) => panic ! ( ) ,
@@ -1935,7 +1948,7 @@ mod tests {
19351948 #[ test]
19361949 fn copy_src_does_not_exist ( ) {
19371950 let tmpdir = tmpdir ( ) ;
1938- let from = Path2 :: new ( "test/nonexistent-bogus-path" ) ;
1951+ let from = Path :: new ( "test/nonexistent-bogus-path" ) ;
19391952 let to = tmpdir. join ( "out.txt" ) ;
19401953 check ! ( check!( File :: create( & to) ) . write( b"hello" ) ) ;
19411954 assert ! ( fs:: copy( & from, & to) . is_err( ) ) ;
@@ -2026,34 +2039,35 @@ mod tests {
20262039 assert_eq ! ( v, b"carrot" . to_vec( ) ) ;
20272040 }
20282041
2029- #[ cfg( not( windows) ) ] // FIXME(#10264) operation not permitted?
20302042 #[ test]
20312043 fn symlinks_work ( ) {
20322044 let tmpdir = tmpdir ( ) ;
2045+ if !got_symlink_permission ( & tmpdir) { return } ;
2046+
20332047 let input = tmpdir. join ( "in.txt" ) ;
20342048 let out = tmpdir. join ( "out.txt" ) ;
20352049
20362050 check ! ( check!( File :: create( & input) ) . write( "foobar" . as_bytes( ) ) ) ;
2037- check ! ( fs:: soft_link( & input, & out) ) ;
2038- // if cfg!(not(windows)) {
2039- // assert_eq!(check!(lstat(&out)).kind, FileType::Symlink);
2040- // assert_eq!(check!(out.lstat()).kind, FileType::Symlink);
2041- // }
2051+ check ! ( symlink_file( & input, & out) ) ;
2052+ assert ! ( check!( out. symlink_metadata( ) ) . file_type( ) . is_symlink( ) ) ;
20422053 assert_eq ! ( check!( fs:: metadata( & out) ) . len( ) ,
20432054 check!( fs:: metadata( & input) ) . len( ) ) ;
20442055 let mut v = Vec :: new ( ) ;
20452056 check ! ( check!( File :: open( & out) ) . read_to_end( & mut v) ) ;
20462057 assert_eq ! ( v, b"foobar" . to_vec( ) ) ;
20472058 }
20482059
2049- #[ cfg( not( windows) ) ] // apparently windows doesn't like symlinks
20502060 #[ test]
20512061 fn symlink_noexist ( ) {
2062+ // Symlinks can point to things that don't exist
20522063 let tmpdir = tmpdir ( ) ;
2053- // symlinks can point to things that don't exist
2054- check ! ( fs:: soft_link( & tmpdir. join( "foo" ) , & tmpdir. join( "bar" ) ) ) ;
2055- assert_eq ! ( check!( fs:: read_link( & tmpdir. join( "bar" ) ) ) ,
2056- tmpdir. join( "foo" ) ) ;
2064+ if !got_symlink_permission ( & tmpdir) { return } ;
2065+
2066+ // Use a relative path for testing. Symlinks get normalized by Windows,
2067+ // so we may not get the same path back for absolute paths
2068+ check ! ( symlink_file( & "foo" , & tmpdir. join( "bar" ) ) ) ;
2069+ assert_eq ! ( check!( fs:: read_link( & tmpdir. join( "bar" ) ) ) . to_str( ) . unwrap( ) ,
2070+ "foo" ) ;
20572071 }
20582072
20592073 #[ test]
@@ -2346,9 +2360,10 @@ mod tests {
23462360 }
23472361
23482362 #[ test]
2349- #[ cfg( not( windows) ) ]
23502363 fn realpath_works ( ) {
23512364 let tmpdir = tmpdir ( ) ;
2365+ if !got_symlink_permission ( & tmpdir) { return } ;
2366+
23522367 let tmpdir = fs:: canonicalize ( tmpdir. path ( ) ) . unwrap ( ) ;
23532368 let file = tmpdir. join ( "test" ) ;
23542369 let dir = tmpdir. join ( "test2" ) ;
@@ -2357,8 +2372,8 @@ mod tests {
23572372
23582373 File :: create ( & file) . unwrap ( ) ;
23592374 fs:: create_dir ( & dir) . unwrap ( ) ;
2360- fs :: soft_link ( & file, & link) . unwrap ( ) ;
2361- fs :: soft_link ( & dir, & linkdir) . unwrap ( ) ;
2375+ symlink_file ( & file, & link) . unwrap ( ) ;
2376+ symlink_dir ( & dir, & linkdir) . unwrap ( ) ;
23622377
23632378 assert ! ( link. symlink_metadata( ) . unwrap( ) . file_type( ) . is_symlink( ) ) ;
23642379
@@ -2370,11 +2385,11 @@ mod tests {
23702385 }
23712386
23722387 #[ test]
2373- #[ cfg( not( windows) ) ]
23742388 fn realpath_works_tricky ( ) {
23752389 let tmpdir = tmpdir ( ) ;
2376- let tmpdir = fs :: canonicalize ( tmpdir. path ( ) ) . unwrap ( ) ;
2390+ if ! got_symlink_permission ( & tmpdir) { return } ;
23772391
2392+ let tmpdir = fs:: canonicalize ( tmpdir. path ( ) ) . unwrap ( ) ;
23782393 let a = tmpdir. join ( "a" ) ;
23792394 let b = a. join ( "b" ) ;
23802395 let c = b. join ( "c" ) ;
@@ -2385,8 +2400,14 @@ mod tests {
23852400 fs:: create_dir_all ( & b) . unwrap ( ) ;
23862401 fs:: create_dir_all ( & d) . unwrap ( ) ;
23872402 File :: create ( & f) . unwrap ( ) ;
2388- fs:: soft_link ( "../d/e" , & c) . unwrap ( ) ;
2389- fs:: soft_link ( "../f" , & e) . unwrap ( ) ;
2403+ if cfg ! ( not( windows) ) {
2404+ symlink_dir ( "../d/e" , & c) . unwrap ( ) ;
2405+ symlink_file ( "../f" , & e) . unwrap ( ) ;
2406+ }
2407+ if cfg ! ( windows) {
2408+ symlink_dir ( r"..\d\e" , & c) . unwrap ( ) ;
2409+ symlink_file ( r"..\f" , & e) . unwrap ( ) ;
2410+ }
23902411
23912412 assert_eq ! ( fs:: canonicalize( & c) . unwrap( ) , f) ;
23922413 assert_eq ! ( fs:: canonicalize( & e) . unwrap( ) , f) ;
@@ -2420,4 +2441,31 @@ mod tests {
24202441 let res = fs:: read_dir ( "/path/that/does/not/exist" ) ;
24212442 assert_eq ! ( res. err( ) . unwrap( ) . kind( ) , ErrorKind :: NotFound ) ;
24222443 }
2444+
2445+ #[ test]
2446+ fn create_dir_all_with_junctions ( ) {
2447+ let tmpdir = tmpdir ( ) ;
2448+ let target = tmpdir. join ( "target" ) ;
2449+
2450+ let junction = tmpdir. join ( "junction" ) ;
2451+ let b = junction. join ( "a/b" ) ;
2452+
2453+ let link = tmpdir. join ( "link" ) ;
2454+ let d = link. join ( "c/d" ) ;
2455+
2456+ fs:: create_dir ( & target) . unwrap ( ) ;
2457+
2458+ check ! ( symlink_junction( & target, & junction) ) ;
2459+ check ! ( fs:: create_dir_all( & b) ) ;
2460+ // the junction itself is not a directory, but `is_dir()` on a Path
2461+ // follows links
2462+ assert ! ( junction. is_dir( ) ) ;
2463+ assert ! ( b. exists( ) ) ;
2464+
2465+ if !got_symlink_permission ( & tmpdir) { return } ;
2466+ check ! ( symlink_dir( & target, & link) ) ;
2467+ check ! ( fs:: create_dir_all( & d) ) ;
2468+ assert ! ( link. is_dir( ) ) ;
2469+ assert ! ( d. exists( ) ) ;
2470+ }
24232471}
0 commit comments