Skip to content

Commit d7d75ed

Browse files
seritoolsmbilker
authored andcommitted
Add fallback impl for File::truncate and File::seek
- Fallback for `SetFilePointerEx` based on `SetFilePointer` - Fallback for `SetFileInformationByHandle` with `FileEndOfFileInfo` based on `SetFilePointerEx` and `SetEndOfFile` Signed-off-by: Dennis Duda <git@seri.tools>
1 parent 7285be2 commit d7d75ed

File tree

4 files changed

+93
-30
lines changed

4 files changed

+93
-30
lines changed

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ pub struct SYSTEMTIME {
213213

214214
pub type LPSYSTEMTIME = *mut SYSTEMTIME;
215215

216+
pub const INVALID_SET_FILE_POINTER: WIN32_ERROR = 0xFFFFFFFFu32;
217+
216218
pub unsafe extern "system" fn WriteFileEx(
217219
hFile: BorrowedHandle<'_>,
218220
lpBuffer: *mut ::core::ffi::c_void,
@@ -430,6 +432,44 @@ compat_fn_with_fallback! {
430432
GetSystemTime(&mut st);
431433
crate::sys::cvt(SystemTimeToFileTime(&st, lpSystemTimeAsFileTime)).unwrap();
432434
}
435+
436+
// >= 2000
437+
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfilepointerex
438+
pub fn SetFilePointerEx(
439+
hFile: HANDLE,
440+
liDistanceToMove: LARGE_INTEGER,
441+
lpNewFilePointer: PLARGE_INTEGER,
442+
dwMoveMethod: DWORD
443+
) -> BOOL {
444+
let lDistanceToMove = liDistanceToMove as LONG;
445+
let mut distance_to_move_high = (liDistanceToMove >> 32) as LONG;
446+
447+
let newPos_low = SetFilePointer(hFile, lDistanceToMove, &mut distance_to_move_high, dwMoveMethod);
448+
449+
// since (-1 as u32) could be a valid value for the lower 32 bits of the new file pointer
450+
// position, a call to GetLastError is needed to actually see if it failed
451+
if newPos_low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR {
452+
return FALSE;
453+
}
454+
455+
if !lpNewFilePointer.is_null() {
456+
*lpNewFilePointer = (distance_to_move_high as LARGE_INTEGER) << 32 | (newPos_low as LARGE_INTEGER);
457+
}
458+
459+
TRUE
460+
}
461+
462+
// >= Vista / Server 2008 (XP / Server 2003 when linking a supported FileExtd.lib)
463+
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle
464+
pub fn SetFileInformationByHandle(
465+
hFile: HANDLE,
466+
FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
467+
lpFileInformation: LPVOID,
468+
dwBufferSize: DWORD
469+
) -> BOOL {
470+
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD);
471+
FALSE
472+
}
433473
}
434474

435475
compat_fn_optional! {
@@ -495,4 +535,13 @@ extern "system" {
495535

496536
pub fn GetSystemTime(lpSystemTime: LPSYSTEMTIME);
497537
pub fn SystemTimeToFileTime(lpSystemTime: *const SYSTEMTIME, lpFileTime: LPFILETIME) -> BOOL;
538+
539+
pub fn SetEndOfFile(hFile: HANDLE) -> BOOL;
540+
541+
pub fn SetFilePointer(
542+
hFile: HANDLE,
543+
lDistanceToMove: LONG,
544+
lpDistanceToMoveHigh: *mut LONG,
545+
dwMoveMethod: DWORD,
546+
) -> DWORD;
498547
}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,8 +2372,6 @@ Windows.Win32.Storage.FileSystem.SECURITY_SQOS_PRESENT
23722372
Windows.Win32.Storage.FileSystem.SECURITY_VALID_SQOS_FLAGS
23732373
Windows.Win32.Storage.FileSystem.SET_FILE_POINTER_MOVE_METHOD
23742374
Windows.Win32.Storage.FileSystem.SetFileAttributesW
2375-
Windows.Win32.Storage.FileSystem.SetFileInformationByHandle
2376-
Windows.Win32.Storage.FileSystem.SetFilePointerEx
23772375
Windows.Win32.Storage.FileSystem.SetFileTime
23782376
Windows.Win32.Storage.FileSystem.SPECIFIC_RIGHTS_ALL
23792377
Windows.Win32.Storage.FileSystem.STANDARD_RIGHTS_ALL

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

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -435,24 +435,6 @@ extern "system" {
435435
) -> BOOL;
436436
}
437437
#[link(name = "kernel32")]
438-
extern "system" {
439-
pub fn SetFileInformationByHandle(
440-
hfile: HANDLE,
441-
fileinformationclass: FILE_INFO_BY_HANDLE_CLASS,
442-
lpfileinformation: *const ::core::ffi::c_void,
443-
dwbuffersize: u32,
444-
) -> BOOL;
445-
}
446-
#[link(name = "kernel32")]
447-
extern "system" {
448-
pub fn SetFilePointerEx(
449-
hfile: HANDLE,
450-
lidistancetomove: i64,
451-
lpnewfilepointer: *mut i64,
452-
dwmovemethod: SET_FILE_POINTER_MOVE_METHOD,
453-
) -> BOOL;
454-
}
455-
#[link(name = "kernel32")]
456438
extern "system" {
457439
pub fn SetFileTime(
458440
hfile: HANDLE,

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

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -316,16 +316,50 @@ impl File {
316316
}
317317

318318
pub fn truncate(&self, size: u64) -> io::Result<()> {
319-
let mut info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as c::LARGE_INTEGER };
320-
let size = mem::size_of_val(&info);
321-
cvt(unsafe {
322-
c::SetFileInformationByHandle(
323-
self.handle.as_raw_handle(),
324-
c::FileEndOfFileInfo,
325-
&mut info as *mut _ as *mut _,
326-
size as c::DWORD,
327-
)
328-
})?;
319+
if c::SetFileInformationByHandle::available() {
320+
let mut info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as c::LARGE_INTEGER };
321+
let size = mem::size_of_val(&info);
322+
323+
cvt(unsafe {
324+
c::SetFileInformationByHandle(
325+
self.handle.as_raw_handle(),
326+
c::FileEndOfFileInfo,
327+
&mut info as *mut _ as *mut _,
328+
size as c::DWORD,
329+
)
330+
})?;
331+
} else {
332+
let mut saved_pos = 0;
333+
unsafe {
334+
// get current file pointer position
335+
cvt(c::SetFilePointerEx(
336+
self.handle.as_raw_handle(),
337+
0,
338+
&mut saved_pos,
339+
c::FILE_CURRENT,
340+
))?;
341+
342+
// seek to new end position
343+
cvt(c::SetFilePointerEx(
344+
self.handle.as_raw_handle(),
345+
size as c::LARGE_INTEGER,
346+
ptr::null_mut(),
347+
c::FILE_BEGIN,
348+
))?;
349+
350+
// set current position as end of file
351+
cvt(c::SetEndOfFile(self.handle.as_raw_handle()))?;
352+
353+
// go back to saved position
354+
cvt(c::SetFilePointerEx(
355+
self.handle.as_raw_handle(),
356+
saved_pos as c::LARGE_INTEGER,
357+
ptr::null_mut(),
358+
c::FILE_BEGIN,
359+
))?;
360+
}
361+
}
362+
329363
Ok(())
330364
}
331365

0 commit comments

Comments
 (0)