Skip to content

Commit f9615bf

Browse files
committed
Auto merge of #1159 - divergentdave:shim-seek, r=RalfJung
Add shim for seeking files This adds a shim for `lseek64` (`lseek` on macOS). This enables the use of `<File as Seek>::seek`. Testing is included.
2 parents e3cfb61 + 98a1cac commit f9615bf

File tree

3 files changed

+60
-2
lines changed

3 files changed

+60
-2
lines changed

src/shims/foreign_items.rs

+7
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
489489
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
490490
}
491491

492+
| "lseek64"
493+
| "lseek"
494+
=> {
495+
let result = this.lseek64(args[0], args[1], args[2])?;
496+
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
497+
}
498+
492499
"unlink" => {
493500
let result = this.unlink(args[0])?;
494501
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;

src/shims/fs.rs

+35-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::HashMap;
22
use std::convert::{TryFrom, TryInto};
33
use std::fs::{remove_file, File, OpenOptions};
4-
use std::io::{Read, Write};
4+
use std::io::{Read, Seek, SeekFrom, Write};
55
use std::path::PathBuf;
66
use std::time::SystemTime;
77

@@ -264,6 +264,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
264264
}
265265
}
266266

267+
fn lseek64(
268+
&mut self,
269+
fd_op: OpTy<'tcx, Tag>,
270+
offset_op: OpTy<'tcx, Tag>,
271+
whence_op: OpTy<'tcx, Tag>,
272+
) -> InterpResult<'tcx, i64> {
273+
let this = self.eval_context_mut();
274+
275+
this.check_no_isolation("lseek64")?;
276+
277+
let fd = this.read_scalar(fd_op)?.to_i32()?;
278+
let offset = this.read_scalar(offset_op)?.to_i64()?;
279+
let whence = this.read_scalar(whence_op)?.to_i32()?;
280+
281+
let seek_from = if whence == this.eval_libc_i32("SEEK_SET")? {
282+
SeekFrom::Start(offset as u64)
283+
} else if whence == this.eval_libc_i32("SEEK_CUR")? {
284+
SeekFrom::Current(offset)
285+
} else if whence == this.eval_libc_i32("SEEK_END")? {
286+
SeekFrom::End(offset)
287+
} else {
288+
let einval = this.eval_libc("EINVAL")?;
289+
this.set_last_error(einval)?;
290+
return Ok(-1);
291+
};
292+
293+
if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) {
294+
let result = handle.file.seek(seek_from).map(|offset| offset as i64);
295+
this.try_unwrap_io_result(result)
296+
} else {
297+
this.handle_not_found()
298+
}
299+
}
300+
267301
fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
268302
let this = self.eval_context_mut();
269303

tests/run-pass/fs.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// compile-flags: -Zmiri-disable-isolation
33

44
use std::fs::{File, remove_file};
5-
use std::io::{Read, Write, ErrorKind, Result};
5+
use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom};
66
use std::path::{PathBuf, Path};
77

88
fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> {
@@ -42,6 +42,23 @@ fn main() {
4242
file.read_to_end(&mut contents).unwrap();
4343
assert_eq!(bytes, contents.as_slice());
4444

45+
// Test that seeking to the beginning and reading until EOF gets the text again.
46+
file.seek(SeekFrom::Start(0)).unwrap();
47+
let mut contents = Vec::new();
48+
file.read_to_end(&mut contents).unwrap();
49+
assert_eq!(bytes, contents.as_slice());
50+
// Test seeking relative to the end of the file.
51+
file.seek(SeekFrom::End(-1)).unwrap();
52+
let mut contents = Vec::new();
53+
file.read_to_end(&mut contents).unwrap();
54+
assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice());
55+
// Test seeking relative to the current position.
56+
file.seek(SeekFrom::Start(5)).unwrap();
57+
file.seek(SeekFrom::Current(-3)).unwrap();
58+
let mut contents = Vec::new();
59+
file.read_to_end(&mut contents).unwrap();
60+
assert_eq!(&bytes[2..], contents.as_slice());
61+
4562
// Test that metadata of an absolute path is correct.
4663
test_metadata(bytes, &path).unwrap();
4764
// Test that metadata of a relative path is correct.

0 commit comments

Comments
 (0)