@@ -1265,20 +1265,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
1265
1265
/// ```
1266
1266
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1267
1267
pub 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 ( ) )
1282
1269
}
1283
1270
1284
1271
/// Returns an iterator over the entries within a directory.
@@ -1489,19 +1476,27 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
1489
1476
1490
1477
#[ cfg( test) ]
1491
1478
mod tests {
1492
- #![ allow( deprecated) ] //rand
1493
-
1494
1479
use prelude:: v1:: * ;
1495
1480
use io:: prelude:: * ;
1496
1481
1497
1482
use env;
1498
1483
use fs:: { self , File , OpenOptions } ;
1499
1484
use io:: { ErrorKind , SeekFrom } ;
1500
- use path:: PathBuf ;
1501
- use path:: Path as Path2 ;
1485
+ use path:: { Path , PathBuf } ;
1502
1486
use rand:: { self , StdRng , Rng } ;
1503
1487
use str;
1504
1488
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
+
1505
1500
macro_rules! check { ( $e: expr) => (
1506
1501
match $e {
1507
1502
Ok ( t) => t,
@@ -1525,7 +1520,7 @@ mod tests {
1525
1520
p. join ( path)
1526
1521
}
1527
1522
1528
- fn path < ' a > ( & ' a self ) -> & ' a Path2 {
1523
+ fn path < ' a > ( & ' a self ) -> & ' a Path {
1529
1524
let TempDir ( ref p) = * self ;
1530
1525
p
1531
1526
}
@@ -1548,6 +1543,27 @@ mod tests {
1548
1543
TempDir ( ret)
1549
1544
}
1550
1545
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
+
1551
1567
#[ test]
1552
1568
fn file_test_io_smoke_test ( ) {
1553
1569
let message = "it's alright. have a good time" ;
@@ -1578,8 +1594,9 @@ mod tests {
1578
1594
if cfg ! ( unix) {
1579
1595
error ! ( result, "o such file or directory" ) ;
1580
1596
}
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
+ }
1583
1600
}
1584
1601
1585
1602
#[ test]
@@ -1592,8 +1609,9 @@ mod tests {
1592
1609
if cfg ! ( unix) {
1593
1610
error ! ( result, "o such file or directory" ) ;
1594
1611
}
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
+ }
1597
1615
}
1598
1616
1599
1617
#[ test]
@@ -1799,6 +1817,7 @@ mod tests {
1799
1817
}
1800
1818
1801
1819
#[ test]
1820
+ #[ allow( deprecated) ]
1802
1821
fn file_test_walk_dir ( ) {
1803
1822
let tmpdir = tmpdir ( ) ;
1804
1823
let dir = & tmpdir. join ( "walk_dir" ) ;
@@ -1855,19 +1874,13 @@ mod tests {
1855
1874
let result = fs:: create_dir_all ( & file) ;
1856
1875
1857
1876
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()));
1862
1877
}
1863
1878
1864
1879
#[ test]
1865
1880
fn recursive_mkdir_slash ( ) {
1866
- check ! ( fs:: create_dir_all( & Path2 :: new( "/" ) ) ) ;
1881
+ check ! ( fs:: create_dir_all( & Path :: new( "/" ) ) ) ;
1867
1882
}
1868
1883
1869
- // FIXME(#12795) depends on lstat to work on windows
1870
- #[ cfg( not( windows) ) ]
1871
1884
#[ test]
1872
1885
fn recursive_rmdir ( ) {
1873
1886
let tmpdir = tmpdir ( ) ;
@@ -1879,7 +1892,7 @@ mod tests {
1879
1892
check ! ( fs:: create_dir_all( & dtt) ) ;
1880
1893
check ! ( fs:: create_dir_all( & d2) ) ;
1881
1894
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" ) ) ) ;
1883
1896
check ! ( fs:: remove_dir_all( & d1) ) ;
1884
1897
1885
1898
assert ! ( !d1. is_dir( ) ) ;
@@ -1888,8 +1901,8 @@ mod tests {
1888
1901
1889
1902
#[ test]
1890
1903
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( ) ) ;
1893
1906
1894
1907
let tmpdir = tmpdir ( ) ;
1895
1908
@@ -1907,21 +1920,21 @@ mod tests {
1907
1920
1908
1921
#[ test]
1909
1922
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( ) ) ;
1912
1925
1913
1926
let tmpdir = tmpdir ( ) ;
1914
1927
let unicode = tmpdir. path ( ) ;
1915
1928
let unicode = unicode. join ( & format ! ( "test-각丁ー再见" ) ) ;
1916
1929
check ! ( fs:: create_dir( & unicode) ) ;
1917
1930
assert ! ( unicode. exists( ) ) ;
1918
- assert ! ( !Path2 :: new( "test/unicode-bogus-path-각丁ー再见" ) . exists( ) ) ;
1931
+ assert ! ( !Path :: new( "test/unicode-bogus-path-각丁ー再见" ) . exists( ) ) ;
1919
1932
}
1920
1933
1921
1934
#[ test]
1922
1935
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" ) ;
1925
1938
1926
1939
match fs:: copy ( & from, & to) {
1927
1940
Ok ( ..) => panic ! ( ) ,
@@ -1935,7 +1948,7 @@ mod tests {
1935
1948
#[ test]
1936
1949
fn copy_src_does_not_exist ( ) {
1937
1950
let tmpdir = tmpdir ( ) ;
1938
- let from = Path2 :: new ( "test/nonexistent-bogus-path" ) ;
1951
+ let from = Path :: new ( "test/nonexistent-bogus-path" ) ;
1939
1952
let to = tmpdir. join ( "out.txt" ) ;
1940
1953
check ! ( check!( File :: create( & to) ) . write( b"hello" ) ) ;
1941
1954
assert ! ( fs:: copy( & from, & to) . is_err( ) ) ;
@@ -2026,34 +2039,35 @@ mod tests {
2026
2039
assert_eq ! ( v, b"carrot" . to_vec( ) ) ;
2027
2040
}
2028
2041
2029
- #[ cfg( not( windows) ) ] // FIXME(#10264) operation not permitted?
2030
2042
#[ test]
2031
2043
fn symlinks_work ( ) {
2032
2044
let tmpdir = tmpdir ( ) ;
2045
+ if !got_symlink_permission ( & tmpdir) { return } ;
2046
+
2033
2047
let input = tmpdir. join ( "in.txt" ) ;
2034
2048
let out = tmpdir. join ( "out.txt" ) ;
2035
2049
2036
2050
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( ) ) ;
2042
2053
assert_eq ! ( check!( fs:: metadata( & out) ) . len( ) ,
2043
2054
check!( fs:: metadata( & input) ) . len( ) ) ;
2044
2055
let mut v = Vec :: new ( ) ;
2045
2056
check ! ( check!( File :: open( & out) ) . read_to_end( & mut v) ) ;
2046
2057
assert_eq ! ( v, b"foobar" . to_vec( ) ) ;
2047
2058
}
2048
2059
2049
- #[ cfg( not( windows) ) ] // apparently windows doesn't like symlinks
2050
2060
#[ test]
2051
2061
fn symlink_noexist ( ) {
2062
+ // Symlinks can point to things that don't exist
2052
2063
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" ) ;
2057
2071
}
2058
2072
2059
2073
#[ test]
@@ -2346,9 +2360,10 @@ mod tests {
2346
2360
}
2347
2361
2348
2362
#[ test]
2349
- #[ cfg( not( windows) ) ]
2350
2363
fn realpath_works ( ) {
2351
2364
let tmpdir = tmpdir ( ) ;
2365
+ if !got_symlink_permission ( & tmpdir) { return } ;
2366
+
2352
2367
let tmpdir = fs:: canonicalize ( tmpdir. path ( ) ) . unwrap ( ) ;
2353
2368
let file = tmpdir. join ( "test" ) ;
2354
2369
let dir = tmpdir. join ( "test2" ) ;
@@ -2357,8 +2372,8 @@ mod tests {
2357
2372
2358
2373
File :: create ( & file) . unwrap ( ) ;
2359
2374
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 ( ) ;
2362
2377
2363
2378
assert ! ( link. symlink_metadata( ) . unwrap( ) . file_type( ) . is_symlink( ) ) ;
2364
2379
@@ -2370,11 +2385,11 @@ mod tests {
2370
2385
}
2371
2386
2372
2387
#[ test]
2373
- #[ cfg( not( windows) ) ]
2374
2388
fn realpath_works_tricky ( ) {
2375
2389
let tmpdir = tmpdir ( ) ;
2376
- let tmpdir = fs :: canonicalize ( tmpdir. path ( ) ) . unwrap ( ) ;
2390
+ if ! got_symlink_permission ( & tmpdir) { return } ;
2377
2391
2392
+ let tmpdir = fs:: canonicalize ( tmpdir. path ( ) ) . unwrap ( ) ;
2378
2393
let a = tmpdir. join ( "a" ) ;
2379
2394
let b = a. join ( "b" ) ;
2380
2395
let c = b. join ( "c" ) ;
@@ -2385,8 +2400,14 @@ mod tests {
2385
2400
fs:: create_dir_all ( & b) . unwrap ( ) ;
2386
2401
fs:: create_dir_all ( & d) . unwrap ( ) ;
2387
2402
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
+ }
2390
2411
2391
2412
assert_eq ! ( fs:: canonicalize( & c) . unwrap( ) , f) ;
2392
2413
assert_eq ! ( fs:: canonicalize( & e) . unwrap( ) , f) ;
@@ -2420,4 +2441,31 @@ mod tests {
2420
2441
let res = fs:: read_dir ( "/path/that/does/not/exist" ) ;
2421
2442
assert_eq ! ( res. err( ) . unwrap( ) . kind( ) , ErrorKind :: NotFound ) ;
2422
2443
}
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
+ }
2423
2471
}
0 commit comments