use crate::io::FileDesc;
use crate::sys::cvt;
use crate::IntoInner;
use std::fs::File;
use std::io::{ErrorKind, Result, SeekFrom};
use std::mem;
use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
use std::process::Stdio;
use std::ptr;
use winapi::shared::minwindef::{DWORD, FALSE, LPVOID};
use winapi::um::fileapi::{ReadFile, SetFilePointerEx, WriteFile};
use winapi::um::handleapi::{CloseHandle, DuplicateHandle, INVALID_HANDLE_VALUE};
use winapi::um::namedpipeapi::CreatePipe;
use winapi::um::processenv::GetStdHandle;
use winapi::um::processthreadsapi::{GetCurrentProcess, GetCurrentProcessId};
use winapi::um::winbase::{
FILE_BEGIN, FILE_CURRENT, FILE_END, STD_ERROR_HANDLE, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
};
use winapi::um::winnt::{DUPLICATE_SAME_ACCESS, LARGE_INTEGER};
#[derive(Debug, PartialEq, Eq)]
pub struct RawIo {
handle: RawHandle,
}
unsafe impl Send for RawIo {}
unsafe impl Sync for RawIo {}
impl Into<Stdio> for RawIo {
fn into(self) -> Stdio {
unsafe { FromRawHandle::from_raw_handle(self.into_inner()) }
}
}
impl FromRawHandle for FileDesc {
unsafe fn from_raw_handle(handle: RawHandle) -> Self {
Self::new(handle)
}
}
impl AsRawHandle for FileDesc {
fn as_raw_handle(&self) -> RawHandle {
self.inner().inner()
}
}
impl IntoRawHandle for FileDesc {
fn into_raw_handle(self) -> RawHandle {
unsafe { self.into_inner().into_inner() }
}
}
impl From<File> for FileDesc {
fn from(file: File) -> Self {
unsafe { FromRawHandle::from_raw_handle(file.into_raw_handle()) }
}
}
impl RawIo {
pub unsafe fn new(handle: RawHandle) -> Self {
assert!(!handle.is_null(), "null handle");
RawIo { handle: handle }
}
pub unsafe fn into_inner(self) -> RawHandle {
let handle = self.inner();
mem::forget(self);
handle
}
pub fn inner(&self) -> RawHandle {
self.handle
}
pub fn duplicate(&self) -> Result<Self> {
unsafe {
let mut ret = INVALID_HANDLE_VALUE;
cvt({
let cur_proc = GetCurrentProcess();
DuplicateHandle(
cur_proc,
self.inner(),
cur_proc,
&mut ret,
0 as DWORD,
FALSE,
DUPLICATE_SAME_ACCESS,
)
})?;
Ok(RawIo::new(ret))
}
}
pub fn read_inner(&self, buf: &mut [u8]) -> Result<usize> {
let mut read = 0;
let res = cvt(unsafe {
ReadFile(
self.inner(),
buf.as_ptr() as LPVOID,
buf.len() as DWORD,
&mut read,
ptr::null_mut(),
)
});
match res {
Ok(_) => Ok(read as usize),
Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(0),
Err(e) => Err(e),
}
}
pub fn write_inner(&self, buf: &[u8]) -> Result<usize> {
let mut amt = 0;
cvt(unsafe {
WriteFile(
self.inner(),
buf.as_ptr() as LPVOID,
buf.len() as DWORD,
&mut amt,
ptr::null_mut(),
)
})?;
Ok(amt as usize)
}
pub fn flush_inner(&self) -> Result<()> {
Ok(())
}
pub fn seek(&self, pos: SeekFrom) -> Result<u64> {
let (whence, startpos) = match pos {
SeekFrom::Start(n) => (FILE_BEGIN, n as i64),
SeekFrom::End(n) => (FILE_END, n),
SeekFrom::Current(n) => (FILE_CURRENT, n),
};
unsafe {
let mut pos: LARGE_INTEGER = mem::zeroed();
*pos.QuadPart_mut() = startpos;
let mut newpos: LARGE_INTEGER = mem::zeroed();
cvt(SetFilePointerEx(self.inner(), pos, &mut newpos, whence))?;
Ok(*newpos.QuadPart() as u64)
}
}
}
impl Drop for RawIo {
fn drop(&mut self) {
unsafe {
let _ = CloseHandle(self.inner());
}
}
}
pub fn pipe() -> Result<(RawIo, RawIo)> {
unsafe {
let mut reader = INVALID_HANDLE_VALUE;
let mut writer = INVALID_HANDLE_VALUE;
cvt(CreatePipe(&mut reader, &mut writer, ptr::null_mut(), 0))?;
Ok((RawIo::new(reader), RawIo::new(writer)))
}
}
pub fn dup_stdio() -> Result<(RawIo, RawIo, RawIo)> {
fn dup_handle(handle: DWORD) -> Result<RawIo> {
unsafe {
let current_process = GetCurrentProcess();
let mut new_handle = INVALID_HANDLE_VALUE;
cvt(DuplicateHandle(
current_process,
GetStdHandle(handle),
current_process,
&mut new_handle,
0 as DWORD,
FALSE,
DUPLICATE_SAME_ACCESS,
))?;
Ok(RawIo::new(new_handle))
}
}
Ok((
dup_handle(STD_INPUT_HANDLE)?,
dup_handle(STD_OUTPUT_HANDLE)?,
dup_handle(STD_ERROR_HANDLE)?,
))
}
pub fn getpid() -> DWORD {
unsafe { GetCurrentProcessId() }
}