Skip to content

Commit b69a464

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 c5fc0f7 commit b69a464

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
@@ -328,16 +328,7 @@ impl File {
328328
mem::size_of::<c::FILE_ALLOCATION_INFO>() as u32,
329329
);
330330
if result == 0 {
331-
let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 };
332-
let result = c::SetFileInformationByHandle(
333-
handle.as_raw_handle(),
334-
c::FileEndOfFileInfo,
335-
(&raw const eof).cast::<c_void>(),
336-
mem::size_of::<c::FILE_END_OF_FILE_INFO>() as u32,
337-
);
338-
if result == 0 {
339-
return Err(io::Error::last_os_error());
340-
}
331+
Self::truncate_inner(handle.as_raw_handle(), 0)?
341332
}
342333
}
343334
}
@@ -471,8 +462,37 @@ impl File {
471462
}
472463

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

478498
#[cfg(not(target_vendor = "uwp"))]
@@ -482,15 +502,22 @@ impl File {
482502
cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?;
483503
let mut reparse_tag = 0;
484504
if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
485-
let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed();
486-
cvt(c::GetFileInformationByHandleEx(
487-
self.handle.as_raw_handle(),
488-
c::FileAttributeTagInfo,
489-
(&raw mut attr_tag).cast(),
490-
mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
491-
))?;
492-
if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
493-
reparse_tag = attr_tag.ReparseTag;
505+
#[cfg(target_vendor = "rust9x")]
506+
let f = c::GetFileInformationByHandleEx::available();
507+
#[cfg(not(target_vendor = "rust9x"))]
508+
let f = Some(c::GetFileInformationByHandleEx);
509+
510+
if let Some(f) = f {
511+
let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed();
512+
cvt(f(
513+
self.handle.as_raw_handle(),
514+
c::FileAttributeTagInfo,
515+
(&raw mut attr_tag).cast(),
516+
mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
517+
))?;
518+
if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
519+
reparse_tag = attr_tag.ReparseTag;
520+
}
494521
}
495522
}
496523
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)