|
1 | 1 | use std::collections::HashMap;
|
2 |
| -use std::fs::File; |
3 |
| -use std::io::Read; |
| 2 | +use std::fs::{ File, OpenOptions }; |
| 3 | +use std::io::{ Read, Write }; |
4 | 4 |
|
5 | 5 | use rustc::ty::layout::Size;
|
6 | 6 |
|
@@ -42,16 +42,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
42 | 42 |
|
43 | 43 | let flag = this.read_scalar(flag_op)?.to_i32()?;
|
44 | 44 |
|
45 |
| - if flag != this.eval_libc_i32("O_RDONLY")? && flag != this.eval_libc_i32("O_CLOEXEC")? { |
46 |
| - throw_unsup_format!("Unsupported flag {:#x}", flag); |
| 45 | + let mut options = OpenOptions::new(); |
| 46 | + |
| 47 | + // The first two bits of the flag correspond to the access mode of the file in linux. |
| 48 | + let access_mode = flag & 0b11; |
| 49 | + |
| 50 | + if access_mode == this.eval_libc_i32("O_RDONLY")? { |
| 51 | + options.read(true); |
| 52 | + } else if access_mode == this.eval_libc_i32("O_WRONLY")? { |
| 53 | + options.write(true); |
| 54 | + } else if access_mode == this.eval_libc_i32("O_RDWR")? { |
| 55 | + options.read(true).write(true); |
| 56 | + } else { |
| 57 | + throw_unsup_format!("Unsupported access mode {:#x}", access_mode); |
| 58 | + } |
| 59 | + |
| 60 | + if flag & this.eval_libc_i32("O_APPEND")? != 0 { |
| 61 | + options.append(true); |
| 62 | + } |
| 63 | + if flag & this.eval_libc_i32("O_TRUNC")? != 0 { |
| 64 | + options.truncate(true); |
| 65 | + } |
| 66 | + if flag & this.eval_libc_i32("O_CREAT")? != 0 { |
| 67 | + options.create(true); |
47 | 68 | }
|
48 | 69 |
|
49 | 70 | let path_bytes = this
|
50 | 71 | .memory()
|
51 | 72 | .read_c_str(this.read_scalar(path_op)?.not_undef()?)?;
|
52 | 73 | let path = std::str::from_utf8(path_bytes)
|
53 | 74 | .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?;
|
54 |
| - let fd = File::open(path).map(|file| { |
| 75 | + |
| 76 | + let fd = options.open(path).map(|file| { |
55 | 77 | let mut fh = &mut this.machine.file_handler;
|
56 | 78 | fh.low += 1;
|
57 | 79 | fh.handles.insert(fh.low, FileHandle { file, flag });
|
@@ -151,8 +173,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
151 | 173 | )
|
152 | 174 | }
|
153 | 175 |
|
| 176 | + fn write( |
| 177 | + &mut self, |
| 178 | + fd_op: OpTy<'tcx, Tag>, |
| 179 | + buf_op: OpTy<'tcx, Tag>, |
| 180 | + count_op: OpTy<'tcx, Tag>, |
| 181 | + ) -> InterpResult<'tcx, i64> { |
| 182 | + let this = self.eval_context_mut(); |
| 183 | + |
| 184 | + if !this.machine.communicate { |
| 185 | + throw_unsup_format!("`write` not available when isolation is enabled") |
| 186 | + } |
| 187 | + |
| 188 | + let tcx = &{ this.tcx.tcx }; |
| 189 | + |
| 190 | + let fd = this.read_scalar(fd_op)?.to_i32()?; |
| 191 | + let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; |
| 192 | + let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; |
| 193 | + |
| 194 | + // `to_vec` is needed to avoid borrowing issues when writing to the file. |
| 195 | + let bytes = this.memory().get(buf.alloc_id)?.get_bytes(tcx, buf, Size::from_bytes(count))?.to_vec(); |
| 196 | + |
| 197 | + this.remove_handle_and(fd, |mut handle, this| { |
| 198 | + let bytes = handle.file.write(&bytes).map(|bytes| bytes as i64); |
| 199 | + this.machine.file_handler.handles.insert(fd, handle); |
| 200 | + this.consume_result(bytes) |
| 201 | + }) |
| 202 | + } |
| 203 | + |
154 | 204 | /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it
|
155 |
| - /// using `f`. |
| 205 | + /// using the `f` closure. |
156 | 206 | ///
|
157 | 207 | /// If the `fd` file descriptor does not corresponds to a file, this functions returns `Ok(-1)`
|
158 | 208 | /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor).
|
|
0 commit comments