Implement ftruncate64/ftruncate for File::set_len
This commit is contained in:
parent
8d9db57a0d
commit
54897f66f8
4 changed files with 65 additions and 0 deletions
|
|
@ -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()?;
|
||||
|
|
|
|||
|
|
@ -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" => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue