Auto merge of #1143 - christianpoveda:symlink-shim, r=RalfJung
Add shim for symbolic link creation r? @RalfJung
This commit is contained in:
commit
b4c54b4641
@ -494,11 +494,21 @@ fn emulate_foreign_item(
|
||||
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
|
||||
}
|
||||
|
||||
"symlink" => {
|
||||
let result = this.symlink(args[0], args[1])?;
|
||||
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
|
||||
}
|
||||
|
||||
"stat$INODE64" => {
|
||||
let result = this.stat(args[0], args[1])?;
|
||||
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
|
||||
}
|
||||
|
||||
"lstat$INODE64" => {
|
||||
let result = this.lstat(args[0], args[1])?;
|
||||
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
|
||||
}
|
||||
|
||||
"clock_gettime" => {
|
||||
let result = this.clock_gettime(args[0], args[1])?;
|
||||
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
|
||||
|
@ -276,15 +276,68 @@ fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||
this.try_unwrap_io_result(result)
|
||||
}
|
||||
|
||||
fn symlink(
|
||||
&mut self,
|
||||
target_op: OpTy<'tcx, Tag>,
|
||||
linkpath_op: OpTy<'tcx, Tag>
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
#[cfg(target_family = "unix")]
|
||||
fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> {
|
||||
std::os::unix::fs::symlink(src, dst)
|
||||
}
|
||||
|
||||
#[cfg(target_family = "windows")]
|
||||
fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> {
|
||||
use std::os::windows::fs;
|
||||
if src.is_dir() {
|
||||
fs::symlink_dir(src, dst)
|
||||
} else {
|
||||
fs::symlink_file(src, dst)
|
||||
}
|
||||
}
|
||||
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("symlink")?;
|
||||
|
||||
let target = this.read_os_str_from_c_str(this.read_scalar(target_op)?.not_undef()?)?.into();
|
||||
let linkpath = this.read_os_str_from_c_str(this.read_scalar(linkpath_op)?.not_undef()?)?.into();
|
||||
|
||||
this.try_unwrap_io_result(create_link(target, linkpath).map(|_| 0))
|
||||
}
|
||||
|
||||
fn stat(
|
||||
&mut self,
|
||||
path_op: OpTy<'tcx, Tag>,
|
||||
buf_op: OpTy<'tcx, Tag>,
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
this.check_no_isolation("stat")?;
|
||||
// `stat` always follows symlinks.
|
||||
this.stat_or_lstat(true, path_op, buf_op)
|
||||
}
|
||||
|
||||
// `lstat` is used to get symlink metadata.
|
||||
fn lstat(
|
||||
&mut self,
|
||||
path_op: OpTy<'tcx, Tag>,
|
||||
buf_op: OpTy<'tcx, Tag>,
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
this.check_no_isolation("lstat")?;
|
||||
this.stat_or_lstat(false, path_op, buf_op)
|
||||
}
|
||||
|
||||
fn stat_or_lstat(
|
||||
&mut self,
|
||||
follow_symlink: bool,
|
||||
path_op: OpTy<'tcx, Tag>,
|
||||
buf_op: OpTy<'tcx, Tag>,
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" {
|
||||
throw_unsup_format!("The `stat` shim is only available for `macos` targets.")
|
||||
throw_unsup_format!("The `stat` and `lstat` shims are only available for `macos` targets.")
|
||||
}
|
||||
|
||||
let path_scalar = this.read_scalar(path_op)?.not_undef()?;
|
||||
@ -292,8 +345,7 @@ fn stat(
|
||||
|
||||
let buf = this.deref_operand(buf_op)?;
|
||||
|
||||
// `stat` always follows symlinks. `lstat` is used to get symlink metadata.
|
||||
let metadata = match FileMetadata::new(this, path, true)? {
|
||||
let metadata = match FileMetadata::new(this, path, follow_symlink)? {
|
||||
Some(metadata) => metadata,
|
||||
None => return Ok(-1),
|
||||
};
|
||||
@ -545,7 +597,6 @@ fn new<'tcx, 'mir>(
|
||||
let metadata = if follow_symlink {
|
||||
std::fs::metadata(path)
|
||||
} else {
|
||||
// FIXME: metadata for symlinks need testing.
|
||||
std::fs::symlink_metadata(path)
|
||||
};
|
||||
|
||||
|
@ -19,7 +19,11 @@ fn main() {
|
||||
let tmp = std::env::temp_dir();
|
||||
let filename = PathBuf::from("miri_test_fs.txt");
|
||||
let path = tmp.join(&filename);
|
||||
let symlink_path = tmp.join("miri_test_fs_symlink.txt");
|
||||
let bytes = b"Hello, World!\n";
|
||||
// Clean the paths for robustness.
|
||||
remove_file(&path).ok();
|
||||
remove_file(&symlink_path).ok();
|
||||
|
||||
// Test creating, writing and closing a file (closing is tested when `file` is dropped).
|
||||
let mut file = File::create(&path).unwrap();
|
||||
@ -39,9 +43,23 @@ fn main() {
|
||||
// Test that metadata of an absolute path is correct.
|
||||
test_metadata(bytes, &path).unwrap();
|
||||
// Test that metadata of a relative path is correct.
|
||||
std::env::set_current_dir(tmp).unwrap();
|
||||
std::env::set_current_dir(&tmp).unwrap();
|
||||
test_metadata(bytes, &filename).unwrap();
|
||||
|
||||
// Creating a symbolic link should succeed.
|
||||
std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
|
||||
// Test that the symbolic link has the same contents as the file.
|
||||
let mut symlink_file = File::open(&symlink_path).unwrap();
|
||||
let mut contents = Vec::new();
|
||||
symlink_file.read_to_end(&mut contents).unwrap();
|
||||
assert_eq!(bytes, contents.as_slice());
|
||||
// Test that metadata of a symbolic link is correct.
|
||||
test_metadata(bytes, &symlink_path).unwrap();
|
||||
// Test that the metadata of a symbolic link is correct when not following it.
|
||||
assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
|
||||
// Removing symbolic link should succeed.
|
||||
remove_file(&symlink_path).unwrap();
|
||||
|
||||
// Removing file should succeed.
|
||||
remove_file(&path).unwrap();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user