Skip to content

Commit 7f6f458

Browse files
committed
Adress comments
1 parent cdb1df7 commit 7f6f458

File tree

3 files changed

+63
-29
lines changed

3 files changed

+63
-29
lines changed

src/libstd/fs.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -1475,7 +1475,9 @@ mod tests {
14751475
use str;
14761476

14771477
#[cfg(windows)]
1478-
use os::windows::fs::{symlink_dir, symlink_file, symlink_junction};
1478+
use os::windows::fs::{symlink_dir, symlink_file};
1479+
#[cfg(windows)]
1480+
use sys::fs::symlink_junction;
14791481
#[cfg(unix)]
14801482
use os::unix::fs::symlink as symlink_dir;
14811483
#[cfg(unix)]
@@ -1533,6 +1535,7 @@ mod tests {
15331535
// `SeCreateSymbolicLinkPrivilege`). Instead of disabling these test on Windows, use this
15341536
// function to test whether we have permission, and return otherwise. This way, we still don't
15351537
// run these tests most of the time, but at least we do if the user has the right permissions.
1538+
#[cfg(windows)]
15361539
pub fn got_symlink_permission(tmpdir: &TempDir) -> bool {
15371540
let link = tmpdir.join("some_hopefully_unique_link_name");
15381541

@@ -1546,6 +1549,9 @@ mod tests {
15461549
}
15471550
}
15481551
}
1552+
#[cfg(not(windows))]
1553+
#[allow(unused_variables)]
1554+
pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { true }
15491555

15501556
#[test]
15511557
fn file_test_io_smoke_test() {
@@ -2401,4 +2407,30 @@ mod tests {
24012407
let res = fs::read_dir("/path/that/does/not/exist");
24022408
assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound);
24032409
}
2410+
2411+
#[test]
2412+
fn create_dir_all_with_junctions() {
2413+
let tmpdir = tmpdir();
2414+
let target = tmpdir.join("target");
2415+
2416+
let junction = tmpdir.join("junction");
2417+
let b = junction.join("a/b");
2418+
2419+
let link = tmpdir.join("link");
2420+
let d = link.join("c/d");
2421+
2422+
fs::create_dir(&target).unwrap();
2423+
2424+
check!(symlink_junction(&target, &junction));
2425+
check!(fs::create_dir_all(&b));
2426+
// the junction itself is not a directory, but `is_dir()` on a Path follows links
2427+
assert!(junction.is_dir());
2428+
assert!(b.exists());
2429+
2430+
if !got_symlink_permission(&tmpdir) { return };
2431+
check!(symlink_dir(&target, &link));
2432+
check!(fs::create_dir_all(&d));
2433+
assert!(link.is_dir());
2434+
assert!(d.exists());
2435+
}
24042436
}

src/libstd/sys/unix/fs.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -512,12 +512,11 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
512512

513513
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
514514
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));
515+
let child = try!(child);
516+
if try!(child.file_type()).is_dir() {
517+
try!(remove_dir_all(&child.path()));
519518
} else {
520-
try!(unlink(&*child));
519+
try!(unlink(&child.path()));
521520
}
522521
}
523522
rmdir(path)

src/libstd/sys/windows/fs.rs

+26-23
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub struct FileAttr {
3535

3636
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
3737
pub enum FileType {
38-
Dir, File, Symlink, ReparsePoint, MountPoint,
38+
Dir, File, SymlinkFile, SymlinkDir, ReparsePoint, MountPoint,
3939
}
4040

4141
pub struct ReadDir {
@@ -444,23 +444,30 @@ impl FilePermissions {
444444

445445
impl FileType {
446446
fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType {
447-
if attrs & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
448-
match reparse_tag {
449-
c::IO_REPARSE_TAG_SYMLINK => FileType::Symlink,
450-
c::IO_REPARSE_TAG_MOUNT_POINT => FileType::MountPoint,
451-
_ => FileType::ReparsePoint,
452-
}
453-
} else if attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0 {
454-
FileType::Dir
455-
} else {
456-
FileType::File
447+
match (attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0,
448+
attrs & c::FILE_ATTRIBUTE_REPARSE_POINT != 0,
449+
reparse_tag) {
450+
(false, false, _) => FileType::File,
451+
(true, false, _) => FileType::Dir,
452+
(false, true, c::IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkFile,
453+
(true, true, c::IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkDir,
454+
(true, true, c::IO_REPARSE_TAG_MOUNT_POINT) => FileType::MountPoint,
455+
(_, true, _) => FileType::ReparsePoint,
456+
// Note: if a _file_ has a reparse tag of the type IO_REPARSE_TAG_MOUNT_POINT it is
457+
// invalid, as junctions always have to be dirs. We set the filetype to ReparsePoint
458+
// to indicate it is something symlink-like, but not something you can follow.
457459
}
458460
}
459461

460462
pub fn is_dir(&self) -> bool { *self == FileType::Dir }
461463
pub fn is_file(&self) -> bool { *self == FileType::File }
462464
pub fn is_symlink(&self) -> bool {
463-
*self == FileType::Symlink || *self == FileType::MountPoint
465+
*self == FileType::SymlinkFile ||
466+
*self == FileType::SymlinkDir ||
467+
*self == FileType::MountPoint
468+
}
469+
pub fn is_symlink_dir(&self) -> bool {
470+
*self == FileType::SymlinkDir || *self == FileType::MountPoint
464471
}
465472
}
466473

@@ -519,18 +526,14 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
519526

520527
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
521528
for child in try!(readdir(path)) {
522-
let child = try!(child).path();
523-
let stat = try!(lstat(&*child));
524-
if stat.data.dwFileAttributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 {
525-
if stat.data.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
526-
// remove junctions and directory symlinks with rmdir
527-
try!(rmdir(&*child));
528-
} else {
529-
try!(remove_dir_all(&*child));
530-
}
529+
let child = try!(child);
530+
let child_type = try!(child.file_type());
531+
if child_type.is_dir() {
532+
try!(remove_dir_all(&child.path()));
533+
} else if child_type.is_symlink_dir() {
534+
try!(rmdir(&child.path()));
531535
} else {
532-
// remove files and file symlinks
533-
try!(unlink(&*child));
536+
try!(unlink(&child.path()));
534537
}
535538
}
536539
rmdir(path)

0 commit comments

Comments
 (0)