]> git.lizzy.rs Git - rust.git/commitdiff
Add file sync shims
authorDavid Cook <divergentdave@gmail.com>
Wed, 22 Apr 2020 03:01:40 +0000 (22:01 -0500)
committerDavid Cook <divergentdave@gmail.com>
Mon, 18 May 2020 03:10:40 +0000 (22:10 -0500)
Adds implementations for fsync, fdatasync, and sync_file_range

src/shims/foreign_items/posix.rs
src/shims/foreign_items/posix/linux.rs
src/shims/fs.rs
tests/run-pass/fs.rs
tests/run-pass/libc.rs

index 951a40293b72d834615b25b5e03f8808b3a4bc9f..6311f0a4a9fc4c2f5e48437213b664864d3855cf 100644 (file)
@@ -136,6 +136,14 @@ fn emulate_foreign_item_by_name(
                 // "lseek" is only used on macOS which is 64bit-only, so `i64` always works.
                 this.write_scalar(Scalar::from_i64(result), dest)?;
             }
+            "fsync" => {
+                let result = this.fsync(args[0])?;
+                this.write_scalar(Scalar::from_i32(result), dest)?;
+            }
+            "fdatasync" => {
+                let result = this.fdatasync(args[0])?;
+                this.write_scalar(Scalar::from_i32(result), dest)?;
+            }
 
             // Allocation
             "posix_memalign" => {
index e0f54cac1570a7846f33e989b28c156fbf1ef466..16d7d059e73b214e7918bbe2d169a563c3007c23 100644 (file)
@@ -54,6 +54,11 @@ fn emulate_foreign_item_by_name(
                 // fadvise is only informational, we can ignore it.
                 this.write_null(dest)?;
             }
+            // Linux-only
+            "sync_file_range" => {
+                let result = this.sync_file_range(args[0], args[1], args[2], args[3])?;
+                this.write_scalar(Scalar::from_i32(result), dest)?;
+            }
 
             // Time related shims
             "clock_gettime" => {
index 8613f6bb0994e730c1fc0b2bc3465840f43d430f..b7579f6cb732e5f0ead25132c398551658c32db8 100644 (file)
@@ -375,6 +375,15 @@ fn fcntl(
                 fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable }, start)
             });
             this.try_unwrap_io_result(fd_result)
+        } else if this.tcx.sess.target.target.target_os == "macos"
+            && cmd == this.eval_libc_i32("F_FULLFSYNC")?
+        {
+            if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) {
+                let result = file.sync_all();
+                this.try_unwrap_io_result(result.map(|_| 0i32))
+            } else {
+                this.handle_not_found()
+            }
         } else {
             throw_unsup_format!("the {:#x} command is not supported for `fcntl`)", cmd);
         }
@@ -1103,6 +1112,59 @@ fn ftruncate64(
             this.handle_not_found()
         }
     }
+
+    fn fsync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
+        let this = self.eval_context_mut();
+
+        this.check_no_isolation("fsync")?;
+
+        let fd = this.read_scalar(fd_op)?.to_i32()?;
+        if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) {
+            let result = file.sync_all();
+            this.try_unwrap_io_result(result.map(|_| 0i32))
+        } else {
+            this.handle_not_found()
+        }
+    }
+
+    fn fdatasync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
+        let this = self.eval_context_mut();
+
+        this.check_no_isolation("fdatasync")?;
+
+        let fd = this.read_scalar(fd_op)?.to_i32()?;
+        if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) {
+            let result = file.sync_data();
+            this.try_unwrap_io_result(result.map(|_| 0i32))
+        } else {
+            this.handle_not_found()
+        }
+    }
+
+    fn sync_file_range(
+        &mut self,
+        fd_op: OpTy<'tcx, Tag>,
+        offset_op: OpTy<'tcx, Tag>,
+        nbytes_op: OpTy<'tcx, Tag>,
+        flags_op: OpTy<'tcx, Tag>,
+    ) -> InterpResult<'tcx, i32> {
+        let this = self.eval_context_mut();
+
+        this.check_no_isolation("sync_file_range")?;
+
+        let fd = this.read_scalar(fd_op)?.to_i32()?;
+        let _offset = this.read_scalar(offset_op)?.to_i64()?;
+        let _nbytes = this.read_scalar(nbytes_op)?.to_i64()?;
+        let _flags = this.read_scalar(flags_op)?.to_u32()?;
+        if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) {
+            // In the interest of host compatibility, we conservatively ignore
+            // offset, nbytes, and flags, and sync the entire file.
+            let result = file.sync_data();
+            this.try_unwrap_io_result(result.map(|_| 0i32))
+        } else {
+            this.handle_not_found()
+        }
+    }
 }
 
 /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when
