@@ -276,24 +276,76 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
276
276
this. try_unwrap_io_result ( result)
277
277
}
278
278
279
+ fn symlink (
280
+ & mut self ,
281
+ target_op : OpTy < ' tcx , Tag > ,
282
+ linkpath_op : OpTy < ' tcx , Tag >
283
+ ) -> InterpResult < ' tcx , i32 > {
284
+ #[ cfg( target_family = "unix" ) ]
285
+ fn create_link ( src : PathBuf , dst : PathBuf ) -> std:: io:: Result < ( ) > {
286
+ std:: os:: unix:: fs:: symlink ( src, dst)
287
+ }
288
+
289
+ #[ cfg( target_family = "windows" ) ]
290
+ fn create_link ( src : PathBuf , dst : PathBuf ) -> std:: io:: Result < ( ) > {
291
+ use std:: os:: windows:: fs;
292
+ if src. is_dir ( ) {
293
+ fs:: symlink_dir ( src, dst)
294
+ } else {
295
+ fs:: symlink_file ( src, dst)
296
+ }
297
+ }
298
+
299
+ let this = self . eval_context_mut ( ) ;
300
+
301
+ this. check_no_isolation ( "symlink" ) ?;
302
+
303
+ let target = this. read_os_str_from_c_str ( this. read_scalar ( target_op) ?. not_undef ( ) ?) ?. into ( ) ;
304
+ let linkpath = this. read_os_str_from_c_str ( this. read_scalar ( linkpath_op) ?. not_undef ( ) ?) ?. into ( ) ;
305
+
306
+ this. try_unwrap_io_result ( create_link ( target, linkpath) . map ( |_| 0 ) )
307
+ }
308
+
279
309
fn stat (
280
310
& mut self ,
281
311
path_op : OpTy < ' tcx , Tag > ,
282
312
buf_op : OpTy < ' tcx , Tag > ,
283
313
) -> InterpResult < ' tcx , i32 > {
284
314
let this = self . eval_context_mut ( ) ;
315
+ this. check_no_isolation ( "stat" ) ?;
316
+ // `stat` always follows symlinks.
317
+ this. stat_or_lstat ( true , path_op, buf_op)
318
+ }
319
+
320
+ // `lstat` is used to get symlink metadata.
321
+ fn lstat (
322
+ & mut self ,
323
+ path_op : OpTy < ' tcx , Tag > ,
324
+ buf_op : OpTy < ' tcx , Tag > ,
325
+ ) -> InterpResult < ' tcx , i32 > {
326
+ let this = self . eval_context_mut ( ) ;
327
+ this. check_no_isolation ( "lstat" ) ?;
328
+ this. stat_or_lstat ( false , path_op, buf_op)
329
+ }
330
+
331
+ fn stat_or_lstat (
332
+ & mut self ,
333
+ follow_symlink : bool ,
334
+ path_op : OpTy < ' tcx , Tag > ,
335
+ buf_op : OpTy < ' tcx , Tag > ,
336
+ ) -> InterpResult < ' tcx , i32 > {
337
+ let this = self . eval_context_mut ( ) ;
285
338
286
339
if this. tcx . sess . target . target . target_os . to_lowercase ( ) != "macos" {
287
- throw_unsup_format ! ( "The `stat` shim is only available for `macos` targets." )
340
+ throw_unsup_format ! ( "The `stat` and `lstat` shims are only available for `macos` targets." )
288
341
}
289
342
290
343
let path_scalar = this. read_scalar ( path_op) ?. not_undef ( ) ?;
291
344
let path: PathBuf = this. read_os_str_from_c_str ( path_scalar) ?. into ( ) ;
292
345
293
346
let buf = this. deref_operand ( buf_op) ?;
294
347
295
- // `stat` always follows symlinks. `lstat` is used to get symlink metadata.
296
- let metadata = match FileMetadata :: new ( this, path, true ) ? {
348
+ let metadata = match FileMetadata :: new ( this, path, follow_symlink) ? {
297
349
Some ( metadata) => metadata,
298
350
None => return Ok ( -1 ) ,
299
351
} ;
@@ -545,7 +597,6 @@ impl FileMetadata {
545
597
let metadata = if follow_symlink {
546
598
std:: fs:: metadata ( path)
547
599
} else {
548
- // FIXME: metadata for symlinks need testing.
549
600
std:: fs:: symlink_metadata ( path)
550
601
} ;
551
602
0 commit comments