Skip to content

Commit 4a1dbc7

Browse files
committed
Add shim for symbolic link creation
1 parent f3c267d commit 4a1dbc7

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

src/shims/foreign_items.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
494494
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
495495
}
496496

497+
"symlink" => {
498+
let result = this.symlink(args[0], args[1])?;
499+
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
500+
}
501+
497502
"stat$INODE64" => {
498503
let result = this.stat(args[0], args[1])?;
499504
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;

src/shims/fs.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,36 @@ 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(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>,
@@ -545,7 +575,6 @@ impl FileMetadata {
545575
let metadata = if follow_symlink {
546576
std::fs::metadata(path)
547577
} else {
548-
// FIXME: metadata for symlinks need testing.
549578
std::fs::symlink_metadata(path)
550579
};
551580

tests/run-pass/fs.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,24 @@ fn main() {
3939
// Test that metadata of an absolute path is correct.
4040
test_metadata(bytes, &path).unwrap();
4141
// Test that metadata of a relative path is correct.
42-
std::env::set_current_dir(tmp).unwrap();
42+
std::env::set_current_dir(&tmp).unwrap();
4343
test_metadata(bytes, &filename).unwrap();
4444

45+
// Creating a symbolic link should succeed
46+
let symlink_path = tmp.join("miri_test_fs_symlink.txt");
47+
std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
48+
// Test that the symbolic link has the same contents as the file.
49+
let mut symlink_file = File::open(&symlink_path).unwrap();
50+
let mut contents = Vec::new();
51+
symlink_file.read_to_end(&mut contents).unwrap();
52+
assert_eq!(bytes, contents.as_slice());
53+
// Test that metadata of a symbolic link is correct.
54+
test_metadata(bytes, &symlink_path).unwrap();
55+
// Test that the metadata of a symbolic link is correct when not following it.
56+
assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
57+
// Removing symbolic link should succeed.
58+
remove_file(&symlink_path).unwrap();
59+
4560
// Removing file should succeed.
4661
remove_file(&path).unwrap();
4762

0 commit comments

Comments
 (0)