Skip to content

Commit 9544927

Browse files
committed
Add fallback impls for File::truncate and File::seek, file_attr
- Fallback for `SetFilePointerEx` based on `SetFilePointer` - Fallback for file truncation (`SetFileInformationByHandle` with `FileEndOfFileInfo`) based on `SetFilePointerEx` and `SetEndOfFile` - file_attr: Don't query reparse tag if API is not available (`GetFileInformationByHandleEx` with `FileAttributeTagInfo`)
1 parent 3b293c1 commit 9544927

File tree

5 files changed

+113
-21
lines changed

5 files changed

+113
-21
lines changed

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,3 +390,58 @@ compat_fn_with_fallback! {
390390
rtabort!("unimplemented")
391391
}
392392
}
393+
394+
#[cfg(target_vendor = "rust9x")]
395+
compat_fn_with_fallback! {
396+
pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false };
397+
// >= 2000
398+
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfilepointerex
399+
pub fn SetFilePointerEx(
400+
hfile: HANDLE,
401+
lidistancetomove: i64,
402+
lpnewfilepointer: *mut i64,
403+
dwmovemethod: SET_FILE_POINTER_MOVE_METHOD,
404+
) -> BOOL {
405+
unsafe {
406+
let distance_low = lidistancetomove as i32;
407+
let mut distance_high = (lidistancetomove >> 32) as i32;
408+
409+
let new_pos_low = SetFilePointer(hfile, distance_low, &mut distance_high, dwmovemethod);
410+
411+
// since (-1 as u32) could be a valid value for the lower 32 bits of the new file
412+
// pointer position, a call to GetLastError is needed to actually see if it failed
413+
if new_pos_low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR {
414+
return FALSE;
415+
}
416+
417+
if !lpnewfilepointer.is_null() {
418+
*lpnewfilepointer = (distance_high as i64) << 32 | (new_pos_low as i64);
419+
}
420+
421+
TRUE
422+
}
423+
}
424+
425+
// >= Vista / Server 2008 (XP / Server 2003 when linking a supported FileExtd.lib)
426+
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle
427+
pub fn SetFileInformationByHandle(
428+
hfile: HANDLE,
429+
fileinformationclass: FILE_INFO_BY_HANDLE_CLASS,
430+
lpfileinformation: *const ::core::ffi::c_void,
431+
dwbuffersize: u32,
432+
) -> BOOL {
433+
unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); };
434+
FALSE
435+
}
436+
// >= Vista / Server 2008 (XP / Server 2003 when linking a supported FileExtd.lib)
437+
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
438+
pub fn GetFileInformationByHandleEx(
439+
hfile: HANDLE,
440+
fileinformationclass: FILE_INFO_BY_HANDLE_CLASS,
441+
lpfileinformation: *mut ::core::ffi::c_void,
442+
dwbuffersize: u32,
443+
) -> BOOL {
444+
unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); };
445+
FALSE
446+
}
447+
}

