//! Owned and borrowed OS handles. #![stable(feature = "io_safety", since = "1.63.0")] use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; use crate::fmt; use crate::fs; use crate::io; use crate::marker::PhantomData; use crate::mem::forget; use crate::ptr; use crate::sys::c; use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; /// A borrowed handle. /// /// This has a lifetime parameter to tie it to the lifetime of something that /// owns the handle. /// /// This uses `repr(transparent)` and has the representation of a host handle, /// so it can be used in FFI in places where a handle is passed as an argument, /// it is not captured or consumed. /// /// Note that it *may* have the value `-1`, which in `BorrowedHandle` always /// represents a valid handle value, such as [the current process handle], and /// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See /// [here] for the full story. /// /// And, it *may* have the value `NULL` (0), which can occur when consoles are /// detached from processes, or when `windows_subsystem` is used. /// /// This type's `.to_owned()` implementation returns another `BorrowedHandle` /// rather than an `OwnedHandle`. It just makes a trivial copy of the raw /// handle, which is then borrowed under the same lifetime. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 /// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks #[derive(Copy, Clone)] #[repr(transparent)] #[stable(feature = "io_safety", since = "1.63.0")] pub struct BorrowedHandle<'handle> { handle: RawHandle, _phantom: PhantomData<&'handle OwnedHandle>, } /// An owned handle. /// /// This closes the handle on drop. /// /// Note that it *may* have the value `-1`, which in `OwnedHandle` always /// represents a valid handle value, such as [the current process handle], and /// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See /// [here] for the full story. /// /// And, it *may* have the value `NULL` (0), which can occur when consoles are /// detached from processes, or when `windows_subsystem` is used. /// /// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such, /// it must not be used with handles to open registry keys which need to be /// closed with [`RegCloseKey`] instead. /// /// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 /// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks #[repr(transparent)] #[stable(feature = "io_safety", since = "1.63.0")] pub struct OwnedHandle { handle: RawHandle, } /// FFI type for handles in return values or out parameters, where `NULL` is used /// as a sentry value to indicate errors, such as in the return value of `CreateThread`. This uses /// `repr(transparent)` and has the representation of a host handle, so that it can be used in such /// FFI declarations. /// /// The only thing you can usefully do with a `HandleOrNull` is to convert it into an /// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for /// `NULL`. This ensures that such FFI calls cannot start using the handle without /// checking for `NULL` first. /// /// This type may hold any handle value that [`OwnedHandle`] may hold. As with `OwnedHandle`, when /// it holds `-1`, that value is interpreted as a valid handle value, such as /// [the current process handle], and not `INVALID_HANDLE_VALUE`. /// /// If this holds a non-null handle, it will close the handle on drop. /// /// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks #[repr(transparent)] #[stable(feature = "io_safety", since = "1.63.0")] #[derive(Debug)] pub struct HandleOrNull(OwnedHandle); /// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used /// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses /// `repr(transparent)` and has the representation of a host handle, so that it can be used in such /// FFI declarations. /// /// The only thing you can usefully do with a `HandleOrInvalid` is to convert it into an /// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for /// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without /// checking for `INVALID_HANDLE_VALUE` first. /// /// This type may hold any handle value that [`OwnedHandle`] may hold, except that when it holds /// `-1`, that value is interpreted to mean `INVALID_HANDLE_VALUE`. /// /// If holds a handle other than `INVALID_HANDLE_VALUE`, it will close the handle on drop. #[repr(transparent)] #[stable(feature = "io_safety", since = "1.63.0")] #[derive(Debug)] pub struct HandleOrInvalid(OwnedHandle); // The Windows [`HANDLE`] type may be transferred across and shared between // thread boundaries (despite containing a `*mut void`, which in general isn't // `Send` or `Sync`). // // [`HANDLE`]: std::os::windows::raw::HANDLE #[stable(feature = "io_safety", since = "1.63.0")] unsafe impl Send for OwnedHandle {} #[stable(feature = "io_safety", since = "1.63.0")] unsafe impl Send for HandleOrNull {} #[stable(feature = "io_safety", since = "1.63.0")] unsafe impl Send for HandleOrInvalid {} #[stable(feature = "io_safety", since = "1.63.0")] unsafe impl Send for BorrowedHandle<'_> {} #[stable(feature = "io_safety", since = "1.63.0")] unsafe impl Sync for OwnedHandle {} #[stable(feature = "io_safety", since = "1.63.0")] unsafe impl Sync for HandleOrNull {} #[stable(feature = "io_safety", since = "1.63.0")] unsafe impl Sync for HandleOrInvalid {} #[stable(feature = "io_safety", since = "1.63.0")] unsafe impl Sync for BorrowedHandle<'_> {} impl BorrowedHandle<'_> { /// Return a `BorrowedHandle` holding the given raw handle. /// /// # Safety /// /// The resource pointed to by `handle` must be a valid open handle, it /// must remain open for the duration of the returned `BorrowedHandle`. /// /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is /// sometimes a valid handle value. See [here] for the full story. /// /// And, it *may* have the value `NULL` (0), which can occur when consoles are /// detached from processes, or when `windows_subsystem` is used. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] #[rustc_const_stable(feature = "io_safety", since = "1.63.0")] #[stable(feature = "io_safety", since = "1.63.0")] pub const unsafe fn borrow_raw(handle: RawHandle) -> Self { Self { handle, _phantom: PhantomData } } } #[stable(feature = "io_safety", since = "1.63.0")] impl TryFrom for OwnedHandle { type Error = NullHandleError; #[inline] fn try_from(handle_or_null: HandleOrNull) -> Result { let owned_handle = handle_or_null.0; if owned_handle.handle.is_null() { // Don't call `CloseHandle`; it'd be harmless, except that it could // overwrite the `GetLastError` error. forget(owned_handle); Err(NullHandleError(())) } else { Ok(owned_handle) } } } impl OwnedHandle { /// Creates a new `OwnedHandle` instance that shares the same underlying /// object as the existing `OwnedHandle` instance. #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone(&self) -> crate::io::Result { self.as_handle().try_clone_to_owned() } } impl BorrowedHandle<'_> { /// Creates a new `OwnedHandle` instance that shares the same underlying /// object as the existing `BorrowedHandle` instance. #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> crate::io::Result { self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS) } pub(crate) fn duplicate( &self, access: c::DWORD, inherit: bool, options: c::DWORD, ) -> io::Result { let handle = self.as_raw_handle(); // `Stdin`, `Stdout`, and `Stderr` can all hold null handles, such as // in a process with a detached console. `DuplicateHandle` would fail // if we passed it a null handle, but we can treat null as a valid // handle which doesn't do any I/O, and allow it to be duplicated. if handle.is_null() { return unsafe { Ok(OwnedHandle::from_raw_handle(handle)) }; } let mut ret = ptr::null_mut(); cvt(unsafe { let cur_proc = c::GetCurrentProcess(); c::DuplicateHandle( cur_proc, handle, cur_proc, &mut ret, access, inherit as c::BOOL, options, ) })?; unsafe { Ok(OwnedHandle::from_raw_handle(ret)) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl TryFrom for OwnedHandle { type Error = InvalidHandleError; #[inline] fn try_from(handle_or_invalid: HandleOrInvalid) -> Result { let owned_handle = handle_or_invalid.0; if owned_handle.handle == c::INVALID_HANDLE_VALUE { // Don't call `CloseHandle`; it'd be harmless, except that it could // overwrite the `GetLastError` error. forget(owned_handle); Err(InvalidHandleError(())) } else { Ok(owned_handle) } } } /// This is the error type used by [`HandleOrNull`] when attempting to convert /// into a handle, to indicate that the value is null. // The empty field prevents constructing this, and allows extending it in the future. #[stable(feature = "io_safety", since = "1.63.0")] #[derive(Debug, Clone, PartialEq, Eq)] pub struct NullHandleError(()); #[stable(feature = "io_safety", since = "1.63.0")] impl fmt::Display for NullHandleError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { "A HandleOrNull could not be converted to a handle because it was null".fmt(fmt) } } #[stable(feature = "io_safety", since = "1.63.0")] impl crate::error::Error for NullHandleError {} /// This is the error type used by [`HandleOrInvalid`] when attempting to /// convert into a handle, to indicate that the value is /// `INVALID_HANDLE_VALUE`. // The empty field prevents constructing this, and allows extending it in the future. #[stable(feature = "io_safety", since = "1.63.0")] #[derive(Debug, Clone, PartialEq, Eq)] pub struct InvalidHandleError(()); #[stable(feature = "io_safety", since = "1.63.0")] impl fmt::Display for InvalidHandleError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { "A HandleOrInvalid could not be converted to a handle because it was INVALID_HANDLE_VALUE" .fmt(fmt) } } #[stable(feature = "io_safety", since = "1.63.0")] impl crate::error::Error for InvalidHandleError {} #[stable(feature = "io_safety", since = "1.63.0")] impl AsRawHandle for BorrowedHandle<'_> { #[inline] fn as_raw_handle(&self) -> RawHandle { self.handle } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsRawHandle for OwnedHandle { #[inline] fn as_raw_handle(&self) -> RawHandle { self.handle } } #[stable(feature = "io_safety", since = "1.63.0")] impl IntoRawHandle for OwnedHandle { #[inline] fn into_raw_handle(self) -> RawHandle { let handle = self.handle; forget(self); handle } } #[stable(feature = "io_safety", since = "1.63.0")] impl FromRawHandle for OwnedHandle { #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self { handle } } } impl HandleOrNull { /// Constructs a new instance of `Self` from the given `RawHandle` returned /// from a Windows API that uses null to indicate failure, such as /// `CreateThread`. /// /// Use `HandleOrInvalid` instead of `HandleOrNull` for APIs that /// use `INVALID_HANDLE_VALUE` to indicate failure. /// /// # Safety /// /// The passed `handle` value must either satisfy the safety requirements /// of [`FromRawHandle::from_raw_handle`], or be null. Note that not all /// Windows APIs use null for errors; see [here] for the full story. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[stable(feature = "io_safety", since = "1.63.0")] #[inline] pub unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self(OwnedHandle::from_raw_handle(handle)) } } impl HandleOrInvalid { /// Constructs a new instance of `Self` from the given `RawHandle` returned /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate /// failure, such as `CreateFileW`. /// /// Use `HandleOrNull` instead of `HandleOrInvalid` for APIs that /// use null to indicate failure. /// /// # Safety /// /// The passed `handle` value must either satisfy the safety requirements /// of [`FromRawHandle::from_raw_handle`], or be /// `INVALID_HANDLE_VALUE` (-1). Note that not all Windows APIs use /// `INVALID_HANDLE_VALUE` for errors; see [here] for the full story. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[stable(feature = "io_safety", since = "1.63.0")] #[inline] pub unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self(OwnedHandle::from_raw_handle(handle)) } } #[stable(feature = "io_safety", since = "1.63.0")] impl Drop for OwnedHandle { #[inline] fn drop(&mut self) { unsafe { let _ = c::CloseHandle(self.handle); } } } #[stable(feature = "io_safety", since = "1.63.0")] impl fmt::Debug for BorrowedHandle<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("BorrowedHandle").field("handle", &self.handle).finish() } } #[stable(feature = "io_safety", since = "1.63.0")] impl fmt::Debug for OwnedHandle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OwnedHandle").field("handle", &self.handle).finish() } } /// A trait to borrow the handle from an underlying object. #[stable(feature = "io_safety", since = "1.63.0")] pub trait AsHandle { /// Borrows the handle. /// /// # Example /// /// ```rust,no_run /// use std::fs::File; /// # use std::io; /// use std::os::windows::io::{AsHandle, BorrowedHandle}; /// /// let mut f = File::open("foo.txt")?; /// let borrowed_handle: BorrowedHandle<'_> = f.as_handle(); /// # Ok::<(), io::Error>(()) /// ``` #[stable(feature = "io_safety", since = "1.63.0")] fn as_handle(&self) -> BorrowedHandle<'_>; } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for &T { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { T::as_handle(self) } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for &mut T { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { T::as_handle(self) } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for BorrowedHandle<'_> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { *self } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for OwnedHandle { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { // Safety: `OwnedHandle` and `BorrowedHandle` have the same validity // invariants, and the `BorrowdHandle` is bounded by the lifetime // of `&self`. unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for fs::File { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { self.as_inner().as_handle() } } #[stable(feature = "io_safety", since = "1.63.0")] impl From for OwnedHandle { #[inline] fn from(file: fs::File) -> OwnedHandle { file.into_inner().into_inner().into_inner().into() } } #[stable(feature = "io_safety", since = "1.63.0")] impl From for fs::File { #[inline] fn from(owned: OwnedHandle) -> Self { Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned))) } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for crate::io::Stdin { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl<'a> AsHandle for crate::io::StdinLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for crate::io::Stdout { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl<'a> AsHandle for crate::io::StdoutLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for crate::io::Stderr { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl<'a> AsHandle for crate::io::StderrLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for crate::process::ChildStdin { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl From for OwnedHandle { #[inline] fn from(child_stdin: crate::process::ChildStdin) -> OwnedHandle { unsafe { OwnedHandle::from_raw_handle(child_stdin.into_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for crate::process::ChildStdout { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl From for OwnedHandle { #[inline] fn from(child_stdout: crate::process::ChildStdout) -> OwnedHandle { unsafe { OwnedHandle::from_raw_handle(child_stdout.into_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for crate::process::ChildStderr { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl From for OwnedHandle { #[inline] fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle { unsafe { OwnedHandle::from_raw_handle(child_stderr.into_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for crate::thread::JoinHandle { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } #[stable(feature = "io_safety", since = "1.63.0")] impl From> for OwnedHandle { #[inline] fn from(join_handle: crate::thread::JoinHandle) -> OwnedHandle { join_handle.into_inner().into_handle().into_inner() } }