about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPaul Dicker <pitdicker@gmail.com>2016-02-03 18:23:33 +0100
committerPaul Dicker <pitdicker@gmail.com>2016-02-03 18:23:33 +0100
commit7f6f4581946f9ae8e2c23cd7e09eb4f03d6c3cb1 (patch)
tree84f92ea71bd466e128528d52e61fbc3a352b97a7 /src
parentcdb1df749e848c2d0e0a87fa6140aa7c74220b80 (diff)
downloadrust-7f6f4581946f9ae8e2c23cd7e09eb4f03d6c3cb1.tar.gz
rust-7f6f4581946f9ae8e2c23cd7e09eb4f03d6c3cb1.zip
Adress comments
Diffstat (limited to 'src')
-rw-r--r--src/libstd/fs.rs34
-rw-r--r--src/libstd/sys/unix/fs.rs9
-rw-r--r--src/libstd/sys/windows/fs.rs49
3 files changed, 63 insertions, 29 deletions
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index 63980f39c48..23672d0cc13 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -1475,7 +1475,9 @@ mod tests {
     use str;
 
     #[cfg(windows)]
-    use os::windows::fs::{symlink_dir, symlink_file, symlink_junction};
+    use os::windows::fs::{symlink_dir, symlink_file};
+    #[cfg(windows)]
+    use sys::fs::symlink_junction;
     #[cfg(unix)]
     use os::unix::fs::symlink as symlink_dir;
     #[cfg(unix)]
@@ -1533,6 +1535,7 @@ mod tests {
     // `SeCreateSymbolicLinkPrivilege`). Instead of disabling these test on Windows, use this
     // function to test whether we have permission, and return otherwise. This way, we still don't
     // run these tests most of the time, but at least we do if the user has the right permissions.
+    #[cfg(windows)]
     pub fn got_symlink_permission(tmpdir: &TempDir) -> bool {
         let link = tmpdir.join("some_hopefully_unique_link_name");
 
@@ -1546,6 +1549,9 @@ mod tests {
                 }
         }
     }
+    #[cfg(not(windows))]
+    #[allow(unused_variables)]
+    pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { true }
 
     #[test]
     fn file_test_io_smoke_test() {
@@ -2401,4 +2407,30 @@ mod tests {
         let res = fs::read_dir("/path/that/does/not/exist");
         assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound);
     }
+
+    #[test]
+    fn create_dir_all_with_junctions() {
+        let tmpdir = tmpdir();
+        let target = tmpdir.join("target");
+
+        let junction = tmpdir.join("junction");
+        let b = junction.join("a/b");
+
+        let link = tmpdir.join("link");
+        let d = link.join("c/d");
+
+        fs::create_dir(&target).unwrap();
+
+        check!(symlink_junction(&target, &junction));
+        check!(fs::create_dir_all(&b));
+        // the junction itself is not a directory, but `is_dir()` on a Path follows links
+        assert!(junction.is_dir());
+        assert!(b.exists());
+
+        if !got_symlink_permission(&tmpdir) { return };
+        check!(symlink_dir(&target, &link));
+        check!(fs::create_dir_all(&d));
+        assert!(link.is_dir());
+        assert!(d.exists());
+    }
 }
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index f7989d35710..a2e6f467b17 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -512,12 +512,11 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
 
 pub fn remove_dir_all(path: &Path) -> io::Result<()> {
     for child in try!(readdir(path)) {
-        let child = try!(child).path();
-        let stat = try!(lstat(&*child));
-        if stat.file_type().is_dir() {
-            try!(remove_dir_all(&*child));
+        let child = try!(child);
+        if try!(child.file_type()).is_dir() {
+            try!(remove_dir_all(&child.path()));
         } else {
-            try!(unlink(&*child));
+            try!(unlink(&child.path()));
         }
     }
     rmdir(path)
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 17d9bf329df..7ace48fe561 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -35,7 +35,7 @@ pub struct FileAttr {
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub enum FileType {
-    Dir, File, Symlink, ReparsePoint, MountPoint,
+    Dir, File, SymlinkFile, SymlinkDir, ReparsePoint, MountPoint,
 }
 
 pub struct ReadDir {
@@ -444,23 +444,30 @@ impl FilePermissions {
 
 impl FileType {
     fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType {
-        if attrs & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
-            match reparse_tag {
-                c::IO_REPARSE_TAG_SYMLINK => FileType::Symlink,
-                c::IO_REPARSE_TAG_MOUNT_POINT => FileType::MountPoint,
-                _ => FileType::ReparsePoint,
-            }
-        } else if attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0 {
-            FileType::Dir
-        } else {
-            FileType::File
+        match (attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0,
+               attrs & c::FILE_ATTRIBUTE_REPARSE_POINT != 0,
+               reparse_tag) {
+            (false, false, _) => FileType::File,
+            (true, false, _) => FileType::Dir,
+            (false, true, c::IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkFile,
+            (true, true, c::IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkDir,
+            (true, true, c::IO_REPARSE_TAG_MOUNT_POINT) => FileType::MountPoint,
+            (_, true, _) => FileType::ReparsePoint,
+            // Note: if a _file_ has a reparse tag of the type IO_REPARSE_TAG_MOUNT_POINT it is
+            // invalid, as junctions always have to be dirs. We set the filetype to ReparsePoint
+            // to indicate it is something symlink-like, but not something you can follow.
         }
     }
 
     pub fn is_dir(&self) -> bool { *self == FileType::Dir }
     pub fn is_file(&self) -> bool { *self == FileType::File }
     pub fn is_symlink(&self) -> bool {
-        *self == FileType::Symlink || *self == FileType::MountPoint
+        *self == FileType::SymlinkFile ||
+        *self == FileType::SymlinkDir ||
+        *self == FileType::MountPoint
+    }
+    pub fn is_symlink_dir(&self) -> bool {
+        *self == FileType::SymlinkDir || *self == FileType::MountPoint
     }
 }
 
@@ -519,18 +526,14 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
 
 pub fn remove_dir_all(path: &Path) -> io::Result<()> {
     for child in try!(readdir(path)) {
-        let child = try!(child).path();
-        let stat = try!(lstat(&*child));
-        if stat.data.dwFileAttributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 {
-            if stat.data.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
-                // remove junctions and directory symlinks with rmdir
-                try!(rmdir(&*child));
-            } else {
-                try!(remove_dir_all(&*child));
-            }
+        let child = try!(child);
+        let child_type = try!(child.file_type());
+        if child_type.is_dir() {
+            try!(remove_dir_all(&child.path()));
+        } else if child_type.is_symlink_dir() {
+            try!(rmdir(&child.path()));
         } else {
-            // remove files and file symlinks
-            try!(unlink(&*child));
+            try!(unlink(&child.path()));
         }
     }
     rmdir(path)