@@ -269,25 +269,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
269
269
let this = self . eval_context_mut ( ) ;
270
270
271
271
if this. tcx . sess . target . target . target_os . to_lowercase ( ) != "macos" {
272
- throw_unsup_format ! ( "The `stat` shim is only only available for `macos` targets." )
272
+ throw_unsup_format ! ( "The `stat` shim is only available for `macos` targets." )
273
273
}
274
274
275
275
let path_scalar = this. read_scalar ( path_op) ?. not_undef ( ) ?;
276
276
let path: PathBuf = this. read_os_str_from_c_str ( path_scalar) ?. into ( ) ;
277
277
278
278
let buf = this. deref_operand ( buf_op) ?;
279
279
280
- let status = match FileStatus :: new ( this, path, false ) ? {
281
- Some ( status) => status,
280
+ // `stat` always follows symlinks. `lstat` is used to get symlink metadata.
281
+ let metadata = match FileMetadata :: new ( this, path, true ) ? {
282
+ Some ( metadata) => metadata,
282
283
None => return Ok ( -1 ) ,
283
284
} ;
284
285
285
286
// FIXME: use Scalar::to_u16
286
- let mode: u16 = status . mode . to_bits ( Size :: from_bits ( 16 ) ) ? as u16 ;
287
+ let mode: u16 = metadata . mode . to_bits ( Size :: from_bits ( 16 ) ) ? as u16 ;
287
288
288
- let ( access_sec, access_nsec) = status . accessed . unwrap_or ( ( 0 , 0 ) ) ;
289
- let ( created_sec, created_nsec) = status . created . unwrap_or ( ( 0 , 0 ) ) ;
290
- let ( modified_sec, modified_nsec) = status . modified . unwrap_or ( ( 0 , 0 ) ) ;
289
+ let ( access_sec, access_nsec) = metadata . accessed . unwrap_or ( ( 0 , 0 ) ) ;
290
+ let ( created_sec, created_nsec) = metadata . created . unwrap_or ( ( 0 , 0 ) ) ;
291
+ let ( modified_sec, modified_nsec) = metadata . modified . unwrap_or ( ( 0 , 0 ) ) ;
291
292
292
293
let dev_t_layout = this. libc_ty_layout ( "dev_t" ) ?;
293
294
let mode_t_layout = this. libc_ty_layout ( "mode_t" ) ?;
@@ -302,7 +303,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
302
303
let blksize_t_layout = this. libc_ty_layout ( "blksize_t" ) ?;
303
304
let uint32_t_layout = this. libc_ty_layout ( "uint32_t" ) ?;
304
305
305
- // We need to add 32 bits of padding after `st_rdev` if we are in a 64-bit platform.
306
+ // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform.
306
307
let pad_layout = if this. tcx . sess . target . ptr_width == 64 {
307
308
uint32_t_layout
308
309
} else {
@@ -326,7 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
326
327
immty_from_uint_checked ( 0u128 , long_layout) ?, // st_ctime_nsec
327
328
immty_from_uint_checked ( created_sec, time_t_layout) ?, // st_birthtime
328
329
immty_from_uint_checked ( created_nsec, long_layout) ?, // st_birthtime_nsec
329
- immty_from_uint_checked ( status . size , off_t_layout) ?, // st_size
330
+ immty_from_uint_checked ( metadata . size , off_t_layout) ?, // st_size
330
331
immty_from_uint_checked ( 0u128 , blkcnt_t_layout) ?, // st_blocks
331
332
immty_from_uint_checked ( 0u128 , blksize_t_layout) ?, // st_blksize
332
333
immty_from_uint_checked ( 0u128 , uint32_t_layout) ?, // st_flags
@@ -351,7 +352,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
351
352
this. check_no_isolation ( "statx" ) ?;
352
353
353
354
if this. tcx . sess . target . target . target_os . to_lowercase ( ) != "linux" {
354
- throw_unsup_format ! ( "The `statx` shim is only only available for `linux` targets." )
355
+ throw_unsup_format ! ( "The `statx` shim is only available for `linux` targets." )
355
356
}
356
357
357
358
let statxbuf_scalar = this. read_scalar ( statxbuf_op) ?. not_undef ( ) ?;
@@ -413,34 +414,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
413
414
// symbolic links.
414
415
let follow_symlink = flags & this. eval_libc ( "AT_SYMLINK_NOFOLLOW" ) ?. to_i32 ( ) ? == 0 ;
415
416
416
- let status = match FileStatus :: new ( this, path, follow_symlink) ? {
417
- Some ( status ) => status ,
417
+ let metadata = match FileMetadata :: new ( this, path, follow_symlink) ? {
418
+ Some ( metadata ) => metadata ,
418
419
None => return Ok ( -1 ) ,
419
420
} ;
420
421
421
422
// The `mode` field specifies the type of the file and the permissions over the file for
422
423
// the owner, its group and other users. Given that we can only provide the file type
423
424
// without using platform specific methods, we only set the bits corresponding to the file
424
425
// type. This should be an `__u16` but `libc` provides its values as `u32`.
425
- let mode: u16 = status
426
+ let mode: u16 = metadata
426
427
. mode
427
428
. to_u32 ( ) ?
428
429
. try_into ( )
429
430
. unwrap_or_else ( |_| bug ! ( "libc contains bad value for constant" ) ) ;
430
431
431
432
// We need to set the corresponding bits of `mask` if the access, creation and modification
432
433
// times were available. Otherwise we let them be zero.
433
- let ( access_sec, access_nsec) = status . accessed . map ( |tup| {
434
+ let ( access_sec, access_nsec) = metadata . accessed . map ( |tup| {
434
435
mask |= this. eval_libc ( "STATX_ATIME" ) ?. to_u32 ( ) ?;
435
436
InterpResult :: Ok ( tup)
436
437
} ) . unwrap_or ( Ok ( ( 0 , 0 ) ) ) ?;
437
438
438
- let ( created_sec, created_nsec) = status . created . map ( |tup| {
439
+ let ( created_sec, created_nsec) = metadata . created . map ( |tup| {
439
440
mask |= this. eval_libc ( "STATX_BTIME" ) ?. to_u32 ( ) ?;
440
441
InterpResult :: Ok ( tup)
441
442
} ) . unwrap_or ( Ok ( ( 0 , 0 ) ) ) ?;
442
443
443
- let ( modified_sec, modified_nsec) = status . modified . map ( |tup| {
444
+ let ( modified_sec, modified_nsec) = metadata . modified . map ( |tup| {
444
445
mask |= this. eval_libc ( "STATX_MTIME" ) ?. to_u32 ( ) ?;
445
446
InterpResult :: Ok ( tup)
446
447
} ) . unwrap_or ( Ok ( ( 0 , 0 ) ) ) ?;
@@ -461,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
461
462
immty_from_uint_checked ( mode, __u16_layout) ?, // stx_mode
462
463
immty_from_uint_checked ( 0u128 , __u16_layout) ?, // statx padding
463
464
immty_from_uint_checked ( 0u128 , __u64_layout) ?, // stx_ino
464
- immty_from_uint_checked ( status . size , __u64_layout) ?, // stx_size
465
+ immty_from_uint_checked ( metadata . size , __u64_layout) ?, // stx_size
465
466
immty_from_uint_checked ( 0u128 , __u64_layout) ?, // stx_blocks
466
467
immty_from_uint_checked ( 0u128 , __u64_layout) ?, // stx_attributes
467
468
immty_from_uint_checked ( access_sec, __u64_layout) ?, // stx_atime.tv_sec
@@ -511,25 +512,27 @@ fn extract_sec_and_nsec<'tcx>(
511
512
} ) . transpose ( )
512
513
}
513
514
514
- struct FileStatus {
515
+ /// Stores a file's metadata in order to avoid code duplication in the different metadata related
516
+ /// shims.
517
+ struct FileMetadata {
515
518
mode : Scalar < Tag > ,
516
519
size : u64 ,
517
520
created : Option < ( u64 , u32 ) > ,
518
521
accessed : Option < ( u64 , u32 ) > ,
519
522
modified : Option < ( u64 , u32 ) > ,
520
523
}
521
524
522
- impl FileStatus {
525
+ impl FileMetadata {
523
526
fn new < ' tcx , ' mir > (
524
527
ecx : & mut MiriEvalContext < ' mir , ' tcx > ,
525
528
path : PathBuf ,
526
529
follow_symlink : bool
527
- ) -> InterpResult < ' tcx , Option < FileStatus > > {
530
+ ) -> InterpResult < ' tcx , Option < FileMetadata > > {
528
531
let metadata = if follow_symlink {
532
+ std:: fs:: metadata ( path)
533
+ } else {
529
534
// FIXME: metadata for symlinks need testing.
530
535
std:: fs:: symlink_metadata ( path)
531
- } else {
532
- std:: fs:: metadata ( path)
533
536
} ;
534
537
535
538
let metadata = match metadata {
@@ -559,6 +562,6 @@ impl FileStatus {
559
562
let modified = extract_sec_and_nsec ( metadata. modified ( ) ) ?;
560
563
561
564
// FIXME: Provide more fields using platform specific methods.
562
- Ok ( Some ( FileStatus { mode, size, created, accessed, modified } ) )
565
+ Ok ( Some ( FileMetadata { mode, size, created, accessed, modified } ) )
563
566
}
564
567
}
0 commit comments