From 085874d1ffd224dfe39a1aaa82e4f286b8614c91 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 11:19:06 -0600 Subject: [PATCH] Add F_DUPFD/F_DUPFD_CLOEXEC to fcntl shim --- src/shims/fs.rs | 21 +++++++++++++++++++-- tests/run-pass/fs.rs | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 2ae215e7204f..07390be2c8bb 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -28,7 +28,7 @@ impl Default for FileHandler { FileHandler { handles: Default::default(), // 0, 1 and 2 are reserved for stdin, stdout and stderr. - low: 3, + low: 2, } } } @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, fd_op: OpTy<'tcx, Tag>, cmd_op: OpTy<'tcx, Tag>, - _arg1_op: Option>, + arg_op: Option>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -139,6 +139,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { this.handle_not_found() } + } else if cmd == this.eval_libc_i32("F_DUPFD")? || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")? { + let arg = match arg_op { + Some(arg_op) => this.read_scalar(arg_op)?.to_i32()?, + None => throw_unsup_format!("fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"), + }; + let fh = &mut this.machine.file_handler; + let (file_result, writable) = match fh.handles.get(&fd) { + Some(original) => (original.file.try_clone(), original.writable), + None => return this.handle_not_found(), + }; + let fd_result = file_result.map(|duplicated| { + let new_fd = std::cmp::max(fh.low + 1, arg); + fh.low = new_fd; + fh.handles.insert(fh.low, FileHandle { file: duplicated, writable }).unwrap_none(); + new_fd + }); + this.try_unwrap_io_result(fd_result) } else { throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); } diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 71c6e854f7c5..632ed13f2eac 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -41,6 +41,8 @@ fn main() { // Reading until EOF should get the whole text. file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Cloning a file should be successful + file.try_clone().unwrap(); // Test that seeking to the beginning and reading until EOF gets the text again. file.seek(SeekFrom::Start(0)).unwrap();