diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index cb0e2614114e8..a7adcc96167ba 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -13,6 +13,8 @@ use core::{mem, ptr}; mod windows_sys; pub use windows_sys::*; +#[cfg(target_vendor = "rust9x")] +pub(crate) mod fileextd; #[cfg(target_vendor = "rust9x")] pub(crate) mod wspiapi; @@ -436,29 +438,6 @@ compat_fn_with_fallback! { TRUE } } - - // >= Vista / Server 2008 (XP / Server 2003 when linking a supported FileExtd.lib) - // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle - pub fn SetFileInformationByHandle( - hfile: HANDLE, - fileinformationclass: FILE_INFO_BY_HANDLE_CLASS, - lpfileinformation: *const ::core::ffi::c_void, - dwbuffersize: u32, - ) -> BOOL { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); }; - FALSE - } - // >= Vista / Server 2008 (XP / Server 2003 when linking a supported FileExtd.lib) - // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex - pub fn GetFileInformationByHandleEx( - hfile: HANDLE, - fileinformationclass: FILE_INFO_BY_HANDLE_CLASS, - lpfileinformation: *mut ::core::ffi::c_void, - dwbuffersize: u32, - ) -> BOOL { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); }; - FALSE - } } #[cfg(target_vendor = "rust9x")] @@ -704,3 +683,51 @@ compat_fn_with_fallback! { FALSE } } + +#[cfg(target_vendor = "rust9x")] +pub(crate) use fileextd::{ + get_file_information_by_handle_ex as GetFileInformationByHandleEx, + set_file_information_by_handle as SetFileInformationByHandle, +}; +#[cfg(target_vendor = "rust9x")] +compat_fn_with_fallback! { + pub static NTDLL: &CStr = c"ntdll" => { load: true, unicows: false }; + // all NT only + fn NtQueryDirectoryFile( + filehandle: HANDLE, + event: HANDLE, + apcroutine: PIO_APC_ROUTINE, + apccontext: *const core::ffi::c_void, + iostatusblock: *mut IO_STATUS_BLOCK, + fileinformation: *mut core::ffi::c_void, + length: u32, + fileinformationclass: FILE_INFORMATION_CLASS, + returnsingleentry: BOOLEAN, + filename: *const UNICODE_STRING, + restartscan: BOOLEAN + ) -> NTSTATUS { + rtabort!("unimplemented") + } + fn NtQueryInformationFile(filehandle: HANDLE, + iostatusblock: *mut IO_STATUS_BLOCK, + fileinformation: *mut core::ffi::c_void, + length: u32, + fileinformationclass: FILE_INFORMATION_CLASS + ) -> NTSTATUS { + rtabort!("unimplemented") + } + fn NtSetInformationFile(filehandle: HANDLE, + iostatusblock: *mut IO_STATUS_BLOCK, + fileinformation: *const core::ffi::c_void, + length: u32, + fileinformationclass: FILE_INFORMATION_CLASS + ) -> NTSTATUS { + rtabort!("unimplemented") + } + fn NtWaitForSingleObject(handle: HANDLE, + alertable: BOOLEAN, + timeout: *mut i64 + ) -> NTSTATUS { + rtabort!("unimplemented") + } +} diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index fc751bbe9ac05..c0f476c499bf1 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -9,6 +9,7 @@ Windows.Wdk.Storage.FileSystem.FILE_CREATE_TREE_CONNECTION Windows.Wdk.Storage.FileSystem.FILE_DELETE_ON_CLOSE Windows.Wdk.Storage.FileSystem.FILE_DIRECTORY_FILE Windows.Wdk.Storage.FileSystem.FILE_DISALLOW_EXCLUSIVE +Windows.Wdk.Storage.FileSystem.FILE_INFORMATION_CLASS Windows.Wdk.Storage.FileSystem.FILE_NO_COMPRESSION Windows.Wdk.Storage.FileSystem.FILE_NO_EA_KNOWLEDGE Windows.Wdk.Storage.FileSystem.FILE_NO_INTERMEDIATE_BUFFERING @@ -31,13 +32,25 @@ Windows.Wdk.Storage.FileSystem.FILE_SUPERSEDE Windows.Wdk.Storage.FileSystem.FILE_SYNCHRONOUS_IO_ALERT Windows.Wdk.Storage.FileSystem.FILE_SYNCHRONOUS_IO_NONALERT Windows.Wdk.Storage.FileSystem.FILE_WRITE_THROUGH +Windows.Wdk.Storage.FileSystem.FileAttributeTagInformation +Windows.Wdk.Storage.FileSystem.FileBasicInformation +Windows.Wdk.Storage.FileSystem.FileDispositionInformation +Windows.Wdk.Storage.FileSystem.FileDispositionInformationEx +Windows.Wdk.Storage.FileSystem.FileEndOfFileInformation +Windows.Wdk.Storage.FileSystem.FileFullDirectoryInformation +Windows.Wdk.Storage.FileSystem.FileFullDirectoryInformation +Windows.Wdk.Storage.FileSystem.FileNameInformation Windows.Wdk.Storage.FileSystem.NtCreateFile Windows.Wdk.Storage.FileSystem.NTCREATEFILE_CREATE_DISPOSITION Windows.Wdk.Storage.FileSystem.NTCREATEFILE_CREATE_OPTIONS Windows.Wdk.Storage.FileSystem.NtOpenFile +Windows.Wdk.Storage.FileSystem.NtQueryDirectoryFile +Windows.Wdk.Storage.FileSystem.NtQueryInformationFile Windows.Wdk.Storage.FileSystem.NtReadFile +Windows.Wdk.Storage.FileSystem.NtSetInformationFile Windows.Wdk.Storage.FileSystem.NtWriteFile Windows.Wdk.Storage.FileSystem.SYMLINK_FLAG_RELATIVE +Windows.Wdk.System.Threading.NtWaitForSingleObject Windows.Win32.Foundation.BOOL Windows.Win32.Foundation.BOOLEAN Windows.Win32.Foundation.CloseHandle @@ -2295,6 +2308,7 @@ Windows.Win32.Storage.FileSystem.FILE_FLAG_SEQUENTIAL_SCAN Windows.Win32.Storage.FileSystem.FILE_FLAG_SESSION_AWARE Windows.Win32.Storage.FileSystem.FILE_FLAG_WRITE_THROUGH Windows.Win32.Storage.FileSystem.FILE_FLAGS_AND_ATTRIBUTES +Windows.Win32.Storage.FileSystem.FILE_FULL_DIR_INFO Windows.Win32.Storage.FileSystem.FILE_GENERIC_EXECUTE Windows.Win32.Storage.FileSystem.FILE_GENERIC_READ Windows.Win32.Storage.FileSystem.FILE_GENERIC_WRITE @@ -2302,6 +2316,7 @@ Windows.Win32.Storage.FileSystem.FILE_ID_BOTH_DIR_INFO Windows.Win32.Storage.FileSystem.FILE_INFO_BY_HANDLE_CLASS Windows.Win32.Storage.FileSystem.FILE_IO_PRIORITY_HINT_INFO Windows.Win32.Storage.FileSystem.FILE_LIST_DIRECTORY +Windows.Win32.Storage.FileSystem.FILE_NAME_INFO Windows.Win32.Storage.FileSystem.FILE_NAME_NORMALIZED Windows.Win32.Storage.FileSystem.FILE_NAME_OPENED Windows.Win32.Storage.FileSystem.FILE_READ_ATTRIBUTES diff --git a/library/std/src/sys/pal/windows/c/fileextd.rs b/library/std/src/sys/pal/windows/c/fileextd.rs new file mode 100644 index 0000000000000..1216aac2b9414 --- /dev/null +++ b/library/std/src/sys/pal/windows/c/fileextd.rs @@ -0,0 +1,174 @@ +//! Manual implementation of a subset of `GetFileInformationByHandleEx` and +//! `SetFileInformationByHandle` based on `fileextd.lib` from Microsoft. Many of their later-added +//! APIs do exist all the way back to NT3.1, but were not exposed via a Win32 API until later. + +use super::*; + +pub(crate) unsafe fn get_file_information_by_handle_ex( + file_handle: HANDLE, + fileinformationclass: FILE_INFO_BY_HANDLE_CLASS, + lpfileinformation: *mut core::ffi::c_void, + dwbuffersize: u32, +) -> BOOL { + if !crate::sys::compat::checks::is_windows_nt() { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED) }; + return FALSE; + } + + unsafe { + #[allow(non_upper_case_globals)] + let (class, min_buffer_size, use_directory_api_info): ( + FILE_INFORMATION_CLASS, + u32, + Option, + ) = match fileinformationclass { + FileBasicInfo => { + (FileBasicInformation, core::mem::size_of::() as u32, None) + } + FileNameInfo => { + (FileNameInformation, core::mem::size_of::() as u32, None) + } + FileAttributeTagInfo => ( + // NT API: 2000 and up + FileAttributeTagInformation, + core::mem::size_of::() as u32, + None, + ), + // rust9x: replaced with the following two + // FileIdBothDirectoryInfo => ( + // // NT API: XP/2003 and up; exposed via Win32 API since Vista + // FileIdBothDirectoryInformation, + // core::mem::size_of::() as u32, + // Some(false), + // ), + // FileIdBothDirectoryRestartInfo => ( + // // NT API: XP/2003 and up; exposed via Win32 API since Vista + // FileIdBothDirectoryInformation, + // core::mem::size_of::() as u32, + // Some(true), + // ), + FileFullDirectoryInfo => ( + // NT API: at least NT4 but likely 3.1+; exposed via Win32 API since Win8 + FileFullDirectoryInformation, + core::mem::size_of::() as u32, + Some(false), + ), + FileFullDirectoryRestartInfo => ( + // NT API: at least NT4 but likely 3.1+; exposed via Win32 API since Win8 + FileFullDirectoryInformation, + core::mem::size_of::() as u32, + Some(true), + ), + _ => { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + }; + + if dwbuffersize < min_buffer_size { + SetLastError(ERROR_BAD_LENGTH); + return FALSE; + } + + let mut io_status_block: IO_STATUS_BLOCK = core::mem::zeroed(); + let mut status = if let Some(restart_scan) = use_directory_api_info { + NtQueryDirectoryFile( + file_handle, + core::ptr::null_mut(), + None, + core::ptr::null(), + &mut io_status_block, + lpfileinformation, + dwbuffersize, + class, + false as BOOLEAN, + core::ptr::null(), + restart_scan as BOOLEAN, + ) + } else { + NtQueryInformationFile( + file_handle, + &mut io_status_block, + lpfileinformation, + dwbuffersize, + class, + ) + }; + + if status == STATUS_PENDING { + status = NtWaitForSingleObject(file_handle, false as BOOLEAN, core::ptr::null_mut()); + } + + if status < 0 { + set_last_error_from_ntstatus(status); + return FALSE; + } + + // keeping for reference; FileStreamInformation is not used by the standard library + // currently if class == FileStreamInformation && io_status_block.Information == 0 { + // set_last_error_from_ntstatus(STATUS_END_OF_FILE); return FALSE; } + } + TRUE +} + +pub(crate) unsafe fn set_file_information_by_handle( + file_handle: HANDLE, + fileinformationclass: FILE_INFO_BY_HANDLE_CLASS, + lpfileinformation: *const core::ffi::c_void, + dwbuffersize: u32, +) -> BOOL { + if !crate::sys::compat::checks::is_windows_nt() { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED) }; + return FALSE; + } + + unsafe { + #[allow(non_upper_case_globals)] + let (class, min_buffer_size): (FILE_INFORMATION_CLASS, u32) = match fileinformationclass { + FileBasicInfo => (FileBasicInformation, core::mem::size_of::() as u32), + FileEndOfFileInfo => { + (FileEndOfFileInformation, core::mem::size_of::() as u32) + } + FileDispositionInfo => { + (FileDispositionInformation, core::mem::size_of::() as u32) + } + FileDispositionInfoEx => ( + // NT API: some Windows 10 version + FileDispositionInformationEx, + core::mem::size_of::() as u32, + ), + _ => { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + }; + + if dwbuffersize < min_buffer_size { + SetLastError(ERROR_BAD_LENGTH); + return FALSE; + } + + let mut io_status_block: IO_STATUS_BLOCK = core::mem::zeroed(); + let status = NtSetInformationFile( + file_handle, + &mut io_status_block, + lpfileinformation, + dwbuffersize, + class, + ); + + if status < 0 { + set_last_error_from_ntstatus(status); + return FALSE; + } + } + + TRUE +} + +fn set_last_error_from_ntstatus(status: NTSTATUS) { + unsafe { + let error = RtlNtStatusToDosError(status); + SetLastError(error); + } +} diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index d23538c778119..437a9941bf7b2 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -132,7 +132,11 @@ windows_targets::link!("kernel32.dll" "system" fn WriteFile(hfile : HANDLE, lpbu windows_targets::link!("kernel32.dll" "system" fn WriteFileEx(hfile : HANDLE, lpbuffer : *const u8, nnumberofbytestowrite : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL); windows_targets::link!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS); windows_targets::link!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS); +windows_targets::link!("ntdll.dll" "system" fn NtQueryDirectoryFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, fileinformation : *mut core::ffi::c_void, length : u32, fileinformationclass : FILE_INFORMATION_CLASS, returnsingleentry : BOOLEAN, filename : *const UNICODE_STRING, restartscan : BOOLEAN) -> NTSTATUS); +windows_targets::link!("ntdll.dll" "system" fn NtQueryInformationFile(filehandle : HANDLE, iostatusblock : *mut IO_STATUS_BLOCK, fileinformation : *mut core::ffi::c_void, length : u32, fileinformationclass : FILE_INFORMATION_CLASS) -> NTSTATUS); windows_targets::link!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); +windows_targets::link!("ntdll.dll" "system" fn NtSetInformationFile(filehandle : HANDLE, iostatusblock : *mut IO_STATUS_BLOCK, fileinformation : *const core::ffi::c_void, length : u32, fileinformationclass : FILE_INFORMATION_CLASS) -> NTSTATUS); +windows_targets::link!("ntdll.dll" "system" fn NtWaitForSingleObject(handle : HANDLE, alertable : BOOLEAN, timeout : *mut i64) -> NTSTATUS); windows_targets::link!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); windows_targets::link!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32); windows_targets::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL); @@ -2477,6 +2481,22 @@ pub const FILE_FLAG_RANDOM_ACCESS: FILE_FLAGS_AND_ATTRIBUTES = 268435456u32; pub const FILE_FLAG_SEQUENTIAL_SCAN: FILE_FLAGS_AND_ATTRIBUTES = 134217728u32; pub const FILE_FLAG_SESSION_AWARE: FILE_FLAGS_AND_ATTRIBUTES = 8388608u32; pub const FILE_FLAG_WRITE_THROUGH: FILE_FLAGS_AND_ATTRIBUTES = 2147483648u32; +#[repr(C)] +#[derive(Clone, Copy)] +pub struct FILE_FULL_DIR_INFO { + pub NextEntryOffset: u32, + pub FileIndex: u32, + pub CreationTime: i64, + pub LastAccessTime: i64, + pub LastWriteTime: i64, + pub ChangeTime: i64, + pub EndOfFile: i64, + pub AllocationSize: i64, + pub FileAttributes: u32, + pub FileNameLength: u32, + pub EaSize: u32, + pub FileName: [u16; 1], +} pub const FILE_GENERIC_EXECUTE: FILE_ACCESS_RIGHTS = 1179808u32; pub const FILE_GENERIC_READ: FILE_ACCESS_RIGHTS = 1179785u32; pub const FILE_GENERIC_WRITE: FILE_ACCESS_RIGHTS = 1179926u32; @@ -2499,6 +2519,7 @@ pub struct FILE_ID_BOTH_DIR_INFO { pub FileId: i64, pub FileName: [u16; 1], } +pub type FILE_INFORMATION_CLASS = i32; pub type FILE_INFO_BY_HANDLE_CLASS = i32; #[repr(C)] #[derive(Clone, Copy)] @@ -2506,6 +2527,12 @@ pub struct FILE_IO_PRIORITY_HINT_INFO { pub PriorityHint: PRIORITY_HINT, } pub const FILE_LIST_DIRECTORY: FILE_ACCESS_RIGHTS = 1u32; +#[repr(C)] +#[derive(Clone, Copy)] +pub struct FILE_NAME_INFO { + pub FileNameLength: u32, + pub FileName: [u16; 1], +} pub const FILE_NAME_NORMALIZED: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32; pub const FILE_NAME_OPENED: GETFINALPATHNAMEBYHANDLE_FLAGS = 8u32; pub const FILE_NON_DIRECTORY_FILE: NTCREATEFILE_CREATE_OPTIONS = 64u32; @@ -2602,13 +2629,19 @@ pub const FSCTL_SET_REPARSE_POINT: u32 = 589988u32; pub const FileAlignmentInfo: FILE_INFO_BY_HANDLE_CLASS = 17i32; pub const FileAllocationInfo: FILE_INFO_BY_HANDLE_CLASS = 5i32; pub const FileAttributeTagInfo: FILE_INFO_BY_HANDLE_CLASS = 9i32; +pub const FileAttributeTagInformation: FILE_INFORMATION_CLASS = 35i32; pub const FileBasicInfo: FILE_INFO_BY_HANDLE_CLASS = 0i32; +pub const FileBasicInformation: FILE_INFORMATION_CLASS = 4i32; pub const FileCaseSensitiveInfo: FILE_INFO_BY_HANDLE_CLASS = 23i32; pub const FileCompressionInfo: FILE_INFO_BY_HANDLE_CLASS = 8i32; pub const FileDispositionInfo: FILE_INFO_BY_HANDLE_CLASS = 4i32; pub const FileDispositionInfoEx: FILE_INFO_BY_HANDLE_CLASS = 21i32; +pub const FileDispositionInformation: FILE_INFORMATION_CLASS = 13i32; +pub const FileDispositionInformationEx: FILE_INFORMATION_CLASS = 64i32; pub const FileEndOfFileInfo: FILE_INFO_BY_HANDLE_CLASS = 6i32; +pub const FileEndOfFileInformation: FILE_INFORMATION_CLASS = 20i32; pub const FileFullDirectoryInfo: FILE_INFO_BY_HANDLE_CLASS = 14i32; +pub const FileFullDirectoryInformation: FILE_INFORMATION_CLASS = 2i32; pub const FileFullDirectoryRestartInfo: FILE_INFO_BY_HANDLE_CLASS = 15i32; pub const FileIdBothDirectoryInfo: FILE_INFO_BY_HANDLE_CLASS = 10i32; pub const FileIdBothDirectoryRestartInfo: FILE_INFO_BY_HANDLE_CLASS = 11i32; @@ -2617,6 +2650,7 @@ pub const FileIdExtdDirectoryRestartInfo: FILE_INFO_BY_HANDLE_CLASS = 20i32; pub const FileIdInfo: FILE_INFO_BY_HANDLE_CLASS = 18i32; pub const FileIoPriorityHintInfo: FILE_INFO_BY_HANDLE_CLASS = 12i32; pub const FileNameInfo: FILE_INFO_BY_HANDLE_CLASS = 2i32; +pub const FileNameInformation: FILE_INFORMATION_CLASS = 9i32; pub const FileNormalizedNameInfo: FILE_INFO_BY_HANDLE_CLASS = 24i32; pub const FileRemoteProtocolInfo: FILE_INFO_BY_HANDLE_CLASS = 13i32; pub const FileRenameInfo: FILE_INFO_BY_HANDLE_CLASS = 3i32; diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index cca8e30de72b8..ac9fe84053678 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -527,7 +527,7 @@ impl File { #[cfg(target_vendor = "rust9x")] pub fn truncate_inner(handle: RawHandle, size: u64) -> io::Result<()> { - if c::SetFileInformationByHandle::available().is_some() { + if crate::sys::compat::checks::is_windows_nt() { let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 }; api::set_file_information_by_handle(handle, &info).io_result() } else { @@ -556,22 +556,20 @@ impl File { cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?; let mut reparse_tag = 0; if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - #[cfg(target_vendor = "rust9x")] - let f = c::GetFileInformationByHandleEx::available(); - #[cfg(not(target_vendor = "rust9x"))] - let f = Some(c::GetFileInformationByHandleEx); - - if let Some(f) = f { - let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed(); - cvt(f( - self.handle.as_raw_handle(), - c::FileAttributeTagInfo, - (&raw mut attr_tag).cast(), - mem::size_of::().try_into().unwrap(), - ))?; - if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - reparse_tag = attr_tag.ReparseTag; - } + let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed(); + // rust9x: If a reparse point attribute is returned, we must be on NT-based Windows + // with support for FileAttributeTagInformation, so our + // fallback implementation of `GetFileInformationByHandleEx` will work without + // further checks. + + cvt(c::GetFileInformationByHandleEx( + self.handle.as_raw_handle(), + c::FileAttributeTagInfo, + (&raw mut attr_tag).cast(), + mem::size_of::().try_into().unwrap(), + ))?; + if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + reparse_tag = attr_tag.ReparseTag; } } Ok(FileAttr { @@ -908,6 +906,10 @@ impl File { /// you will always iterate an empty directory regardless of the target. #[allow(unused)] fn fill_dir_buff(&self, buffer: &mut DirBuff, restart: bool) -> Result { + #[cfg(target_vendor = "rust9x")] + let class = + if restart { c::FileFullDirectoryRestartInfo } else { c::FileFullDirectoryInfo }; + #[cfg(not(target_vendor = "rust9x"))] let class = if restart { c::FileIdBothDirectoryRestartInfo } else { c::FileIdBothDirectoryInfo }; @@ -985,6 +987,9 @@ impl<'a> Iterator for DirBuffIter<'a> { // `FILE_ID_BOTH_DIR_INFO` and the trailing filename (for at least // `FileNameLength` bytes) let (name, is_directory, next_entry) = unsafe { + #[cfg(target_vendor = "rust9x")] + let info = buffer.as_ptr().cast::(); + #[cfg(not(target_vendor = "rust9x"))] let info = buffer.as_ptr().cast::(); // While this is guaranteed to be aligned in documentation for // https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_both_dir_info @@ -1335,10 +1340,7 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { { // if the modern file/directory APIs are not available, we'll fall back to the old (unsafe, see // https://github.com/rust-lang/rust/pull/93112) directory removal implementation - if !(c::NtOpenFile::available().is_some() - && c::GetFileInformationByHandleEx::available().is_some() - && c::SetFileInformationByHandle::available().is_some()) - { + if !crate::sys::compat::checks::is_windows_nt() { let filetype = lstat(path)?.file_type(); if filetype.is_symlink() { // On Windows symlinks to files and directories are removed differently. diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs index 2e096bf8af6a6..5953574d4577c 100644 --- a/library/std/src/sys/pal/windows/io.rs +++ b/library/std/src/sys/pal/windows/io.rs @@ -125,10 +125,11 @@ fn msys_tty_on(handle: BorrowedHandle<'_>) -> bool { // Safety: buffer length is fixed. let res = unsafe { #[cfg(target_vendor = "rust9x")] - let Some(fun) = c::GetFileInformationByHandleEx::available() else { return false }; - #[cfg(not(target_vendor = "rust9x"))] - let fun = c::GetFileInformationByHandleEx; - fun( + if !crate::sys::compat::checks::is_windows_nt() { + return false; + } + + c::GetFileInformationByHandleEx( handle.as_raw_handle(), c::FileNameInfo, (&raw mut name_info) as *mut c_void,