Add file sync shims
Adds implementations for fsync, fdatasync, and sync_file_range
This commit is contained in:
parent
ac09e2f5cd
commit
87c4694448
@ -136,6 +136,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
// "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" => {
|
||||
|
@ -54,6 +54,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
// 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" => {
|
||||
|
@ -375,6 +375,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
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 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user