@@ -345,7 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
345
345
346
346
let buf = this. deref_operand ( buf_op) ?;
347
347
348
- let metadata = match FileMetadata :: new ( this, path, follow_symlink) ? {
348
+ let metadata = match FileMetadata :: from_path ( this, path, follow_symlink) ? {
349
349
Some ( metadata) => metadata,
350
350
None => return Ok ( -1 ) ,
351
351
} ;
@@ -454,6 +454,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
454
454
this. read_scalar ( flags_op) ?. to_machine_isize ( & * this. tcx ) ?. try_into ( ) . map_err ( |e| {
455
455
err_unsup_format ! ( "Failed to convert pointer sized operand to integer: {}" , e)
456
456
} ) ?;
457
+ let empty_path_flag = flags & this. eval_libc ( "AT_EMPTY_PATH" ) ?. to_i32 ( ) ? != 0 ;
457
458
// `dirfd` should be a `c_int` but the `syscall` function provides an `isize`.
458
459
let dirfd: i32 =
459
460
this. read_scalar ( dirfd_op) ?. to_machine_isize ( & * this. tcx ) ?. try_into ( ) . map_err ( |e| {
@@ -463,7 +464,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
463
464
// to `dirfd` when the latter is `AT_FDCWD`. The behavior of `statx` with a relative path
464
465
// and a directory file descriptor other than `AT_FDCWD` is specified but it cannot be
465
466
// tested from `libstd`. If you found this error, please open an issue reporting it.
466
- if !( path. is_absolute ( ) || dirfd == this. eval_libc_i32 ( "AT_FDCWD" ) ?) {
467
+ if !(
468
+ path. is_absolute ( ) ||
469
+ dirfd == this. eval_libc_i32 ( "AT_FDCWD" ) ? ||
470
+ ( path. as_os_str ( ) . is_empty ( ) && empty_path_flag)
471
+ ) {
467
472
throw_unsup_format ! (
468
473
"Using statx with a relative path and a file descriptor different from `AT_FDCWD` is not supported"
469
474
)
@@ -480,7 +485,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
480
485
// symbolic links.
481
486
let follow_symlink = flags & this. eval_libc ( "AT_SYMLINK_NOFOLLOW" ) ?. to_i32 ( ) ? == 0 ;
482
487
483
- let metadata = match FileMetadata :: new ( this, path, follow_symlink) ? {
488
+ // If the path is empty, and the AT_EMPTY_PATH flag is set, we query the open file
489
+ // represented by dirfd, whether it's a directory or otherwise.
490
+ let metadata = if path. as_os_str ( ) . is_empty ( ) && empty_path_flag {
491
+ FileMetadata :: from_fd ( this, dirfd) ?
492
+ } else {
493
+ FileMetadata :: from_path ( this, path, follow_symlink) ?
494
+ } ;
495
+ let metadata = match metadata {
484
496
Some ( metadata) => metadata,
485
497
None => return Ok ( -1 ) ,
486
498
} ;
@@ -589,7 +601,7 @@ struct FileMetadata {
589
601
}
590
602
591
603
impl FileMetadata {
592
- fn new < ' tcx , ' mir > (
604
+ fn from_path < ' tcx , ' mir > (
593
605
ecx : & mut MiriEvalContext < ' mir , ' tcx > ,
594
606
path : PathBuf ,
595
607
follow_symlink : bool
@@ -600,6 +612,27 @@ impl FileMetadata {
600
612
std:: fs:: symlink_metadata ( path)
601
613
} ;
602
614
615
+ FileMetadata :: from_meta ( ecx, metadata)
616
+ }
617
+
618
+ fn from_fd < ' tcx , ' mir > (
619
+ ecx : & mut MiriEvalContext < ' mir , ' tcx > ,
620
+ fd : i32 ,
621
+ ) -> InterpResult < ' tcx , Option < FileMetadata > > {
622
+ let option = ecx. machine . file_handler . handles . get ( & fd) ;
623
+ let handle = match option {
624
+ Some ( handle) => handle,
625
+ None => return ecx. handle_not_found ( ) . map ( |_: i32 | None ) ,
626
+ } ;
627
+ let metadata = handle. file . metadata ( ) ;
628
+
629
+ FileMetadata :: from_meta ( ecx, metadata)
630
+ }
631
+
632
+ fn from_meta < ' tcx , ' mir > (
633
+ ecx : & mut MiriEvalContext < ' mir , ' tcx > ,
634
+ metadata : Result < std:: fs:: Metadata , std:: io:: Error > ,
635
+ ) -> InterpResult < ' tcx , Option < FileMetadata > > {
603
636
let metadata = match metadata {
604
637
Ok ( metadata) => metadata,
605
638
Err ( e) => {
0 commit comments