Skip to content

Commit a33e1a9

Browse files
committed
Fall back to old impl for remove_dir_all
The recursive directory removal implementation falls back to the old one if the necessary APIs are not available (`NtCreateFile`, `GetFileInformationByHandleEx`, `SetFileInformationByHandle`). The APIs are available on Vista/Server 2008. See notes on `fileextd.lib` above to extend the support to Windows XP/Server 2003. **This might cause security issues**, see rust-lang#93112
1 parent d878ab6 commit a33e1a9

3 files changed

Lines changed: 61 additions & 2 deletions

File tree

library/std/src/sys/fs/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ pub fn remove_dir(path: &Path) -> io::Result<()> {
8282

8383
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
8484
// FIXME: use with_native_path on all platforms
85-
#[cfg(not(windows))]
85+
#[cfg(any(not(windows), target_family = "rust9x"))]
8686
return imp::remove_dir_all(path);
87-
#[cfg(windows)]
87+
#[cfg(all(windows, not(target_family = "rust9x")))]
8888
with_native_path(path, &imp::remove_dir_all)
8989
}
9090

library/std/src/sys/fs/windows.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,6 +1427,46 @@ pub fn rmdir(p: &WCStr) -> io::Result<()> {
14271427
Ok(())
14281428
}
14291429

1430+
#[cfg(target_family = "rust9x")]
1431+
pub fn remove_dir_all(p: &Path) -> io::Result<()> {
1432+
use crate::sys::path::with_native_path;
1433+
1434+
with_native_path(p, &|path| {
1435+
// if the modern file/directory APIs are not available, we'll fall back to the old (unsafe, see
1436+
// https://github.com/rust-lang/rust/pull/93112) directory removal implementation
1437+
if !(c::NtOpenFile::available().is_some()
1438+
&& c::GetFileInformationByHandleEx::available().is_some()
1439+
&& c::SetFileInformationByHandle::available().is_some())
1440+
{
1441+
let filetype = lstat(path)?.file_type();
1442+
if filetype.is_symlink() {
1443+
// On Windows symlinks to files and directories are removed differently.
1444+
// rmdir only deletes dir symlinks and junctions, not file symlinks.
1445+
return rmdir(path);
1446+
} else {
1447+
return remove_dir_all::remove_dir_all_recursive_old(p);
1448+
}
1449+
}
1450+
1451+
// Open a file or directory without following symlinks.
1452+
let mut opts = OpenOptions::new();
1453+
opts.access_mode(c::FILE_LIST_DIRECTORY);
1454+
// `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories.
1455+
// `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target.
1456+
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT);
1457+
let file = File::open_native(path, &opts)?;
1458+
1459+
// Test if the file is not a directory or a symlink to a directory.
1460+
if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 {
1461+
return Err(io::Error::from_raw_os_error(c::ERROR_DIRECTORY as _));
1462+
}
1463+
1464+
// Remove the directory and all its contents.
1465+
remove_dir_all_iterative(file).io_result()
1466+
})
1467+
}
1468+
1469+
#[cfg(not(target_family = "rust9x"))]
14301470
pub fn remove_dir_all(path: &WCStr) -> io::Result<()> {
14311471
// Open a file or directory without following symlinks.
14321472
let mut opts = OpenOptions::new();

library/std/src/sys/fs/windows/remove_dir_all.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,22 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> {
204204
}
205205
Ok(())
206206
}
207+
208+
#[cfg(target_family = "rust9x")]
209+
pub fn remove_dir_all_recursive_old(path: &crate::path::Path) -> crate::io::Result<()> {
210+
use super::*;
211+
use crate::sys::path::with_native_path;
212+
213+
for child in readdir(path)? {
214+
let child = child?;
215+
let child_type = child.file_type()?;
216+
if child_type.is_dir() {
217+
remove_dir_all_recursive_old(&child.path())?;
218+
} else if child_type.is_symlink_dir() {
219+
with_native_path(&child.path(), &rmdir)?;
220+
} else {
221+
with_native_path(&child.path(), &unlink)?;
222+
}
223+
}
224+
with_native_path(path, &rmdir)
225+
}

0 commit comments

Comments
 (0)