use std::fs::File; use std::io; use std::os::windows::io::{ AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle, }; use std::path::Path; use std::process; /// A handle represents an owned and valid Windows handle to a file-like /// object. /// /// When an owned handle is dropped, then the underlying raw handle is closed. /// To get a borrowed handle, use `HandleRef`. #[derive(Debug)] pub struct Handle(File); impl AsRawHandle for Handle { fn as_raw_handle(&self) -> RawHandle { self.0.as_raw_handle() } } impl FromRawHandle for Handle { unsafe fn from_raw_handle(handle: RawHandle) -> Handle { Handle(File::from_raw_handle(handle)) } } impl IntoRawHandle for Handle { fn into_raw_handle(self) -> RawHandle { self.0.into_raw_handle() } } impl Handle { /// Create an owned handle to the given file. /// /// When the returned handle is dropped, the file is closed. /// /// Note that if the given file represents a handle to a directory, then /// it is generally required that it have been opened with the /// [`FILE_FLAG_BACKUP_SEMANTICS`] flag in order to use it in various /// calls such as `information` or `typ`. To have this done automatically /// for you, use the `from_path_any` constructor. /// /// [`FILE_FLAG_BACKUP_SEMANTICS`]: https://docs.microsoft.com/en-us/windows/desktop/api/FileAPI/nf-fileapi-createfilea pub fn from_file(file: File) -> Handle { Handle(file) } /// Open a file to the given file path, and return an owned handle to that /// file. /// /// When the returned handle is dropped, the file is closed. /// /// If there was a problem opening the file, then the corresponding error /// is returned. pub fn from_path>(path: P) -> io::Result { Ok(Handle::from_file(File::open(path)?)) } /// Like `from_path`, but supports opening directory handles as well. /// /// If you use `from_path` on a directory, then subsequent queries using /// that handle will fail. pub fn from_path_any>(path: P) -> io::Result { use std::fs::OpenOptions; use std::os::windows::fs::OpenOptionsExt; use winapi::um::winbase::FILE_FLAG_BACKUP_SEMANTICS; let file = OpenOptions::new() .read(true) .custom_flags(FILE_FLAG_BACKUP_SEMANTICS) .open(path)?; Ok(Handle::from_file(file)) } /// Return this handle as a standard `File` reference. pub fn as_file(&self) -> &File { &self.0 } /// Return this handle as a standard `File` mutable reference. pub fn as_file_mut(&mut self) -> &mut File { &mut self.0 } } /// Represents a borrowed and valid Windows handle to a file-like object, such /// as stdin/stdout/stderr or an actual file. /// /// When a borrowed handle is dropped, then the underlying raw handle is /// **not** closed. To get an owned handle, use `Handle`. #[derive(Debug)] pub struct HandleRef(HandleRefInner); /// The representation of a HandleRef, on which we define a custom Drop impl /// that avoids closing the underlying raw handle. #[derive(Debug)] struct HandleRefInner(Option); impl Drop for HandleRefInner { fn drop(&mut self) { self.0.take().unwrap().into_raw_handle(); } } impl AsRawHandle for HandleRef { fn as_raw_handle(&self) -> RawHandle { self.as_file().as_raw_handle() } } impl Clone for HandleRef { fn clone(&self) -> HandleRef { unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } } } impl HandleRef { /// Create a borrowed handle to stdin. /// /// When the returned handle is dropped, stdin is not closed. pub fn stdin() -> HandleRef { unsafe { HandleRef::from_raw_handle(io::stdin().as_raw_handle()) } } /// Create a handle to stdout. /// /// When the returned handle is dropped, stdout is not closed. pub fn stdout() -> HandleRef { unsafe { HandleRef::from_raw_handle(io::stdout().as_raw_handle()) } } /// Create a handle to stderr. /// /// When the returned handle is dropped, stderr is not closed. pub fn stderr() -> HandleRef { unsafe { HandleRef::from_raw_handle(io::stderr().as_raw_handle()) } } /// Create a borrowed handle to the given file. /// /// When the returned handle is dropped, the file is not closed. pub fn from_file(file: &File) -> HandleRef { unsafe { HandleRef::from_raw_handle(file.as_raw_handle()) } } /// Create a borrowed handle from the given raw handle. /// /// Note that unlike the `FromRawHandle` trait, this constructor does /// **not** consume ownership of the given handle. That is, when the /// borrowed handle created by this constructor is dropped, the underlying /// handle will not be closed. /// /// # Safety /// /// This is unsafe because there is no guarantee that the given raw handle /// is a valid handle. The caller must ensure this is true before invoking /// this constructor. pub unsafe fn from_raw_handle(handle: RawHandle) -> HandleRef { HandleRef(HandleRefInner(Some(File::from_raw_handle(handle)))) } /// Return this handle as a standard `File` reference. pub fn as_file(&self) -> &File { (self.0).0.as_ref().unwrap() } /// Return this handle as a standard `File` mutable reference. pub fn as_file_mut(&mut self) -> &mut File { (self.0).0.as_mut().unwrap() } } /// Construct borrowed and valid Windows handles from file-like objects. pub trait AsHandleRef { /// A borrowed handle that wraps the raw handle of the `Self` object. fn as_handle_ref(&self) -> HandleRef; /// A convenience routine for extracting a `HandleRef` from `Self`, and /// then extracting a raw handle from the `HandleRef`. fn as_raw(&self) -> RawHandle { self.as_handle_ref().as_raw_handle() } } impl<'a, T: AsHandleRef> AsHandleRef for &'a T { fn as_handle_ref(&self) -> HandleRef { (**self).as_handle_ref() } } impl AsHandleRef for Handle { fn as_handle_ref(&self) -> HandleRef { unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } } } impl AsHandleRef for HandleRef { fn as_handle_ref(&self) -> HandleRef { self.clone() } } impl AsHandleRef for File { fn as_handle_ref(&self) -> HandleRef { HandleRef::from_file(self) } } impl AsHandleRef for io::Stdin { fn as_handle_ref(&self) -> HandleRef { unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } } } impl AsHandleRef for io::Stdout { fn as_handle_ref(&self) -> HandleRef { unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } } } impl AsHandleRef for io::Stderr { fn as_handle_ref(&self) -> HandleRef { unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } } } impl AsHandleRef for process::ChildStdin { fn as_handle_ref(&self) -> HandleRef { unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } } } impl AsHandleRef for process::ChildStdout { fn as_handle_ref(&self) -> HandleRef { unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } } } impl AsHandleRef for process::ChildStderr { fn as_handle_ref(&self) -> HandleRef { unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } } }