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