blob: b10c86e2a4200ebd706d5d5a5d5076787b2e9644 [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::io;
use winapi::shared::minwindef::DWORD;
use winapi::shared::minwindef::LPCVOID;
use winapi::shared::minwindef::LPVOID;
use winapi::shared::winerror::ERROR_IO_PENDING;
use winapi::um::fileapi::ReadFile;
use winapi::um::fileapi::WriteFile;
use winapi::um::minwinbase::OVERLAPPED;
use crate::AsRawDescriptor;
/// Safety requirements:
/// 1. buf points to memory that will not be freed until the write operation completes.
/// 2. buf points to at least buf_len bytes.
pub unsafe fn write_file(
handle: &dyn AsRawDescriptor,
buf: *const u8,
buf_len: usize,
overlapped: Option<&mut OVERLAPPED>,
) -> io::Result<usize> {
let is_overlapped = overlapped.is_some();
// Safe because buf points to a valid region of memory whose size we have computed,
// pipe has not been closed (as it's managed by this object), and we check the return
// value for any errors
let mut bytes_written: DWORD = 0;
let success_flag = WriteFile(
handle.as_raw_descriptor(),
buf as LPCVOID,
buf_len
.try_into()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?,
match overlapped {
Some(_) => std::ptr::null_mut(),
None => &mut bytes_written,
},
match overlapped {
Some(v) => v,
None => std::ptr::null_mut(),
},
);
if success_flag == 0 {
let err = io::Error::last_os_error();
if Some(ERROR_IO_PENDING as i32) == err.raw_os_error() && is_overlapped {
Ok(0)
} else {
Err(err)
}
} else {
Ok(bytes_written as usize)
}
}
/// Safety requirements:
/// 1. buf points to memory that will not be freed until the read operation completes.
/// 2. buf points to at least buf_len bytes.
pub unsafe fn read_file(
handle: &dyn AsRawDescriptor,
buf: *mut u8,
buf_len: usize,
overlapped: Option<&mut OVERLAPPED>,
) -> io::Result<usize> {
// Used to verify if ERROR_IO_PENDING should be an error.
let is_overlapped = overlapped.is_some();
// Safe because we cap the size of the read to the size of the buffer
// and check the return code
let mut bytes_read: DWORD = 0;
let success_flag = ReadFile(
handle.as_raw_descriptor(),
buf as LPVOID,
buf_len as DWORD,
match overlapped {
Some(_) => std::ptr::null_mut(),
None => &mut bytes_read,
},
match overlapped {
Some(v) => v,
None => std::ptr::null_mut(),
},
);
if success_flag == 0 {
let e = io::Error::last_os_error();
match e.raw_os_error() {
// ERROR_IO_PENDING, according the to docs, isn't really an error. This just means
// that the ReadFile operation hasn't completed. In this case,
// `get_overlapped_result` will wait until the operation is completed.
Some(error_code) if error_code == ERROR_IO_PENDING as i32 && is_overlapped => Ok(0),
_ => Err(e),
}
} else {
Ok(bytes_read as usize)
}
}