library/std/src/sys/pal/windows/c/bindings.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,6 +2352,7 @@ Windows.Win32.Storage.FileSystem.GetFinalPathNameByHandleW
23522352
Windows.Win32.Storage.FileSystem.GetFullPathNameW
23532353
Windows.Win32.Storage.FileSystem.GetTempPathW
23542354
Windows.Win32.Storage.FileSystem.INVALID_FILE_ATTRIBUTES
2355+
Windows.Win32.Storage.FileSystem.INVALID_SET_FILE_POINTER
23552356
Windows.Win32.Storage.FileSystem.LOCKFILE_EXCLUSIVE_LOCK
23562357
Windows.Win32.Storage.FileSystem.LOCKFILE_FAIL_IMMEDIATELY
23572358
Windows.Win32.Storage.FileSystem.LockFileEx
@@ -2385,8 +2386,10 @@ Windows.Win32.Storage.FileSystem.SECURITY_IMPERSONATION
23852386
Windows.Win32.Storage.FileSystem.SECURITY_SQOS_PRESENT
23862387
Windows.Win32.Storage.FileSystem.SECURITY_VALID_SQOS_FLAGS
23872388
Windows.Win32.Storage.FileSystem.SET_FILE_POINTER_MOVE_METHOD
2389+
Windows.Win32.Storage.FileSystem.SetEndOfFile
23882390
Windows.Win32.Storage.FileSystem.SetFileAttributesW
23892391
Windows.Win32.Storage.FileSystem.SetFileInformationByHandle
2392+
Windows.Win32.Storage.FileSystem.SetFilePointer
23902393
Windows.Win32.Storage.FileSystem.SetFilePointerEx
23912394
Windows.Win32.Storage.FileSystem.SetFileTime
23922395
Windows.Win32.Storage.FileSystem.SPECIFIC_RIGHTS_ALL

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,12 @@ windows_targets::link!("kernel32.dll" "system" fn ReleaseSRWLockShared(srwlock :
8989
windows_targets::link!("kernel32.dll" "system" fn RemoveDirectoryW(lppathname : PCWSTR) -> BOOL);
9090
windows_targets::link!("kernel32.dll" "system" fn ResetEvent(hevent : HANDLE) -> BOOL);
9191
windows_targets::link!("kernel32.dll" "system" fn SetCurrentDirectoryW(lppathname : PCWSTR) -> BOOL);
92+
windows_targets::link!("kernel32.dll" "system" fn SetEndOfFile(hfile : HANDLE) -> BOOL);
9293
windows_targets::link!("kernel32.dll" "system" fn SetEnvironmentVariableW(lpname : PCWSTR, lpvalue : PCWSTR) -> BOOL);
9394
windows_targets::link!("kernel32.dll" "system" fn SetEvent(hevent : HANDLE) -> BOOL);
9495
windows_targets::link!("kernel32.dll" "system" fn SetFileAttributesW(lpfilename : PCWSTR, dwfileattributes : FILE_FLAGS_AND_ATTRIBUTES) -> BOOL);
9596
windows_targets::link!("kernel32.dll" "system" fn SetFileInformationByHandle(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *const core::ffi::c_void, dwbuffersize : u32) -> BOOL);
97+
windows_targets::link!("kernel32.dll" "system" fn SetFilePointer(hfile : HANDLE, ldistancetomove : i32, lpdistancetomovehigh : *mut i32, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD) -> u32);
9698
windows_targets::link!("kernel32.dll" "system" fn SetFilePointerEx(hfile : HANDLE, lidistancetomove : i64, lpnewfilepointer : *mut i64, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD) -> BOOL);
9799
windows_targets::link!("kernel32.dll" "system" fn SetFileTime(hfile : HANDLE, lpcreationtime : *const FILETIME, lplastaccesstime : *const FILETIME, lplastwritetime : *const FILETIME) -> BOOL);
98100
windows_targets::link!("kernel32.dll" "system" fn SetHandleInformation(hobject : HANDLE, dwmask : u32, dwflags : HANDLE_FLAGS) -> BOOL);
@@ -2681,6 +2683,7 @@ pub union INIT_ONCE {
26812683
}
26822684
pub const INIT_ONCE_INIT_FAILED: u32 = 4u32;
26832685
pub const INVALID_FILE_ATTRIBUTES: u32 = 4294967295u32;
2686+
pub const INVALID_SET_FILE_POINTER: u32 = 4294967295u32;
26842687
pub const INVALID_SOCKET: SOCKET = -1i32 as _;
26852688
#[repr(C)]
26862689
#[derive(Clone, Copy)]

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

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -332,16 +332,7 @@ impl File {
332332
mem::size_of::<c::FILE_ALLOCATION_INFO>() as u32,
333333
);
334334
if result == 0 {
335-
let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 };
336-
let result = c::SetFileInformationByHandle(
337-
handle.as_raw_handle(),
338-
c::FileEndOfFileInfo,
339-
(&raw const eof).cast::<c_void>(),
340-
mem::size_of::<c::FILE_END_OF_FILE_INFO>() as u32,
341-
);
342-
if result == 0 {
343-
return Err(io::Error::last_os_error());
344-
}
335+
Self::truncate_inner(handle.as_raw_handle(), 0)?
345336
}
346337
}
347338
}
@@ -475,8 +466,37 @@ impl File {
475466
}
476467

