@@ -276,24 +276,76 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
276276 this. try_unwrap_io_result ( result)
277277 }
278278
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+
279309 fn stat (
280310 & mut self ,
281311 path_op : OpTy < ' tcx , Tag > ,
282312 buf_op : OpTy < ' tcx , Tag > ,
283313 ) -> InterpResult < ' tcx , i32 > {
284314 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 ( ) ;
285338
286339 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." )
288341 }
289342
290343 let path_scalar = this. read_scalar ( path_op) ?. not_undef ( ) ?;
291344 let path: PathBuf = this. read_os_str_from_c_str ( path_scalar) ?. into ( ) ;
292345
293346 let buf = this. deref_operand ( buf_op) ?;
294347
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) ? {
297349 Some ( metadata) => metadata,
298350 None => return Ok ( -1 ) ,
299351 } ;
@@ -545,7 +597,6 @@ impl FileMetadata {
545597 let metadata = if follow_symlink {
546598 std:: fs:: metadata ( path)
547599 } else {
548- // FIXME: metadata for symlinks need testing.
549600 std:: fs:: symlink_metadata ( path)
550601 } ;
551602
0 commit comments