@@ -494,9 +494,65 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
494
494
fn GetCurrentProcessId ( & mut self ) -> InterpResult < ' tcx , u32 > {
495
495
let this = self . eval_context_mut ( ) ;
496
496
this. assert_target_os ( "windows" , "GetCurrentProcessId" ) ;
497
-
498
497
this. check_no_isolation ( "`GetCurrentProcessId`" ) ?;
499
498
500
499
Ok ( std:: process:: id ( ) )
501
500
}
501
+
502
+ #[ allow( non_snake_case) ]
503
+ fn GetUserProfileDirectoryW (
504
+ & mut self ,
505
+ token : & OpTy < ' tcx , Provenance > , // HANDLE
506
+ buf : & OpTy < ' tcx , Provenance > , // LPWSTR
507
+ size : & OpTy < ' tcx , Provenance > , // LPDWORD
508
+ ) -> InterpResult < ' tcx , Scalar < Provenance > > // returns BOOL
509
+ {
510
+ let this = self . eval_context_mut ( ) ;
511
+ this. assert_target_os ( "windows" , "GetUserProfileDirectoryW" ) ;
512
+ this. check_no_isolation ( "`GetUserProfileDirectoryW`" ) ?;
513
+
514
+ let token = this. read_target_isize ( token) ?;
515
+ let buf = this. read_pointer ( buf) ?;
516
+ let size = this. deref_pointer ( size) ?;
517
+
518
+ if token != -4 {
519
+ throw_unsup_format ! (
520
+ "GetUserProfileDirectoryW: only CURRENT_PROCESS_TOKEN is supported"
521
+ ) ;
522
+ }
523
+
524
+ // See <https://learn.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-getuserprofiledirectoryw> for docs.
525
+ Ok ( match directories:: UserDirs :: new ( ) {
526
+ Some ( dirs) => {
527
+ let home = dirs. home_dir ( ) ;
528
+ let size_avail = if this. ptr_is_null ( size. ptr ( ) ) ? {
529
+ 0 // if the buf pointer is null, we can't write to it; `size` will be updated to the required length
530
+ } else {
531
+ this. read_scalar ( & size) ?. to_u32 ( ) ?
532
+ } ;
533
+ // Of course we cannot use `windows_check_buffer_size` here since this uses
534
+ // a different method for dealing with a too-small buffer than the other functions...
535
+ let ( success, len) = this. write_path_to_wide_str (
536
+ home,
537
+ buf,
538
+ size_avail. into ( ) ,
539
+ /*truncate*/ false ,
540
+ ) ?;
541
+ // The Windows docs just say that this is written on failure. But std
542
+ // seems to rely on it always being written.
543
+ this. write_scalar ( Scalar :: from_u32 ( len. try_into ( ) . unwrap ( ) ) , & size) ?;
544
+ if success {
545
+ Scalar :: from_i32 ( 1 ) // return TRUE
546
+ } else {
547
+ this. set_last_error ( this. eval_windows ( "c" , "ERROR_INSUFFICIENT_BUFFER" ) ) ?;
548
+ Scalar :: from_i32 ( 0 ) // return FALSE
549
+ }
550
+ }
551
+ None => {
552
+ // We have to pick some error code.
553
+ this. set_last_error ( this. eval_windows ( "c" , "ERROR_BAD_USER_PROFILE" ) ) ?;
554
+ Scalar :: from_i32 ( 0 ) // return FALSE
555
+ }
556
+ } )
557
+ }
502
558
}
0 commit comments