477468
pub fn truncate(&self, size: u64) -> io::Result<()> {
469+
Self::truncate_inner(self.handle.as_raw_handle(), size)
470+
}
471+
472+
#[cfg(not(target_vendor = "rust9x"))]
473+
pub fn truncate_inner(handle: RawHandle, size: u64) -> io::Result<()> {
478474
let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 };
479-
api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result()
475+
api::set_file_information_by_handle(handle, &info).io_result()
476+
}
477+
478+
#[cfg(target_vendor = "rust9x")]
479+
pub fn truncate_inner(handle: RawHandle, size: u64) -> io::Result<()> {
480+
if c::SetFileInformationByHandle::available().is_some() {
481+
let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 };
482+
api::set_file_information_by_handle(handle, &info).io_result()
483+
} else {
484+
let mut saved_pos = 0i64;
485+
unsafe {
486+
// get current file pointer position
487+
cvt(c::SetFilePointerEx(handle, 0, &mut saved_pos, c::FILE_CURRENT))?;
488+
489+
// seek to new end position
490+
cvt(c::SetFilePointerEx(handle, size as i64, ptr::null_mut(), c::FILE_BEGIN))?;
491+
492+
// set current position as end of file
493+
cvt(c::SetEndOfFile(handle))?;
494+
495+
// go back to saved position
496+
cvt(c::SetFilePointerEx(handle, saved_pos, ptr::null_mut(), c::FILE_BEGIN))?;
497+
}
498+
Ok(())
499+
}
480500
}
481501

482502
#[cfg(not(target_vendor = "uwp"))]
@@ -486,15 +506,22 @@ impl File {
486506
cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?;
487507
let mut reparse_tag = 0;
488508
if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
489-
let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed();
490-
cvt(c::GetFileInformationByHandleEx(
491-
self.handle.as_raw_handle(),
492-
c::FileAttributeTagInfo,
493-
(&raw mut attr_tag).cast(),
494-
mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
495-
))?;
496-
if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
497-
reparse_tag = attr_tag.ReparseTag;
509+
#[cfg(target_vendor = "rust9x")]
510+
let f = c::GetFileInformationByHandleEx::available();
511+
#[cfg(not(target_vendor = "rust9x"))]
512+
let f = Some(c::GetFileInformationByHandleEx);
513+
514+
if let Some(f) = f {
515+
let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed();
516+
cvt(f(
517+
self.handle.as_raw_handle(),
518+
c::FileAttributeTagInfo,
519+
(&raw mut attr_tag).cast(),
520+
mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
521+
))?;
522+
if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
523+
reparse_tag = attr_tag.ReparseTag;
524+
}
498525
}
499526
}
500527
Ok(FileAttr {

library/std/src/sys/pal/windows/io.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,11 @@ fn msys_tty_on(handle: BorrowedHandle<'_>) -> bool {
124124
let mut name_info = FILE_NAME_INFO { FileNameLength: 0, FileName: [0; c::MAX_PATH as usize] };
125125
// Safety: buffer length is fixed.
126126
let res = unsafe {
127-
c::GetFileInformationByHandleEx(
127+
#[cfg(target_vendor = "rust9x")]
128+
let Some(fun) = c::GetFileInformationByHandleEx::available() else { return false };
129+
#[cfg(not(target_vendor = "rust9x"))]
130+
let fun = c::GetFileInformationByHandleEx;
131+
fun(
128132
handle.as_raw_handle(),
129133
c::FileNameInfo,
130134
(&raw mut name_info) as *mut c_void,

0 commit comments

Comments
 (0)