Skip to content

Commit 2be904f

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 568f04b commit 2be904f

File tree

5 files changed

+117
-27
lines changed

5 files changed

+117
-27
lines changed

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

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

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2351,6 +2351,7 @@ Windows.Win32.Storage.FileSystem.GetFinalPathNameByHandleW
23512351
Windows.Win32.Storage.FileSystem.GetFullPathNameW
23522352
Windows.Win32.Storage.FileSystem.GetTempPathW
23532353
Windows.Win32.Storage.FileSystem.INVALID_FILE_ATTRIBUTES
2354+
Windows.Win32.Storage.FileSystem.INVALID_SET_FILE_POINTER
23542355
Windows.Win32.Storage.FileSystem.LOCKFILE_EXCLUSIVE_LOCK
23552356
Windows.Win32.Storage.FileSystem.LOCKFILE_FAIL_IMMEDIATELY
23562357
Windows.Win32.Storage.FileSystem.LockFileEx
@@ -2384,8 +2385,10 @@ Windows.Win32.Storage.FileSystem.SECURITY_IMPERSONATION
23842385
Windows.Win32.Storage.FileSystem.SECURITY_SQOS_PRESENT
23852386
Windows.Win32.Storage.FileSystem.SECURITY_VALID_SQOS_FLAGS
23862387
Windows.Win32.Storage.FileSystem.SET_FILE_POINTER_MOVE_METHOD
2388+
Windows.Win32.Storage.FileSystem.SetEndOfFile
23872389
Windows.Win32.Storage.FileSystem.SetFileAttributesW
23882390
Windows.Win32.Storage.FileSystem.SetFileInformationByHandle
2391+
Windows.Win32.Storage.FileSystem.SetFilePointer
23892392
Windows.Win32.Storage.FileSystem.SetFilePointerEx
23902393
Windows.Win32.Storage.FileSystem.SetFileTime
23912394
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
@@ -88,10 +88,12 @@ windows_targets::link!("kernel32.dll" "system" fn ReleaseSRWLockShared(srwlock :
8888
windows_targets::link!("kernel32.dll" "system" fn RemoveDirectoryW(lppathname : PCWSTR) -> BOOL);
8989
windows_targets::link!("kernel32.dll" "system" fn ResetEvent(hevent : HANDLE) -> BOOL);
9090
windows_targets::link!("kernel32.dll" "system" fn SetCurrentDirectoryW(lppathname : PCWSTR) -> BOOL);
91+
windows_targets::link!("kernel32.dll" "system" fn SetEndOfFile(hfile : HANDLE) -> BOOL);
9192
windows_targets::link!("kernel32.dll" "system" fn SetEnvironmentVariableW(lpname : PCWSTR, lpvalue : PCWSTR) -> BOOL);
9293
windows_targets::link!("kernel32.dll" "system" fn SetEvent(hevent : HANDLE) -> BOOL);
9394
windows_targets::link!("kernel32.dll" "system" fn SetFileAttributesW(lpfilename : PCWSTR, dwfileattributes : FILE_FLAGS_AND_ATTRIBUTES) -> BOOL);
9495
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);
96+
windows_targets::link!("kernel32.dll" "system" fn SetFilePointer(hfile : HANDLE, ldistancetomove : i32, lpdistancetomovehigh : *mut i32, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD) -> u32);
9597
windows_targets::link!("kernel32.dll" "system" fn SetFilePointerEx(hfile : HANDLE, lidistancetomove : i64, lpnewfilepointer : *mut i64, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD) -> BOOL);
9698
windows_targets::link!("kernel32.dll" "system" fn SetFileTime(hfile : HANDLE, lpcreationtime : *const FILETIME, lplastaccesstime : *const FILETIME, lplastwritetime : *const FILETIME) -> BOOL);
9799
windows_targets::link!("kernel32.dll" "system" fn SetHandleInformation(hobject : HANDLE, dwmask : u32, dwflags : HANDLE_FLAGS) -> BOOL);
@@ -2664,6 +2666,7 @@ pub union INIT_ONCE {
26642666
}
26652667
pub const INIT_ONCE_INIT_FAILED: u32 = 4u32;
26662668
pub const INVALID_FILE_ATTRIBUTES: u32 = 4294967295u32;
2669+
pub const INVALID_SET_FILE_POINTER: u32 = 4294967295u32;
26672670
pub const INVALID_SOCKET: SOCKET = -1i32 as _;
26682671
#[repr(C)]
26692672
#[derive(Clone, Copy)]

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

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -314,22 +314,11 @@ impl File {
314314
&& creation == c::OPEN_ALWAYS
315315
&& api::get_last_error() == WinError::ALREADY_EXISTS
316316
{
317-
unsafe {
318-
// This originally used `FileAllocationInfo` instead of
319-
// `FileEndOfFileInfo` but that wasn't supported by WINE.
320-
// It's arguable which fits the semantics of `OpenOptions`
321-
// better so let's just use the more widely supported method.
322-
let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 };
323-
let result = c::SetFileInformationByHandle(
324-
handle.as_raw_handle(),
325-
c::FileEndOfFileInfo,
326-
(&raw const eof).cast::<c_void>(),
327-
mem::size_of::<c::FILE_END_OF_FILE_INFO>() as u32,
328-
);
329-
if result == 0 {
330-
return Err(io::Error::last_os_error());
331-
}
332-
}
317+
// This originally used `FileAllocationInfo` instead of
318+
// `FileEndOfFileInfo` but that wasn't supported by WINE.
319+
// It's arguable which fits the semantics of `OpenOptions`
320+
// better so let's just use the more widely supported method.
321+
Self::truncate_inner(handle.as_raw_handle(), 0)?
333322
}
334323
Ok(File { handle: Handle::from_inner(handle) })
335324
} else {
@@ -461,8 +450,37 @@ impl File {
461450
}
462451

463452
pub fn truncate(&self, size: u64) -> io::Result<()> {
453+
Self::truncate_inner(self.handle.as_raw_handle(), size)
454+
}
455+
456+
#[cfg(not(target_vendor = "rust9x"))]
457+
pub fn truncate_inner(handle: RawHandle, size: u64) -> io::Result<()> {
464458
let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 };
465-
api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result()
459+
api::set_file_information_by_handle(handle, &info).io_result()
460+
}
461+
462+
#[cfg(target_vendor = "rust9x")]
463+
pub fn truncate_inner(handle: RawHandle, size: u64) -> io::Result<()> {
464+
if c::SetFileInformationByHandle::available().is_some() {
465+
let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 };
466+
api::set_file_information_by_handle(handle, &info).io_result()
467+
} else {
468+
let mut saved_pos = 0i64;
469+
unsafe {
470+
// get current file pointer position
471+
cvt(c::SetFilePointerEx(handle, 0, &mut saved_pos, c::FILE_CURRENT))?;
472+
473+
// seek to new end position
474+
cvt(c::SetFilePointerEx(handle, size as i64, ptr::null_mut(), c::FILE_BEGIN))?;
475+
476+
// set current position as end of file
477+
cvt(c::SetEndOfFile(handle))?;
478+
479+
// go back to saved position
480+
cvt(c::SetFilePointerEx(handle, saved_pos, ptr::null_mut(), c::FILE_BEGIN))?;
481+
}
482+
Ok(())
483+
}
466484
}
467485

468486
#[cfg(not(target_vendor = "uwp"))]
@@ -472,15 +490,22 @@ impl File {
472490
cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?;
473491
let mut reparse_tag = 0;
474492
if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
475-
let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed();
476-
cvt(c::GetFileInformationByHandleEx(
477-
self.handle.as_raw_handle(),
478-
c::FileAttributeTagInfo,
479-
(&raw mut attr_tag).cast(),
480-
mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
481-
))?;
482-
if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
483-
reparse_tag = attr_tag.ReparseTag;
493+
#[cfg(target_vendor = "rust9x")]
494+
let f = c::GetFileInformationByHandleEx::available();
495+
#[cfg(not(target_vendor = "rust9x"))]
496+
let f = Some(c::GetFileInformationByHandleEx);
497+
498+
if let Some(f) = f {
499+
let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed();
500+
cvt(f(
501+
self.handle.as_raw_handle(),
502+
c::FileAttributeTagInfo,
503+
(&raw mut attr_tag).cast(),
504+
mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
505+
))?;
506+
if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
507+
reparse_tag = attr_tag.ReparseTag;
508+
}
484509
}
485510
}
486511
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)