index 1a139de8148ae07ac52c5cc91b59baef6e300c61..df022a7c70d8ee59195c860a08043147d105489e 100644 (file)
@@ -14,6 +14,8 @@ fn main() {
     test_seek();
     test_metadata();
     test_file_set_len();
+    test_file_sync_all();
+    test_file_sync_data();
     test_symlink();
     test_errors();
     test_rename();
@@ -182,6 +184,28 @@ fn test_file_set_len() {
     remove_file(&path).unwrap();
 }
 
+fn test_file_sync_all() {
+    let bytes = b"Hello, World!\n";
+    let path = prepare_with_content("miri_test_fs_sync_all.txt", bytes);
+
+    // Test that we can call sync_all (can't readily test effects of this operation)
+    let file = File::open(&path).unwrap();
+    file.sync_all().unwrap();
+
+    remove_file(&path).unwrap();
+}
+
+fn test_file_sync_data() {
+    let bytes = b"Hello, World!\n";
+    let path = prepare_with_content("miri_test_fs_sync_data.txt", bytes);
+
+    // Test that we can call sync_data (can't readily test effects of this operation)
+    let file = File::open(&path).unwrap();
+    file.sync_data().unwrap();
+
+    remove_file(&path).unwrap();
+}
+
 fn test_symlink() {
     let bytes = b"Hello, World!\n";
     let path = prepare_with_content("miri_test_fs_link_target.txt", bytes);
index 04ca5c0b3b1a924cc91d1942e1f1b40dcff5c51e..5897c46f63755b4cea97961f08b7bdebb16884ea 100644 (file)
@@ -17,7 +17,7 @@ fn test_posix_fadvise() {
     use std::io::Write;
     use std::os::unix::io::AsRawFd;
 
-    let path = tmp().join("miri_test_libc.txt");
+    let path = tmp().join("miri_test_libc_posix_fadvise.txt");
     // Cleanup before test
     remove_file(&path).ok();
 
@@ -40,6 +40,37 @@ fn test_posix_fadvise() {
     assert_eq!(result, 0);
 }
 
+#[cfg(target_os = "linux")]
+fn test_sync_file_range() {
+    use std::fs::{remove_file, File};
+    use std::io::Write;
+    use std::os::unix::io::AsRawFd;
+
+    let path = tmp().join("miri_test_libc_sync_file_range.txt");
+    // Cleanup before test
+    remove_file(&path).ok();
+
+    // Write to a file
+    let mut file = File::create(&path).unwrap();
+    let bytes = b"Hello, World!\n";
+    file.write(bytes).unwrap();
+
+    // Test calling sync_file_range on a file.
+    let result = unsafe {
+        libc::sync_file_range(
+            file.as_raw_fd(),
+            0,
+            0,
+            libc::SYNC_FILE_RANGE_WAIT_BEFORE
+                | libc::SYNC_FILE_RANGE_WRITE
+                | libc::SYNC_FILE_RANGE_WAIT_AFTER,
+        )
+    };
+    drop(file);
+    remove_file(&path).unwrap();
+    assert_eq!(result, 0);
+}
+
 fn test_mutex_libc_init_recursive() {
     unsafe {
         let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed();
@@ -169,6 +200,9 @@ fn main() {
     #[cfg(target_os = "linux")]
     test_posix_fadvise();
 
+    #[cfg(target_os = "linux")]
+    test_sync_file_range();
+
     test_mutex_libc_init_recursive();
     test_mutex_libc_init_normal();
     test_mutex_libc_init_errorcheck();