-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Made remove_dir_all
work as documented when directory is a symlink
#29412
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
remove_dir_all
fixes recommended in pull request
* Renamed internal method `*_unchecked` -> `*_recursive` * Better windows support (untested)
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1071,21 +1071,41 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { | |
fn _remove_dir_all(path: &Path) -> io::Result<()> { | ||
let filetype = try!(symlink_metadata(path)).file_type(); | ||
if filetype.is_symlink() { | ||
remove_file(path) | ||
if cfg!(windows) { | ||
// On Windows symlinks to files and directories removed differently | ||
// we should remove only directories here and have error on file | ||
remove_dir(path) | ||
} else { | ||
// On unix symlinks are always files | ||
remove_file(path) | ||
} | ||
} else { | ||
_remove_dir_all_unchecked(path) | ||
remove_dir_all_recursive(path) | ||
} | ||
} | ||
fn _remove_dir_all_unchecked(path: &Path) -> io::Result<()> { | ||
fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { | ||
for child in try!(read_dir(path)) { | ||
let child = try!(child); | ||
let child_path = child.path(); | ||
let mut child_type = try!(child.file_type()); | ||
let child_type = try!(child.file_type()); | ||
if child_type.is_dir() { | ||
try!(_remove_dir_all_unchecked(&*child_path)); | ||
try!(remove_dir_all_recursive(&*child_path)); | ||
} else { | ||
// The FileType::is_dir() is false for symlinks too | ||
try!(remove_file(&*child_path)); | ||
if cfg!(windows) { | ||
if child_type.is_symlink() { | ||
let target_type = try!(metadata(&*child_path)).file_type(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tested this out a bit, and oddly enough I'm not sure we can use this function to determine this. Using
I found that I could create a symlink to a file with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's because Windows doesn't check the target of symbolic links when you create them. You still created a directory symbolic link. It just happens to be pointing at a file. |
||
if target_type.is_dir() { | ||
try!(remove_dir(&*child_path)); | ||
} else { | ||
try!(remove_file(&*child_path)); | ||
} | ||
} else { | ||
try!(remove_file(&*child_path)); | ||
} | ||
} else { | ||
// The FileType::is_dir() is false for symlinks too | ||
try!(remove_file(&*child_path)); | ||
} | ||
} | ||
} | ||
remove_dir(path) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be good to extract into a helper function to be shared with below, something like: