Skip to content

Commit d8720c9

Browse files
committed
Implement file read, write, and delete APIs.
STDIN/ERR/OUT are now proper pseudo-handles.
1 parent f1bb77d commit d8720c9

File tree

4 files changed

+358
-67
lines changed

4 files changed

+358
-67
lines changed

src/shims/windows/foreign_items.rs

+63-63
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
136136
let result = this.GetUserProfileDirectoryW(token, buf, size)?;
137137
this.write_scalar(result, dest)?;
138138
}
139+
"GetCurrentProcess" => {
140+
let [] =
141+
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
142+
this.write_scalar(
143+
Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
144+
dest,
145+
)?;
146+
}
139147
"GetCurrentProcessId" => {
140148
let [] =
141149
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
@@ -145,71 +153,54 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
145153

146154
// File related shims
147155
"NtWriteFile" => {
148-
if !this.frame_in_std() {
149-
throw_unsup_format!(
150-
"`NtWriteFile` support is crude and just enough for stdout to work"
151-
);
152-
}
153-
154156
let [
155157
handle,
156-
_event,
157-
_apc_routine,
158-
_apc_context,
158+
event,
159+
apc_routine,
160+
apc_context,
159161
io_status_block,
160162
buf,
161163
n,
162164
byte_offset,
163-
_key,
165+
key,
164166
] = this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
165-
let handle = this.read_target_isize(handle)?;
166-
let buf = this.read_pointer(buf)?;
167-
let n = this.read_scalar(n)?.to_u32()?;
168-
let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer
169-
let io_status_block = this
170-
.deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
171-
172-
if byte_offset != 0 {
173-
throw_unsup_format!(
174-
"`NtWriteFile` `ByteOffset` parameter is non-null, which is unsupported"
175-
);
176-
}
177-
178-
let written = if handle == -11 || handle == -12 {
179-
// stdout/stderr
180-
use io::Write;
181-
182-
let buf_cont =
183-
this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?;
184-
let res = if this.machine.mute_stdout_stderr {
185-
Ok(buf_cont.len())
186-
} else if handle == -11 {
187-
io::stdout().write(buf_cont)
188-
} else {
189-
io::stderr().write(buf_cont)
190-
};
191-
// We write at most `n` bytes, which is a `u32`, so we cannot have written more than that.
192-
res.ok().map(|n| u32::try_from(n).unwrap())
193-
} else {
194-
throw_unsup_format!(
195-
"on Windows, writing to anything except stdout/stderr is not supported"
196-
)
197-
};
198-
// We have to put the result into io_status_block.
199-
if let Some(n) = written {
200-
let io_status_information =
201-
this.project_field_named(&io_status_block, "Information")?;
202-
this.write_scalar(
203-
Scalar::from_target_usize(n.into(), this),
204-
&io_status_information,
205-
)?;
206-
}
207-
// Return whether this was a success. >= 0 is success.
208-
// For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
209-
this.write_scalar(
210-
Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }),
211-
dest,
167+
let res = this.NtWriteFile(
168+
handle,
169+
event,
170+
apc_routine,
171+
apc_context,
172+
io_status_block,
173+
buf,
174+
n,
175+
byte_offset,
176+
key,
177+
)?;
178+
this.write_scalar(res, dest)?;
179+
}
180+
"NtReadFile" => {
181+
let [
182+
handle,
183+
event,
184+
apc_routine,
185+
apc_context,
186+
io_status_block,
187+
buf,
188+
n,
189+
byte_offset,
190+
key,
191+
] = this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
192+
let res = this.NtReadFile(
193+
handle,
194+
event,
195+
apc_routine,
196+
apc_context,
197+
io_status_block,
198+
buf,
199+
n,
200+
byte_offset,
201+
key,
212202
)?;
203+
this.write_scalar(res, dest)?;
213204
}
214205
"GetFullPathNameW" => {
215206
let [filename, size, buffer, filepart] =
@@ -268,6 +259,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
268259
let res = this.GetFileInformationByHandle(handle, info)?;
269260
this.write_scalar(res, dest)?;
270261
}
262+
"DeleteFileW" => {
263+
let [file_name] =
264+
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
265+
let res = this.DeleteFileW(file_name)?;
266+
this.write_scalar(res, dest)?;
267+
}
268+
"SetFilePointerEx" => {
269+
let [file, distance_to_move, new_file_pointer, move_method] =
270+
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
271+
let res =
272+
this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
273+
this.write_scalar(res, dest)?;
274+
}
271275

272276
// Allocation
273277
"HeapAlloc" => {
@@ -654,12 +658,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
654658
"GetStdHandle" => {
655659
let [which] =
656660
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
657-
let which = this.read_scalar(which)?.to_i32()?;
658-
// We just make this the identity function, so we know later in `NtWriteFile` which
659-
// one it is. This is very fake, but libtest needs it so we cannot make it a
660-
// std-only shim.
661-
// FIXME: this should return real HANDLEs when io support is added
662-
this.write_scalar(Scalar::from_target_isize(which.into(), this), dest)?;
661+
let res = this.GetStdHandle(which)?;
662+
this.write_scalar(res, dest)?;
663663
}
664664
"CloseHandle" => {
665665
let [handle] =

0 commit comments

Comments
 (0)