@@ -5,6 +5,7 @@ use std::path::PathBuf;
55use std:: time:: SystemTime ;
66
77use bitflags:: bitflags;
8+ use rustc_abi:: Size ;
89use rustc_target:: spec:: Os ;
910
1011use crate :: shims:: files:: { FdId , FileDescription , FileHandle } ;
@@ -372,6 +373,90 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
372373 interp_ok ( this. eval_windows ( "c" , "TRUE" ) )
373374 }
374375
376+ fn SetFileInformationByHandle (
377+ & mut self ,
378+ file : & OpTy < ' tcx > , // HANDLE
379+ class : & OpTy < ' tcx > , // FILE_INFO_BY_HANDLE_CLASS
380+ file_information : & OpTy < ' tcx > , // LPVOID
381+ buffer_size : & OpTy < ' tcx > , // DWORD
382+ ) -> InterpResult < ' tcx , Scalar > {
383+ // ^ Returns BOOL (i32 on Windows)
384+ let this = self . eval_context_mut ( ) ;
385+ this. assert_target_os ( Os :: Windows , "SetFileInformationByHandle" ) ;
386+ this. check_no_isolation ( "`SetFileInformationByHandle`" ) ?;
387+
388+ let class = this. read_scalar ( class) ?. to_u32 ( ) ?;
389+ let buffer_size = this. read_scalar ( buffer_size) ?. to_u32 ( ) ?;
390+ let file_information = this. read_pointer ( file_information) ?;
391+ this. check_ptr_access (
392+ file_information,
393+ Size :: from_bytes ( buffer_size) ,
394+ CheckInAllocMsg :: MemoryAccess ,
395+ ) ?;
396+
397+ let file = this. read_handle ( file, "SetFileInformationByHandle" ) ?;
398+ let Handle :: File ( fd_num) = file else { this. invalid_handle ( "SetFileInformationByHandle" ) ? } ;
399+ let Some ( desc) = this. machine . fds . get ( fd_num) else {
400+ this. invalid_handle ( "SetFileInformationByHandle" ) ?
401+ } ;
402+ let file = desc. downcast :: < FileHandle > ( ) . ok_or_else ( || {
403+ err_unsup_format ! (
404+ "`SetFileInformationByHandle` is only supported on file-backed file descriptors"
405+ )
406+ } ) ?;
407+
408+ if class == this. eval_windows_u32 ( "c" , "FileEndOfFileInfo" ) {
409+ let place = this
410+ . ptr_to_mplace ( file_information, this. windows_ty_layout ( "FILE_END_OF_FILE_INFO" ) ) ;
411+ let new_len =
412+ this. read_scalar ( & this. project_field_named ( & place, "EndOfFile" ) ?) ?. to_i64 ( ) ?;
413+ match file. file . set_len ( new_len. try_into ( ) . unwrap ( ) ) {
414+ Ok ( _) => interp_ok ( this. eval_windows ( "c" , "TRUE" ) ) ,
415+ Err ( e) => {
416+ this. set_last_error ( e) ?;
417+ interp_ok ( this. eval_windows ( "c" , "FALSE" ) )
418+ }
419+ }
420+ } else if class == this. eval_windows_u32 ( "c" , "FileAllocationInfo" ) {
421+ // On Windows, files are somewhat similar to a `Vec` in that they have a separate
422+ // "length" (called "EOF position") and "capacity" (called "allocation size").
423+ // Growing the allocation size is largely a performance hint which we can
424+ // ignore -- it can also be directly queried, but we currently do not support that.
425+ // So we only need to do something if this operation shrinks the allocation size
426+ // so far that it affects the EOF position.
427+ let place = this
428+ . ptr_to_mplace ( file_information, this. windows_ty_layout ( "FILE_ALLOCATION_INFO" ) ) ;
429+ let new_alloc_size: u64 = this
430+ . read_scalar ( & this. project_field_named ( & place, "AllocationSize" ) ?) ?
431+ . to_i64 ( ) ?
432+ . try_into ( )
433+ . unwrap ( ) ;
434+ let old_len = match file. file . metadata ( ) {
435+ Ok ( m) => m. len ( ) ,
436+ Err ( e) => {
437+ this. set_last_error ( e) ?;
438+ return interp_ok ( this. eval_windows ( "c" , "FALSE" ) ) ;
439+ }
440+ } ;
441+ if new_alloc_size < old_len {
442+ match file. file . set_len ( new_alloc_size) {
443+ Ok ( _) => interp_ok ( this. eval_windows ( "c" , "TRUE" ) ) ,
444+ Err ( e) => {
445+ this. set_last_error ( e) ?;
446+ interp_ok ( this. eval_windows ( "c" , "FALSE" ) )
447+ }
448+ }
449+ } else {
450+ interp_ok ( this. eval_windows ( "c" , "TRUE" ) )
451+ }
452+ } else {
453+ throw_unsup_format ! (
454+ "SetFileInformationByHandle: Unsupported `FileInformationClass` value {}" ,
455+ class
456+ )
457+ }
458+ }
459+
375460 fn DeleteFileW (
376461 & mut self ,
377462 file_name : & OpTy < ' tcx > , // LPCWSTR
0 commit comments