Adress comments
This commit is contained in:
parent
cdb1df749e
commit
7f6f458194
3 changed files with 63 additions and 29 deletions
|
@ -1475,7 +1475,9 @@ mod tests {
|
||||||
use str;
|
use str;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[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)]
|
#[cfg(unix)]
|
||||||
use os::unix::fs::symlink as symlink_dir;
|
use os::unix::fs::symlink as symlink_dir;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@ -1533,6 +1535,7 @@ mod tests {
|
||||||
// `SeCreateSymbolicLinkPrivilege`). Instead of disabling these test on Windows, use this
|
// `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
|
// 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.
|
// 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 {
|
pub fn got_symlink_permission(tmpdir: &TempDir) -> bool {
|
||||||
let link = tmpdir.join("some_hopefully_unique_link_name");
|
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]
|
#[test]
|
||||||
fn file_test_io_smoke_test() {
|
fn file_test_io_smoke_test() {
|
||||||
|
@ -2401,4 +2407,30 @@ mod tests {
|
||||||
let res = fs::read_dir("/path/that/does/not/exist");
|
let res = fs::read_dir("/path/that/does/not/exist");
|
||||||
assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound);
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -512,12 +512,11 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
|
||||||
|
|
||||||
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
|
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
|
||||||
for child in try!(readdir(path)) {
|
for child in try!(readdir(path)) {
|
||||||
let child = try!(child).path();
|
let child = try!(child);
|
||||||
let stat = try!(lstat(&*child));
|
if try!(child.file_type()).is_dir() {
|
||||||
if stat.file_type().is_dir() {
|
try!(remove_dir_all(&child.path()));
|
||||||
try!(remove_dir_all(&*child));
|
|
||||||
} else {
|
} else {
|
||||||
try!(unlink(&*child));
|
try!(unlink(&child.path()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rmdir(path)
|
rmdir(path)
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub struct FileAttr {
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum FileType {
|
pub enum FileType {
|
||||||
Dir, File, Symlink, ReparsePoint, MountPoint,
|
Dir, File, SymlinkFile, SymlinkDir, ReparsePoint, MountPoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReadDir {
|
pub struct ReadDir {
|
||||||
|
@ -444,23 +444,30 @@ impl FilePermissions {
|
||||||
|
|
||||||
impl FileType {
|
impl FileType {
|
||||||
fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType {
|
fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType {
|
||||||
if attrs & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
|
match (attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0,
|
||||||
match reparse_tag {
|
attrs & c::FILE_ATTRIBUTE_REPARSE_POINT != 0,
|
||||||
c::IO_REPARSE_TAG_SYMLINK => FileType::Symlink,
|
reparse_tag) {
|
||||||
c::IO_REPARSE_TAG_MOUNT_POINT => FileType::MountPoint,
|
(false, false, _) => FileType::File,
|
||||||
_ => FileType::ReparsePoint,
|
(true, false, _) => FileType::Dir,
|
||||||
}
|
(false, true, c::IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkFile,
|
||||||
} else if attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0 {
|
(true, true, c::IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkDir,
|
||||||
FileType::Dir
|
(true, true, c::IO_REPARSE_TAG_MOUNT_POINT) => FileType::MountPoint,
|
||||||
} else {
|
(_, true, _) => FileType::ReparsePoint,
|
||||||
FileType::File
|
// 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_dir(&self) -> bool { *self == FileType::Dir }
|
||||||
pub fn is_file(&self) -> bool { *self == FileType::File }
|
pub fn is_file(&self) -> bool { *self == FileType::File }
|
||||||
pub fn is_symlink(&self) -> bool {
|
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<()> {
|
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
|
||||||
for child in try!(readdir(path)) {
|
for child in try!(readdir(path)) {
|
||||||
let child = try!(child).path();
|
let child = try!(child);
|
||||||
let stat = try!(lstat(&*child));
|
let child_type = try!(child.file_type());
|
||||||
if stat.data.dwFileAttributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 {
|
if child_type.is_dir() {
|
||||||
if stat.data.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
|
try!(remove_dir_all(&child.path()));
|
||||||
// remove junctions and directory symlinks with rmdir
|
} else if child_type.is_symlink_dir() {
|
||||||
try!(rmdir(&*child));
|
try!(rmdir(&child.path()));
|
||||||
} else {
|
} else {
|
||||||
try!(remove_dir_all(&*child));
|
try!(unlink(&child.path()));
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// remove files and file symlinks
|
|
||||||
try!(unlink(&*child));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rmdir(path)
|
rmdir(path)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue