| #![unstable(issue = "none", feature = "windows_handle")] | |
| use core::ffi::c_void; | |
| use core::{cmp, mem, ptr}; | |
| use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; | |
| use crate::os::windows::io::{ | |
| AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, | |
| }; | |
| use crate::sys::{AsInner, FromInner, IntoInner, c, cvt}; | |
| /// An owned container for `HANDLE` object, closing them on Drop. | |
| /// | |
| /// All methods are inherited through a `Deref` impl to `RawHandle` | |
| #[derive(Debug)] | |
| pub struct Handle(OwnedHandle); | |
| impl Handle { | |
| pub fn new_event(manual: bool, init: bool) -> io::Result<Handle> { | |
| unsafe { | |
| let event = | |
| c::CreateEventW(ptr::null_mut(), manual as c::BOOL, init as c::BOOL, ptr::null()); | |
| if event.is_null() { | |
| Err(io::Error::last_os_error()) | |
| } else { | |
| Ok(Handle::from_raw_handle(event)) | |
| } | |
| } | |
| } | |
| } | |
| impl AsInner<OwnedHandle> for Handle { | |
| #[inline] | |
| fn as_inner(&self) -> &OwnedHandle { | |
| &self.0 | |
| } | |
| } | |
| impl IntoInner<OwnedHandle> for Handle { | |
| fn into_inner(self) -> OwnedHandle { | |
| self.0 | |
| } | |
| } | |
| impl FromInner<OwnedHandle> for Handle { | |
| fn from_inner(file_desc: OwnedHandle) -> Self { | |
| Self(file_desc) | |
| } | |
| } | |
| impl AsHandle for Handle { | |
| fn as_handle(&self) -> BorrowedHandle<'_> { | |
| self.0.as_handle() | |
| } | |
| } | |
| impl AsRawHandle for Handle { | |
| fn as_raw_handle(&self) -> RawHandle { | |
| self.0.as_raw_handle() | |
| } | |
| } | |
| impl IntoRawHandle for Handle { | |
| fn into_raw_handle(self) -> RawHandle { | |
| self.0.into_raw_handle() | |
| } | |
| } | |
| impl FromRawHandle for Handle { | |
| unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { | |
| unsafe { Self(FromRawHandle::from_raw_handle(raw_handle)) } | |
| } | |
| } | |
| impl Handle { | |
| pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { | |
| let res = unsafe { self.synchronous_read(buf.as_mut_ptr().cast(), buf.len(), None) }; | |
| match res { | |
| Ok(read) => Ok(read), | |
| // The special treatment of BrokenPipe is to deal with Windows | |
| // pipe semantics, which yields this error when *reading* from | |
| // a pipe after the other end has closed; we interpret that as | |
| // EOF on the pipe. | |
| Err(ref e) if e.kind() == io::ErrorKind::BrokenPipe => Ok(0), | |
| Err(e) => Err(e), | |
| } | |
| } | |
| pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { | |
| crate::io::default_read_vectored(|buf| self.read(buf), bufs) | |
| } | |
| #[inline] | |
| pub fn is_read_vectored(&self) -> bool { | |
| false | |
| } | |
| pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { | |
| let res = | |
| unsafe { self.synchronous_read(buf.as_mut_ptr().cast(), buf.len(), Some(offset)) }; | |
| match res { | |
| Ok(read) => Ok(read), | |
| Err(ref e) if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) => Ok(0), | |
| Err(e) => Err(e), | |
| } | |
| } | |
| pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { | |
| let res = | |
| unsafe { self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), None) }; | |
| match res { | |
| Ok(read) => { | |
| // Safety: `read` bytes were written to the initialized portion of the buffer | |
| unsafe { | |
| cursor.advance(read); | |
| } | |
| Ok(()) | |
| } | |
| // The special treatment of BrokenPipe is to deal with Windows | |
| // pipe semantics, which yields this error when *reading* from | |
| // a pipe after the other end has closed; we interpret that as | |
| // EOF on the pipe. | |
| Err(ref e) if e.kind() == io::ErrorKind::BrokenPipe => Ok(()), | |
| Err(e) => Err(e), | |
| } | |
| } | |
| pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { | |
| // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes | |
| let read = unsafe { | |
| self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), Some(offset)) | |
| }?; | |
| // SAFETY: `read` bytes were written to the initialized portion of the buffer | |
| unsafe { | |
| cursor.advance(read); | |
| } | |
| Ok(()) | |
| } | |
| pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { | |
| let mut me = self; | |
| Read::read_to_end(&mut me, buf) | |
| } | |
| pub unsafe fn read_overlapped( | |
| &self, | |
| buf: &mut [mem::MaybeUninit<u8>], | |
| overlapped: *mut c::OVERLAPPED, | |
| ) -> io::Result<Option<usize>> { | |
| // SAFETY: We have exclusive access to the buffer and it's up to the caller to | |
| // ensure the OVERLAPPED pointer is valid for the lifetime of this function. | |
| let (res, amt) = unsafe { | |
| let len = cmp::min(buf.len(), u32::MAX as usize) as u32; | |
| let mut amt = 0; | |
| let res = cvt(c::ReadFile( | |
| self.as_raw_handle(), | |
| buf.as_mut_ptr().cast::<u8>(), | |
| len, | |
| &mut amt, | |
| overlapped, | |
| )); | |
| (res, amt) | |
| }; | |
| match res { | |
| Ok(_) => Ok(Some(amt as usize)), | |
| Err(e) => { | |
| if e.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) { | |
| Ok(None) | |
| } else if e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) { | |
| Ok(Some(0)) | |
| } else { | |
| Err(e) | |
| } | |
| } | |
| } | |
| } | |
| pub fn overlapped_result( | |
| &self, | |
| overlapped: *mut c::OVERLAPPED, | |
| wait: bool, | |
| ) -> io::Result<usize> { | |
| unsafe { | |
| let mut bytes = 0; | |
| let wait = if wait { c::TRUE } else { c::FALSE }; | |
| let res = | |
| cvt(c::GetOverlappedResult(self.as_raw_handle(), overlapped, &mut bytes, wait)); | |
| match res { | |
| Ok(_) => Ok(bytes as usize), | |
| Err(e) => { | |
| if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) | |
| || e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) | |
| { | |
| Ok(0) | |
| } else { | |
| Err(e) | |
| } | |
| } | |
| } | |
| } | |
| } | |
| pub fn cancel_io(&self) -> io::Result<()> { | |
| unsafe { cvt(c::CancelIo(self.as_raw_handle())).map(drop) } | |
| } | |
| pub fn write(&self, buf: &[u8]) -> io::Result<usize> { | |
| self.synchronous_write(buf, None) | |
| } | |
| pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
| crate::io::default_write_vectored(|buf| self.write(buf), bufs) | |
| } | |
| #[inline] | |
| pub fn is_write_vectored(&self) -> bool { | |
| false | |
| } | |
| pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { | |
| self.synchronous_write(buf, Some(offset)) | |
| } | |
| pub fn try_clone(&self) -> io::Result<Self> { | |
| Ok(Self(self.0.try_clone()?)) | |
| } | |
| pub fn duplicate(&self, access: u32, inherit: bool, options: u32) -> io::Result<Self> { | |
| Ok(Self(self.0.as_handle().duplicate(access, inherit, options)?)) | |
| } | |
| /// Performs a synchronous read. | |
| /// | |
| /// If the handle is opened for asynchronous I/O then this abort the process. | |
| /// See #81357. | |
| /// | |
| /// If `offset` is `None` then the current file position is used. | |
| unsafe fn synchronous_read( | |
| &self, | |
| buf: *mut mem::MaybeUninit<u8>, | |
| len: usize, | |
| offset: Option<u64>, | |
| ) -> io::Result<usize> { | |
| let mut io_status = c::IO_STATUS_BLOCK::PENDING; | |
| // The length is clamped at u32::MAX. | |
| let len = cmp::min(len, u32::MAX as usize) as u32; | |
| // SAFETY: It's up to the caller to ensure `buf` is writeable up to | |
| // the provided `len`. | |
| let status = unsafe { | |
| c::NtReadFile( | |
| self.as_raw_handle(), | |
| ptr::null_mut(), | |
| None, | |
| ptr::null_mut(), | |
| &mut io_status, | |
| buf.cast::<c_void>(), | |
| len, | |
| offset.as_ref().map(|n| ptr::from_ref(n).cast::<i64>()).unwrap_or(ptr::null()), | |
| ptr::null(), | |
| ) | |
| }; | |
| let status = if status == c::STATUS_PENDING { | |
| unsafe { c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE) }; | |
| io_status.status() | |
| } else { | |
| status | |
| }; | |
| match status { | |
| // If the operation has not completed then abort the process. | |
| // Doing otherwise means that the buffer and stack may be written to | |
| // after this function returns. | |
| c::STATUS_PENDING => rtabort!("I/O error: operation failed to complete synchronously"), | |
| // Return `Ok(0)` when there's nothing more to read. | |
| c::STATUS_END_OF_FILE => Ok(0), | |
| // Success! | |
| status if c::nt_success(status) => Ok(io_status.Information), | |
| status => { | |
| let error = unsafe { c::RtlNtStatusToDosError(status) }; | |
| Err(io::Error::from_raw_os_error(error as _)) | |
| } | |
| } | |
| } | |
| /// Performs a synchronous write. | |
| /// | |
| /// If the handle is opened for asynchronous I/O then this abort the process. | |
| /// See #81357. | |
| /// | |
| /// If `offset` is `None` then the current file position is used. | |
| fn synchronous_write(&self, buf: &[u8], offset: Option<u64>) -> io::Result<usize> { | |
| let mut io_status = c::IO_STATUS_BLOCK::PENDING; | |
| // The length is clamped at u32::MAX. | |
| let len = cmp::min(buf.len(), u32::MAX as usize) as u32; | |
| let status = unsafe { | |
| c::NtWriteFile( | |
| self.as_raw_handle(), | |
| ptr::null_mut(), | |
| None, | |
| ptr::null_mut(), | |
| &mut io_status, | |
| buf.as_ptr().cast::<c_void>(), | |
| len, | |
| offset.as_ref().map(|n| ptr::from_ref(n).cast::<i64>()).unwrap_or(ptr::null()), | |
| ptr::null(), | |
| ) | |
| }; | |
| let status = if status == c::STATUS_PENDING { | |
| unsafe { c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE) }; | |
| io_status.status() | |
| } else { | |
| status | |
| }; | |
| match status { | |
| // If the operation has not completed then abort the process. | |
| // Doing otherwise means that the buffer may be read and the stack | |
| // written to after this function returns. | |
| c::STATUS_PENDING => rtabort!("I/O error: operation failed to complete synchronously"), | |
| // Success! | |
| status if c::nt_success(status) => Ok(io_status.Information), | |
| status => { | |
| let error = unsafe { c::RtlNtStatusToDosError(status) }; | |
| Err(io::Error::from_raw_os_error(error as _)) | |
| } | |
| } | |
| } | |
| } | |
| impl<'a> Read for &'a Handle { | |
| fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
| (**self).read(buf) | |
| } | |
| fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { | |
| (**self).read_buf(buf) | |
| } | |
| fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { | |
| (**self).read_vectored(bufs) | |
| } | |
| #[inline] | |
| fn is_read_vectored(&self) -> bool { | |
| (**self).is_read_vectored() | |
| } | |
| } |