Skip to content

Commit 085874d

Browse files
committed
Add F_DUPFD/F_DUPFD_CLOEXEC to fcntl shim
1 parent 329383a commit 085874d

File tree

2 files changed

+21
-2
lines changed

2 files changed

+21
-2
lines changed

src/shims/fs.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl Default for FileHandler {
2828
FileHandler {
2929
handles: Default::default(),
3030
// 0, 1 and 2 are reserved for stdin, stdout and stderr.
31-
low: 3,
31+
low: 2,
3232
}
3333
}
3434
}
@@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
120120
&mut self,
121121
fd_op: OpTy<'tcx, Tag>,
122122
cmd_op: OpTy<'tcx, Tag>,
123-
_arg1_op: Option<OpTy<'tcx, Tag>>,
123+
arg_op: Option<OpTy<'tcx, Tag>>,
124124
) -> InterpResult<'tcx, i32> {
125125
let this = self.eval_context_mut();
126126

@@ -139,6 +139,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
139139
} else {
140140
this.handle_not_found()
141141
}
142+
} else if cmd == this.eval_libc_i32("F_DUPFD")? || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")? {
143+
let arg = match arg_op {
144+
Some(arg_op) => this.read_scalar(arg_op)?.to_i32()?,
145+
None => throw_unsup_format!("fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"),
146+
};
147+
let fh = &mut this.machine.file_handler;
148+
let (file_result, writable) = match fh.handles.get(&fd) {
149+
Some(original) => (original.file.try_clone(), original.writable),
150+
None => return this.handle_not_found(),
151+
};
152+
let fd_result = file_result.map(|duplicated| {
153+
let new_fd = std::cmp::max(fh.low + 1, arg);
154+
fh.low = new_fd;
155+
fh.handles.insert(fh.low, FileHandle { file: duplicated, writable }).unwrap_none();
156+
new_fd
157+
});
158+
this.try_unwrap_io_result(fd_result)
142159
} else {
143160
throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd);
144161
}

tests/run-pass/fs.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ fn main() {
4141
// Reading until EOF should get the whole text.
4242
file.read_to_end(&mut contents).unwrap();
4343
assert_eq!(bytes, contents.as_slice());
44+
// Cloning a file should be successful
45+
file.try_clone().unwrap();
4446

4547
// Test that seeking to the beginning and reading until EOF gets the text again.
4648
file.seek(SeekFrom::Start(0)).unwrap();

0 commit comments

Comments
 (0)