@@ -494,9 +494,65 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
494494 fn GetCurrentProcessId ( & mut self ) -> InterpResult < ' tcx , u32 > {
495495 let this = self . eval_context_mut ( ) ;
496496 this. assert_target_os ( "windows" , "GetCurrentProcessId" ) ;
497-
498497 this. check_no_isolation ( "`GetCurrentProcessId`" ) ?;
499498
500499 Ok ( std:: process:: id ( ) )
501500 }
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+ }
502558}
0 commit comments