-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix a race condition in remove_dir_all.
Port the fix from rust-lang/rust#93112 to cap-std.
- Loading branch information
1 parent
0d887dd
commit bef2e70
Showing
14 changed files
with
241 additions
and
92 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,74 +1,30 @@ | ||
use crate::fs::{ | ||
read_dir_unchecked, remove_dir, remove_file, remove_open_dir, stat, FollowSymlinks, | ||
}; | ||
use super::get_path::get_path; | ||
use crate::fs::{open_dir, open_dir_nofollow, remove_dir, stat, FollowSymlinks}; | ||
#[cfg(windows_file_type_ext)] | ||
use std::os::windows::fs::FileTypeExt; | ||
use std::path::{Component, Path}; | ||
use std::path::Path; | ||
use std::{fs, io}; | ||
|
||
pub(crate) fn remove_dir_all_impl(start: &fs::File, path: &Path) -> io::Result<()> { | ||
// Code derived from `remove_dir_all` in Rust's | ||
// library/std/src/sys/windows/fs.rs at revision | ||
// 108e90ca78f052c0c1c49c42a22c85620be19712. | ||
let filetype = stat(start, path, FollowSymlinks::No)?.file_type(); | ||
if filetype.is_symlink() { | ||
// On Windows symlinks to files and directories are removed | ||
// differently. `remove_dir` only deletes dir symlinks and junctions, | ||
// not file symlinks. | ||
// Open the directory, following symlinks, to make sure it is a directory. | ||
let file = open_dir(start, path)?; | ||
// Test whether the path is a symlink. | ||
let md = stat(start, path, FollowSymlinks::No)?; | ||
drop(file); | ||
if md.is_symlink() { | ||
// If so, just remove the link. | ||
remove_dir(start, path) | ||
} else { | ||
remove_dir_all_recursive(start, path)?; | ||
remove_dir(start, path) | ||
// Otherwise, remove the tree. | ||
let dir = open_dir_nofollow(start, path)?; | ||
remove_open_dir_all_impl(dir) | ||
} | ||
} | ||
|
||
pub(crate) fn remove_open_dir_all_impl(dir: fs::File) -> io::Result<()> { | ||
remove_dir_all_recursive(&dir, Component::CurDir.as_ref())?; | ||
remove_open_dir(dir) | ||
} | ||
|
||
#[cfg(windows_file_type_ext)] | ||
fn remove_dir_all_recursive(start: &fs::File, path: &Path) -> io::Result<()> { | ||
// Code derived from `remove_dir_all_recursive` in Rust's | ||
// library/std/src/sys/windows/fs.rs at revision | ||
// 108e90ca78f052c0c1c49c42a22c85620be19712. | ||
for child in read_dir_unchecked(start, path)? { | ||
let child = child?; | ||
let child_type = child.file_type()?; | ||
if child_type.is_dir() { | ||
let path = path.join(child.file_name()); | ||
remove_dir_all_recursive(start, &path)?; | ||
remove_dir(start, &path)?; | ||
} else if child_type.is_symlink_dir() { | ||
remove_dir(start, &path.join(child.file_name()))?; | ||
} else { | ||
remove_file(start, &path.join(child.file_name()))?; | ||
} | ||
} | ||
Ok(()) | ||
} | ||
|
||
#[cfg(not(windows_file_type_ext))] | ||
fn remove_dir_all_recursive(start: &fs::File, path: &Path) -> io::Result<()> { | ||
for child in read_dir_unchecked(start, path)? { | ||
let child = child?; | ||
let child_type = child.file_type()?; | ||
if child_type.is_dir() { | ||
let path = path.join(child.file_name()); | ||
remove_dir_all_recursive(start, &path)?; | ||
remove_dir(start, &path)?; | ||
} else { | ||
match remove_dir(start, &path.join(child.file_name())) { | ||
Ok(()) => (), | ||
Err(e) => { | ||
if e.raw_os_error() == Some(winapi::shared::winerror::ERROR_DIRECTORY as i32) { | ||
remove_file(start, &path.join(child.file_name()))?; | ||
} else { | ||
return Err(e); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
Ok(()) | ||
// Close the directory so that we can delete it. This is racy; see the | ||
// comments in `remove_open_dir_impl` for details. | ||
let path = get_path(&dir)?; | ||
drop(dir); | ||
fs::remove_dir_all(&path) | ||
} |
Oops, something went wrong.