Skip to content

Commit 7c12644

Browse files
seritoolsmbilker
authored andcommitted
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 b0a801e commit 7c12644

File tree

4 files changed

+59
-27
lines changed

4 files changed

+59
-27
lines changed

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,18 @@ compat_fn_with_fallback! {
563563
) -> COMPARESTRING_RESULT {
564564
rtabort!("unavailable")
565565
}
566+
567+
// >= Vista / Server 2008 (XP / Server 2003 when linking a supported FileExtd.lib)
568+
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
569+
pub fn GetFileInformationByHandleEx(
570+
hFile: HANDLE,
571+
fileInfoClass: FILE_INFO_BY_HANDLE_CLASS,
572+
lpFileInformation: *mut ::core::ffi::c_void,
573+
dwBufferSize: u32
574+
) -> BOOL {
575+
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD);
576+
FALSE
577+
}
566578
}
567579

568580
compat_fn_optional! {
@@ -579,6 +591,22 @@ compat_fn_optional! {
579591
compat_fn_with_fallback! {
580592
pub static NTDLL: &CStr = ansi_str!("ntdll");
581593

594+
pub fn NtCreateFile(
595+
filehandle: *mut HANDLE,
596+
desiredaccess: FILE_ACCESS_RIGHTS,
597+
objectattributes: *const OBJECT_ATTRIBUTES,
598+
iostatusblock: *mut IO_STATUS_BLOCK,
599+
allocationsize: *const i64,
600+
fileattributes: FILE_FLAGS_AND_ATTRIBUTES,
601+
shareaccess: FILE_SHARE_MODE,
602+
createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
603+
createoptions: NTCREATEFILE_CREATE_OPTIONS,
604+
eabuffer: *const ::core::ffi::c_void,
605+
ealength: u32,
606+
) -> NTSTATUS {
607+
rtabort!("unavailable")
608+
}
609+
582610
pub fn NtCreateKeyedEvent(
583611
KeyedEventHandle: LPHANDLE,
584612
DesiredAccess: ACCESS_MASK,

library/std/src/sys/windows/c/windows_sys.lst

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ Windows.Wdk.Storage.FileSystem.FILE_SUPERSEDE
2828
Windows.Wdk.Storage.FileSystem.FILE_SYNCHRONOUS_IO_ALERT
2929
Windows.Wdk.Storage.FileSystem.FILE_SYNCHRONOUS_IO_NONALERT
3030
Windows.Wdk.Storage.FileSystem.FILE_WRITE_THROUGH
31-
Windows.Wdk.Storage.FileSystem.NtCreateFile
3231
Windows.Wdk.Storage.FileSystem.NTCREATEFILE_CREATE_DISPOSITION
3332
Windows.Wdk.Storage.FileSystem.NTCREATEFILE_CREATE_OPTIONS
3433
Windows.Wdk.Storage.FileSystem.NtReadFile
@@ -2325,7 +2324,6 @@ Windows.Win32.Storage.FileSystem.FindNextFileW
23252324
Windows.Win32.Storage.FileSystem.FlushFileBuffers
23262325
Windows.Win32.Storage.FileSystem.GetFileAttributesW
23272326
Windows.Win32.Storage.FileSystem.GetFileInformationByHandle
2328-
Windows.Win32.Storage.FileSystem.GetFileInformationByHandleEx
23292327
Windows.Win32.Storage.FileSystem.GetFileType
23302328
Windows.Win32.Storage.FileSystem.GETFINALPATHNAMEBYHANDLE_FLAGS
23312329
Windows.Win32.Storage.FileSystem.GetFullPathNameW

library/std/src/sys/windows/c/windows_sys.rs

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,6 @@ extern "system" {
194194
) -> BOOL;
195195
}
196196
#[link(name = "kernel32")]
197-
extern "system" {
198-
pub fn GetFileInformationByHandleEx(
199-
hfile: HANDLE,
200-
fileinformationclass: FILE_INFO_BY_HANDLE_CLASS,
201-
lpfileinformation: *mut ::core::ffi::c_void,
202-
dwbuffersize: u32,
203-
) -> BOOL;
204-
}
205-
#[link(name = "kernel32")]
206197
extern "system" {
207198
pub fn GetFileType(hfile: HANDLE) -> FILE_TYPE;
208199
}
@@ -445,22 +436,6 @@ extern "system" {
445436
) -> BOOL;
446437
}
447438
#[link(name = "ntdll")]
448-
extern "system" {
449-
pub fn NtCreateFile(
450-
filehandle: *mut HANDLE,
451-
desiredaccess: FILE_ACCESS_RIGHTS,
452-
objectattributes: *const OBJECT_ATTRIBUTES,
453-
iostatusblock: *mut IO_STATUS_BLOCK,
454-
allocationsize: *const i64,
455-
fileattributes: FILE_FLAGS_AND_ATTRIBUTES,
456-
shareaccess: FILE_SHARE_MODE,
457-
createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
458-
createoptions: NTCREATEFILE_CREATE_OPTIONS,
459-
eabuffer: *const ::core::ffi::c_void,
460-
ealength: u32,
461-
) -> NTSTATUS;
462-
}
463-
#[link(name = "ntdll")]
464439
extern "system" {
465440
pub fn NtReadFile(
466441
filehandle: HANDLE,

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,22 @@ fn open_link(path: &Path, access_mode: u32) -> io::Result<File> {
11611161
}
11621162

11631163
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
1164+
// if the modern file/directory APIs are not available, we'll fall back to the old (unsafe, see
1165+
// https://github.com/rust-lang/rust/pull/93112) directory removal implementation
1166+
if !c::NtCreateFile::available()
1167+
|| !c::GetFileInformationByHandleEx::available()
1168+
|| !c::SetFileInformationByHandle::available()
1169+
{
1170+
let filetype = lstat(path)?.file_type();
1171+
if filetype.is_symlink() {
1172+
// On Windows symlinks to files and directories are removed differently.
1173+
// rmdir only deletes dir symlinks and junctions, not file symlinks.
1174+
return rmdir(path);
1175+
} else {
1176+
return remove_dir_all_recursive_old(path);
1177+
}
1178+
}
1179+
11641180
let file = open_link(path, c::DELETE | c::FILE_LIST_DIRECTORY)?;
11651181

11661182
// Test if the file is not a directory or a symlink to a directory.
@@ -1260,6 +1276,21 @@ fn remove_dir_all_iterative(f: &File, delete: fn(&File) -> io::Result<()>) -> io
12601276
Ok(())
12611277
}
12621278

1279+
fn remove_dir_all_recursive_old(path: &Path) -> io::Result<()> {
1280+
for child in readdir(path)? {
1281+
let child = child?;
1282+
let child_type = child.file_type()?;
1283+
if child_type.is_dir() {
1284+
remove_dir_all_recursive_old(&child.path())?;
1285+
} else if child_type.is_symlink_dir() {
1286+
rmdir(&child.path())?;
1287+
} else {
1288+
unlink(&child.path())?;
1289+
}
1290+
}
1291+
rmdir(path)
1292+
}
1293+
12631294
pub fn readlink(path: &Path) -> io::Result<PathBuf> {
12641295
// Open the link with no access mode, instead of generic read.
12651296
// By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so

0 commit comments

Comments
 (0)