]> git.lizzy.rs Git - rust.git/commitdiff
Add shim for symbolic link creation
authorChristian Poveda <git@christianpoveda.xyz>
Mon, 6 Jan 2020 21:30:17 +0000 (16:30 -0500)
committerChristian Poveda <git@christianpoveda.xyz>
Mon, 6 Jan 2020 21:30:17 +0000 (16:30 -0500)
src/shims/foreign_items.rs
src/shims/fs.rs
tests/run-pass/fs.rs

index 07e3b7d7582650d37f0cb66b0a069bcb483034e4..6a2f42f8321507cf7e61c2fd1d81a2ea96f0dc4d 100644 (file)
@@ -494,6 +494,11 @@ 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)?;
index 8c8bd6f7bb97f651951cc354e73fe4f92c5ceab8..c5b753f3b6a245ffe8ab98ed4f0333a0117555a0 100644 (file)
@@ -276,6 +276,36 @@ 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(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>,
@@ -545,7 +575,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)
         };
 
index 85e39bc45112b0602032fada148730f29ad9d4eb..9e0428fb57c27513ea0e99da39f4986a53a73a83 100644 (file)
@@ -39,9 +39,24 @@ 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
+    let symlink_path = tmp.join("miri_test_fs_symlink.txt");
+    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();