Skip to content

Commit cdb1df7

Browse files
committed
Enable more fs tests on Windows
1 parent b16fbe7 commit cdb1df7

File tree

3 files changed

+143
-171
lines changed

3 files changed

+143
-171
lines changed

src/libstd/fs.rs

+72-57
Original file line numberDiff line numberDiff line change
@@ -1253,20 +1253,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
12531253
/// ```
12541254
#[stable(feature = "rust1", since = "1.0.0")]
12551255
pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
1256-
_remove_dir_all(path.as_ref())
1257-
}
1258-
1259-
fn _remove_dir_all(path: &Path) -> io::Result<()> {
1260-
for child in try!(read_dir(path)) {
1261-
let child = try!(child).path();
1262-
let stat = try!(symlink_metadata(&*child));
1263-
if stat.is_dir() {
1264-
try!(remove_dir_all(&*child));
1265-
} else {
1266-
try!(remove_file(&*child));
1267-
}
1268-
}
1269-
remove_dir(path)
1256+
fs_imp::remove_dir_all(path.as_ref())
12701257
}
12711258

12721259
/// Returns an iterator over the entries within a directory.
@@ -1477,19 +1464,25 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
14771464

14781465
#[cfg(test)]
14791466
mod tests {
1480-
#![allow(deprecated)] //rand
1481-
14821467
use prelude::v1::*;
14831468
use io::prelude::*;
14841469

14851470
use env;
14861471
use fs::{self, File, OpenOptions};
14871472
use io::{ErrorKind, SeekFrom};
1488-
use path::PathBuf;
1489-
use path::Path as Path2;
1473+
use path::{Path, PathBuf};
14901474
use rand::{self, StdRng, Rng};
14911475
use str;
14921476

1477+
#[cfg(windows)]
1478+
use os::windows::fs::{symlink_dir, symlink_file, symlink_junction};
1479+
#[cfg(unix)]
1480+
use os::unix::fs::symlink as symlink_dir;
1481+
#[cfg(unix)]
1482+
use os::unix::fs::symlink as symlink_file;
1483+
#[cfg(unix)]
1484+
use os::unix::fs::symlink as symlink_junction;
1485+
14931486
macro_rules! check { ($e:expr) => (
14941487
match $e {
14951488
Ok(t) => t,
@@ -1513,7 +1506,7 @@ mod tests {
15131506
p.join(path)
15141507
}
15151508

1516-
fn path<'a>(&'a self) -> &'a Path2 {
1509+
fn path<'a>(&'a self) -> &'a Path {
15171510
let TempDir(ref p) = *self;
15181511
p
15191512
}
@@ -1536,6 +1529,24 @@ mod tests {
15361529
TempDir(ret)
15371530
}
15381531

1532+
// Several test fail on windows if the user does not have permission to create symlinks (the
1533+
// `SeCreateSymbolicLinkPrivilege`). Instead of disabling these test on Windows, use this
1534+
// function to test whether we have permission, and return otherwise. This way, we still don't
1535+
// run these tests most of the time, but at least we do if the user has the right permissions.
1536+
pub fn got_symlink_permission(tmpdir: &TempDir) -> bool {
1537+
let link = tmpdir.join("some_hopefully_unique_link_name");
1538+
1539+
match symlink_file(r"nonexisting_target", link) {
1540+
Ok(_) => true,
1541+
Err(ref err) =>
1542+
if err.to_string().contains("A required privilege is not held by the client.") {
1543+
false
1544+
} else {
1545+
true
1546+
}
1547+
}
1548+
}
1549+
15391550
#[test]
15401551
fn file_test_io_smoke_test() {
15411552
let message = "it's alright. have a good time";
@@ -1566,8 +1577,9 @@ mod tests {
15661577
if cfg!(unix) {
15671578
error!(result, "o such file or directory");
15681579
}
1569-
// error!(result, "couldn't open path as file");
1570-
// error!(result, format!("path={}; mode=open; access=read", filename.display()));
1580+
if cfg!(windows) {
1581+
error!(result, "The system cannot find the file specified");
1582+
}
15711583
}
15721584

15731585
#[test]
@@ -1580,8 +1592,9 @@ mod tests {
15801592
if cfg!(unix) {
15811593
error!(result, "o such file or directory");
15821594
}
1583-
// error!(result, "couldn't unlink path");
1584-
// error!(result, format!("path={}", filename.display()));
1595+
if cfg!(windows) {
1596+
error!(result, "The system cannot find the file specified");
1597+
}
15851598
}
15861599

15871600
#[test]
@@ -1787,6 +1800,7 @@ mod tests {
17871800
}
17881801

17891802
#[test]
1803+
#[allow(deprecated)]
17901804
fn file_test_walk_dir() {
17911805
let tmpdir = tmpdir();
17921806
let dir = &tmpdir.join("walk_dir");
@@ -1843,19 +1857,13 @@ mod tests {
18431857
let result = fs::create_dir_all(&file);
18441858

18451859
assert!(result.is_err());
1846-
// error!(result, "couldn't recursively mkdir");
1847-
// error!(result, "couldn't create directory");
1848-
// error!(result, "mode=0700");
1849-
// error!(result, format!("path={}", file.display()));
18501860
}
18511861

18521862
#[test]
18531863
fn recursive_mkdir_slash() {
1854-
check!(fs::create_dir_all(&Path2::new("/")));
1864+
check!(fs::create_dir_all(&Path::new("/")));
18551865
}
18561866

1857-
// FIXME(#12795) depends on lstat to work on windows
1858-
#[cfg(not(windows))]
18591867
#[test]
18601868
fn recursive_rmdir() {
18611869
let tmpdir = tmpdir();
@@ -1867,7 +1875,7 @@ mod tests {
18671875
check!(fs::create_dir_all(&dtt));
18681876
check!(fs::create_dir_all(&d2));
18691877
check!(check!(File::create(&canary)).write(b"foo"));
1870-
check!(fs::soft_link(&d2, &dt.join("d2")));
1878+
check!(symlink_junction(&d2, &dt.join("d2")));
18711879
check!(fs::remove_dir_all(&d1));
18721880

18731881
assert!(!d1.is_dir());
@@ -1876,8 +1884,8 @@ mod tests {
18761884

18771885
#[test]
18781886
fn unicode_path_is_dir() {
1879-
assert!(Path2::new(".").is_dir());
1880-
assert!(!Path2::new("test/stdtest/fs.rs").is_dir());
1887+
assert!(Path::new(".").is_dir());
1888+
assert!(!Path::new("test/stdtest/fs.rs").is_dir());
18811889

18821890
let tmpdir = tmpdir();
18831891

@@ -1895,21 +1903,21 @@ mod tests {
18951903

18961904
#[test]
18971905
fn unicode_path_exists() {
1898-
assert!(Path2::new(".").exists());
1899-
assert!(!Path2::new("test/nonexistent-bogus-path").exists());
1906+
assert!(Path::new(".").exists());
1907+
assert!(!Path::new("test/nonexistent-bogus-path").exists());
19001908

19011909
let tmpdir = tmpdir();
19021910
let unicode = tmpdir.path();
19031911
let unicode = unicode.join(&format!("test-각丁ー再见"));
19041912
check!(fs::create_dir(&unicode));
19051913
assert!(unicode.exists());
1906-
assert!(!Path2::new("test/unicode-bogus-path-각丁ー再见").exists());
1914+
assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
19071915
}
19081916

19091917
#[test]
19101918
fn copy_file_does_not_exist() {
1911-
let from = Path2::new("test/nonexistent-bogus-path");
1912-
let to = Path2::new("test/other-bogus-path");
1919+
let from = Path::new("test/nonexistent-bogus-path");
1920+
let to = Path::new("test/other-bogus-path");
19131921

19141922
match fs::copy(&from, &to) {
19151923
Ok(..) => panic!(),
@@ -1923,7 +1931,7 @@ mod tests {
19231931
#[test]
19241932
fn copy_src_does_not_exist() {
19251933
let tmpdir = tmpdir();
1926-
let from = Path2::new("test/nonexistent-bogus-path");
1934+
let from = Path::new("test/nonexistent-bogus-path");
19271935
let to = tmpdir.join("out.txt");
19281936
check!(check!(File::create(&to)).write(b"hello"));
19291937
assert!(fs::copy(&from, &to).is_err());
@@ -2014,34 +2022,34 @@ mod tests {
20142022
assert_eq!(v, b"carrot".to_vec());
20152023
}
20162024

2017-
#[cfg(not(windows))] // FIXME(#10264) operation not permitted?
20182025
#[test]
20192026
fn symlinks_work() {
20202027
let tmpdir = tmpdir();
2028+
if !got_symlink_permission(&tmpdir) { return };
2029+
20212030
let input = tmpdir.join("in.txt");
20222031
let out = tmpdir.join("out.txt");
20232032

20242033
check!(check!(File::create(&input)).write("foobar".as_bytes()));
2025-
check!(fs::soft_link(&input, &out));
2026-
// if cfg!(not(windows)) {
2027-
// assert_eq!(check!(lstat(&out)).kind, FileType::Symlink);
2028-
// assert_eq!(check!(out.lstat()).kind, FileType::Symlink);
2029-
// }
2034+
check!(symlink_file(&input, &out));
2035+
assert!(check!(out.symlink_metadata()).file_type().is_symlink());
20302036
assert_eq!(check!(fs::metadata(&out)).len(),
20312037
check!(fs::metadata(&input)).len());
20322038
let mut v = Vec::new();
20332039
check!(check!(File::open(&out)).read_to_end(&mut v));
20342040
assert_eq!(v, b"foobar".to_vec());
20352041
}
20362042

2037-
#[cfg(not(windows))] // apparently windows doesn't like symlinks
20382043
#[test]
20392044
fn symlink_noexist() {
2045+
// Symlinks can point to things that don't exist
20402046
let tmpdir = tmpdir();
2041-
// symlinks can point to things that don't exist
2042-
check!(fs::soft_link(&tmpdir.join("foo"), &tmpdir.join("bar")));
2043-
assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))),
2044-
tmpdir.join("foo"));
2047+
if !got_symlink_permission(&tmpdir) { return };
2048+
2049+
// Use a relative path for testing. Symlinks get normalized by Windows, so we may not get
2050+
// the same path back for absolute paths
2051+
check!(symlink_file(&"foo", &tmpdir.join("bar")));
2052+
assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(), "foo");
20452053
}
20462054

20472055
#[test]
@@ -2312,9 +2320,10 @@ mod tests {
23122320
}
23132321

23142322
#[test]
2315-
#[cfg(not(windows))]
23162323
fn realpath_works() {
23172324
let tmpdir = tmpdir();
2325+
if !got_symlink_permission(&tmpdir) { return };
2326+
23182327
let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
23192328
let file = tmpdir.join("test");
23202329
let dir = tmpdir.join("test2");
@@ -2323,8 +2332,8 @@ mod tests {
23232332

23242333
File::create(&file).unwrap();
23252334
fs::create_dir(&dir).unwrap();
2326-
fs::soft_link(&file, &link).unwrap();
2327-
fs::soft_link(&dir, &linkdir).unwrap();
2335+
symlink_file(&file, &link).unwrap();
2336+
symlink_dir(&dir, &linkdir).unwrap();
23282337

23292338
assert!(link.symlink_metadata().unwrap().file_type().is_symlink());
23302339

@@ -2336,11 +2345,11 @@ mod tests {
23362345
}
23372346

23382347
#[test]
2339-
#[cfg(not(windows))]
23402348
fn realpath_works_tricky() {
23412349
let tmpdir = tmpdir();
2342-
let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
2350+
if !got_symlink_permission(&tmpdir) { return };
23432351

2352+
let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
23442353
let a = tmpdir.join("a");
23452354
let b = a.join("b");
23462355
let c = b.join("c");
@@ -2351,8 +2360,14 @@ mod tests {
23512360
fs::create_dir_all(&b).unwrap();
23522361
fs::create_dir_all(&d).unwrap();
23532362
File::create(&f).unwrap();
2354-
fs::soft_link("../d/e", &c).unwrap();
2355-
fs::soft_link("../f", &e).unwrap();
2363+
if cfg!(not(windows)) {
2364+
symlink_dir("../d/e", &c).unwrap();
2365+
symlink_file("../f", &e).unwrap();
2366+
}
2367+
if cfg!(windows) {
2368+
symlink_dir(r"..\d\e", &c).unwrap();
2369+
symlink_file(r"..\f", &e).unwrap();
2370+
}
23562371

23572372
assert_eq!(fs::canonicalize(&c).unwrap(), f);
23582373
assert_eq!(fs::canonicalize(&e).unwrap(), f);

src/libstd/sys/unix/fs.rs

+13
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,19 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
510510
Ok(())
511511
}
512512

513+
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
514+
for child in try!(readdir(path)) {
515+
let child = try!(child).path();
516+
let stat = try!(lstat(&*child));
517+
if stat.file_type().is_dir() {
518+
try!(remove_dir_all(&*child));
519+
} else {
520+
try!(unlink(&*child));
521+
}
522+
}
523+
rmdir(path)
524+
}
525+
513526
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
514527
let c_path = try!(cstr(p));
515528
let p = c_path.as_ptr();

0 commit comments

Comments
 (0)