1 use std::fs::File; 2 use std::io; 3 use std::os::windows::io::{ 4 AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle, 5 }; 6 use std::path::Path; 7 use std::process; 8 9 /// A handle represents an owned and valid Windows handle to a file-like 10 /// object. 11 /// 12 /// When an owned handle is dropped, then the underlying raw handle is closed. 13 /// To get a borrowed handle, use `HandleRef`. 14 #[derive(Debug)] 15 pub struct Handle(File); 16 17 impl AsRawHandle for Handle { as_raw_handle(&self) -> RawHandle18 fn as_raw_handle(&self) -> RawHandle { 19 self.0.as_raw_handle() 20 } 21 } 22 23 impl FromRawHandle for Handle { from_raw_handle(handle: RawHandle) -> Handle24 unsafe fn from_raw_handle(handle: RawHandle) -> Handle { 25 Handle(File::from_raw_handle(handle)) 26 } 27 } 28 29 impl IntoRawHandle for Handle { into_raw_handle(self) -> RawHandle30 fn into_raw_handle(self) -> RawHandle { 31 self.0.into_raw_handle() 32 } 33 } 34 35 impl Handle { 36 /// Create an owned handle to the given file. 37 /// 38 /// When the returned handle is dropped, the file is closed. 39 /// 40 /// Note that if the given file represents a handle to a directory, then 41 /// it is generally required that it have been opened with the 42 /// [`FILE_FLAG_BACKUP_SEMANTICS`] flag in order to use it in various 43 /// calls such as `information` or `typ`. To have this done automatically 44 /// for you, use the `from_path_any` constructor. 45 /// 46 /// [`FILE_FLAG_BACKUP_SEMANTICS`]: https://docs.microsoft.com/en-us/windows/desktop/api/FileAPI/nf-fileapi-createfilea from_file(file: File) -> Handle47 pub fn from_file(file: File) -> Handle { 48 Handle(file) 49 } 50 51 /// Open a file to the given file path, and return an owned handle to that 52 /// file. 53 /// 54 /// When the returned handle is dropped, the file is closed. 55 /// 56 /// If there was a problem opening the file, then the corresponding error 57 /// is returned. from_path<P: AsRef<Path>>(path: P) -> io::Result<Handle>58 pub fn from_path<P: AsRef<Path>>(path: P) -> io::Result<Handle> { 59 Ok(Handle::from_file(File::open(path)?)) 60 } 61 62 /// Like `from_path`, but supports opening directory handles as well. 63 /// 64 /// If you use `from_path` on a directory, then subsequent queries using 65 /// that handle will fail. from_path_any<P: AsRef<Path>>(path: P) -> io::Result<Handle>66 pub fn from_path_any<P: AsRef<Path>>(path: P) -> io::Result<Handle> { 67 use std::fs::OpenOptions; 68 use std::os::windows::fs::OpenOptionsExt; 69 use winapi::um::winbase::FILE_FLAG_BACKUP_SEMANTICS; 70 71 let file = OpenOptions::new() 72 .read(true) 73 .custom_flags(FILE_FLAG_BACKUP_SEMANTICS) 74 .open(path)?; 75 Ok(Handle::from_file(file)) 76 } 77 78 /// Return this handle as a standard `File` reference. as_file(&self) -> &File79 pub fn as_file(&self) -> &File { 80 &self.0 81 } 82 83 /// Return this handle as a standard `File` mutable reference. as_file_mut(&mut self) -> &mut File84 pub fn as_file_mut(&mut self) -> &mut File { 85 &mut self.0 86 } 87 } 88 89 /// Represents a borrowed and valid Windows handle to a file-like object, such 90 /// as stdin/stdout/stderr or an actual file. 91 /// 92 /// When a borrowed handle is dropped, then the underlying raw handle is 93 /// **not** closed. To get an owned handle, use `Handle`. 94 #[derive(Debug)] 95 pub struct HandleRef(HandleRefInner); 96 97 /// The representation of a HandleRef, on which we define a custom Drop impl 98 /// that avoids closing the underlying raw handle. 99 #[derive(Debug)] 100 struct HandleRefInner(Option<File>); 101 102 impl Drop for HandleRefInner { drop(&mut self)103 fn drop(&mut self) { 104 self.0.take().unwrap().into_raw_handle(); 105 } 106 } 107 108 impl AsRawHandle for HandleRef { as_raw_handle(&self) -> RawHandle109 fn as_raw_handle(&self) -> RawHandle { 110 self.as_file().as_raw_handle() 111 } 112 } 113 114 impl Clone for HandleRef { clone(&self) -> HandleRef115 fn clone(&self) -> HandleRef { 116 unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } 117 } 118 } 119 120 impl HandleRef { 121 /// Create a borrowed handle to stdin. 122 /// 123 /// When the returned handle is dropped, stdin is not closed. stdin() -> HandleRef124 pub fn stdin() -> HandleRef { 125 unsafe { HandleRef::from_raw_handle(io::stdin().as_raw_handle()) } 126 } 127 128 /// Create a handle to stdout. 129 /// 130 /// When the returned handle is dropped, stdout is not closed. stdout() -> HandleRef131 pub fn stdout() -> HandleRef { 132 unsafe { HandleRef::from_raw_handle(io::stdout().as_raw_handle()) } 133 } 134 135 /// Create a handle to stderr. 136 /// 137 /// When the returned handle is dropped, stderr is not closed. stderr() -> HandleRef138 pub fn stderr() -> HandleRef { 139 unsafe { HandleRef::from_raw_handle(io::stderr().as_raw_handle()) } 140 } 141 142 /// Create a borrowed handle to the given file. 143 /// 144 /// When the returned handle is dropped, the file is not closed. from_file(file: &File) -> HandleRef145 pub fn from_file(file: &File) -> HandleRef { 146 unsafe { HandleRef::from_raw_handle(file.as_raw_handle()) } 147 } 148 149 /// Create a borrowed handle from the given raw handle. 150 /// 151 /// Note that unlike the `FromRawHandle` trait, this constructor does 152 /// **not** consume ownership of the given handle. That is, when the 153 /// borrowed handle created by this constructor is dropped, the underlying 154 /// handle will not be closed. 155 /// 156 /// # Safety 157 /// 158 /// This is unsafe because there is no guarantee that the given raw handle 159 /// is a valid handle. The caller must ensure this is true before invoking 160 /// this constructor. from_raw_handle(handle: RawHandle) -> HandleRef161 pub unsafe fn from_raw_handle(handle: RawHandle) -> HandleRef { 162 HandleRef(HandleRefInner(Some(File::from_raw_handle(handle)))) 163 } 164 165 /// Return this handle as a standard `File` reference. as_file(&self) -> &File166 pub fn as_file(&self) -> &File { 167 (self.0).0.as_ref().unwrap() 168 } 169 170 /// Return this handle as a standard `File` mutable reference. as_file_mut(&mut self) -> &mut File171 pub fn as_file_mut(&mut self) -> &mut File { 172 (self.0).0.as_mut().unwrap() 173 } 174 } 175 176 /// Construct borrowed and valid Windows handles from file-like objects. 177 pub trait AsHandleRef { 178 /// A borrowed handle that wraps the raw handle of the `Self` object. as_handle_ref(&self) -> HandleRef179 fn as_handle_ref(&self) -> HandleRef; 180 181 /// A convenience routine for extracting a `HandleRef` from `Self`, and 182 /// then extracting a raw handle from the `HandleRef`. as_raw(&self) -> RawHandle183 fn as_raw(&self) -> RawHandle { 184 self.as_handle_ref().as_raw_handle() 185 } 186 } 187 188 impl<'a, T: AsHandleRef> AsHandleRef for &'a T { as_handle_ref(&self) -> HandleRef189 fn as_handle_ref(&self) -> HandleRef { 190 (**self).as_handle_ref() 191 } 192 } 193 194 impl AsHandleRef for Handle { as_handle_ref(&self) -> HandleRef195 fn as_handle_ref(&self) -> HandleRef { 196 unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } 197 } 198 } 199 200 impl AsHandleRef for HandleRef { as_handle_ref(&self) -> HandleRef201 fn as_handle_ref(&self) -> HandleRef { 202 self.clone() 203 } 204 } 205 206 impl AsHandleRef for File { as_handle_ref(&self) -> HandleRef207 fn as_handle_ref(&self) -> HandleRef { 208 HandleRef::from_file(self) 209 } 210 } 211 212 impl AsHandleRef for io::Stdin { as_handle_ref(&self) -> HandleRef213 fn as_handle_ref(&self) -> HandleRef { 214 unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } 215 } 216 } 217 218 impl AsHandleRef for io::Stdout { as_handle_ref(&self) -> HandleRef219 fn as_handle_ref(&self) -> HandleRef { 220 unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } 221 } 222 } 223 224 impl AsHandleRef for io::Stderr { as_handle_ref(&self) -> HandleRef225 fn as_handle_ref(&self) -> HandleRef { 226 unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } 227 } 228 } 229 230 impl AsHandleRef for process::ChildStdin { as_handle_ref(&self) -> HandleRef231 fn as_handle_ref(&self) -> HandleRef { 232 unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } 233 } 234 } 235 236 impl AsHandleRef for process::ChildStdout { as_handle_ref(&self) -> HandleRef237 fn as_handle_ref(&self) -> HandleRef { 238 unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } 239 } 240 } 241 242 impl AsHandleRef for process::ChildStderr { as_handle_ref(&self) -> HandleRef243 fn as_handle_ref(&self) -> HandleRef { 244 unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } 245 } 246 } 247