use kernel32;
use winapi;
use IntoInner;
use io::FileDesc;
use std::fmt;
use std::fs::File;
use std::io::{ErrorKind, Result, SeekFrom};
use std::mem;
use std::os::raw::c_void as HANDLE;
use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
use std::process::Stdio;
use std::ptr;
use std::ptr::Unique;
use sys::cvt;
pub struct RawIo {
handle: Unique<HANDLE>,
}
impl fmt::Debug for RawIo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
struct PointerDebug<'a>(&'a fmt::Pointer);
impl<'a> fmt::Debug for PointerDebug<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{:p}", self.0)
}
}
fmt.debug_struct("RawIo")
.field("handle", &PointerDebug(&self.handle))
.finish()
}
}
impl Eq for RawIo {}
impl PartialEq<RawIo> for RawIo {
fn eq(&self, other: &RawIo) -> bool {
self.handle.as_ptr() == other.handle.as_ptr()
}
}
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 {
RawIo {
handle: Unique::new(handle).expect("null handle"),
}
}
pub unsafe fn into_inner(self) -> RawHandle {
let handle = self.inner();
mem::forget(self);
handle
}
pub fn inner(&self) -> RawHandle {
self.handle.as_ptr()
}
pub fn duplicate(&self) -> Result<Self> {
unsafe {
let mut ret = winapi::INVALID_HANDLE_VALUE;
try!(cvt({
let cur_proc = kernel32::GetCurrentProcess();
kernel32::DuplicateHandle(cur_proc,
self.inner(),
cur_proc,
&mut ret,
0 as winapi::DWORD,
winapi::FALSE,
winapi::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 {
kernel32::ReadFile(self.inner(),
buf.as_ptr() as winapi::LPVOID,
buf.len() as winapi::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;
try!(cvt(unsafe {
kernel32::WriteFile(self.inner(),
buf.as_ptr() as winapi::LPVOID,
buf.len() as winapi::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, pos) = match pos {
SeekFrom::Start(n) => (winapi::FILE_BEGIN, n as i64),
SeekFrom::End(n) => (winapi::FILE_END, n),
SeekFrom::Current(n) => (winapi::FILE_CURRENT, n),
};
let pos = pos as winapi::LARGE_INTEGER;
let mut newpos = 0;
try!(cvt(unsafe {
kernel32::SetFilePointerEx(self.inner(), pos, &mut newpos, whence)
}));
Ok(newpos as u64)
}
}
impl Drop for RawIo {
fn drop(&mut self) {
unsafe {
let _ = kernel32::CloseHandle(self.inner());
}
}
}
pub fn pipe() -> Result<(RawIo, RawIo)> {
use std::ptr;
unsafe {
let mut reader = winapi::INVALID_HANDLE_VALUE;
let mut writer = winapi::INVALID_HANDLE_VALUE;
try!(cvt(kernel32::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: winapi::DWORD) -> Result<RawIo> {
unsafe {
let current_process = kernel32::GetCurrentProcess();
let mut new_handle = winapi::INVALID_HANDLE_VALUE;
try!(cvt(kernel32::DuplicateHandle(current_process,
kernel32::GetStdHandle(handle),
current_process,
&mut new_handle,
0 as winapi::DWORD,
winapi::FALSE,
winapi::DUPLICATE_SAME_ACCESS)));
Ok(RawIo::new(new_handle))
}
}
Ok((
try!(dup_handle(winapi::STD_INPUT_HANDLE)),
try!(dup_handle(winapi::STD_OUTPUT_HANDLE)),
try!(dup_handle(winapi::STD_ERROR_HANDLE))
))
}
pub fn getpid() -> winapi::DWORD {
unsafe {
kernel32::GetCurrentProcessId()
}
}