Implement ftruncate64/ftruncate for File::set_len

This commit is contained in:
David Cook 2020-04-21 21:17:54 -05:00
parent 8d9db57a0d
commit 54897f66f8
4 changed files with 65 additions and 0 deletions

View file

@ -34,6 +34,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let result = this.linux_readdir64_r(args[0], args[1], args[2])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"ftruncate64" => {
let result = this.ftruncate64(args[0], args[1])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
// Linux-only
"posix_fadvise" => {
let _fd = this.read_scalar(args[0])?.to_i32()?;

View file

@ -44,6 +44,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let result = this.macos_readdir_r(args[0], args[1], args[2])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"ftruncate" => {
let result = this.ftruncate64(args[0], args[1])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
// Environment related shims
"_NSGetEnviron" => {

View file

@ -1062,6 +1062,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.handle_not_found()
}
}
fn ftruncate64(
&mut self, fd_op: OpTy<'tcx, Tag>,
length_op: OpTy<'tcx, Tag>,
) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
this.check_no_isolation("ftruncate64")?;
let fd = this.read_scalar(fd_op)?.to_i32()?;
let length = this.read_scalar(length_op)?.to_i64()?;
if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) {
if *writable {
if let Ok(length) = length.try_into() {
let result = file.set_len(length);
this.try_unwrap_io_result(result.map(|_| 0i32))
} else {
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
Ok(-1)
}
} else {
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
Ok(-1)
}
} else {
this.handle_not_found()
}
}
}
/// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when

View file

@ -13,6 +13,7 @@ fn main() {
test_file_create_new();
test_seek();
test_metadata();
test_file_set_len();
test_symlink();
test_errors();
test_rename();
@ -155,6 +156,32 @@ fn test_metadata() {
remove_file(&path).unwrap();
}
fn test_file_set_len() {
let bytes = b"Hello, World!\n";
let path = prepare_with_content("miri_test_fs_set_len.txt", bytes);
// Test extending the file
let mut file = OpenOptions::new().read(true).write(true).open(&path).unwrap();
let bytes_extended = b"Hello, World!\n\x00\x00\x00\x00\x00\x00";
file.set_len(20).unwrap();
let mut contents = Vec::new();
file.read_to_end(&mut contents).unwrap();
assert_eq!(bytes_extended, contents.as_slice());
// Test truncating the file
file.seek(SeekFrom::Start(0)).unwrap();
file.set_len(10).unwrap();
let mut contents = Vec::new();
file.read_to_end(&mut contents).unwrap();
assert_eq!(&bytes[..10], contents.as_slice());
// Can't use set_len on a file not opened for writing
let file = OpenOptions::new().read(true).open(&path).unwrap();
assert_eq!(ErrorKind::InvalidInput, file.set_len(14).unwrap_err().kind());
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);