winapi_util/
win.rs

1use std::{
2    fs::File,
3    io,
4    os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle},
5    path::Path,
6    process,
7};
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)]
15pub struct Handle(File);
16
17impl AsRawHandle for Handle {
18    fn as_raw_handle(&self) -> RawHandle {
19        self.0.as_raw_handle()
20    }
21}
22
23impl FromRawHandle for Handle {
24    unsafe fn from_raw_handle(handle: RawHandle) -> Handle {
25        Handle(File::from_raw_handle(handle))
26    }
27}
28
29impl IntoRawHandle for Handle {
30    fn into_raw_handle(self) -> RawHandle {
31        self.0.into_raw_handle()
32    }
33}
34
35impl 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
47    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.
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.
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 windows_sys::Win32::Storage::FileSystem::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.
79    pub fn as_file(&self) -> &File {
80        &self.0
81    }
82
83    /// Return this handle as a standard `File` mutable reference.
84    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)]
95pub 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)]
100struct HandleRefInner(Option<File>);
101
102impl Drop for HandleRefInner {
103    fn drop(&mut self) {
104        self.0.take().unwrap().into_raw_handle();
105    }
106}
107
108impl AsRawHandle for HandleRef {
109    fn as_raw_handle(&self) -> RawHandle {
110        self.as_file().as_raw_handle()
111    }
112}
113
114impl Clone for HandleRef {
115    fn clone(&self) -> HandleRef {
116        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
117    }
118}
119
120impl HandleRef {
121    /// Create a borrowed handle to stdin.
122    ///
123    /// When the returned handle is dropped, stdin is not closed.
124    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.
131    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.
138    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.
145    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.
161    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.
166    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.
171    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.
177pub trait AsHandleRef {
178    /// A borrowed handle that wraps the raw handle of the `Self` object.
179    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`.
183    fn as_raw(&self) -> RawHandle {
184        self.as_handle_ref().as_raw_handle()
185    }
186}
187
188impl<'a, T: AsHandleRef> AsHandleRef for &'a T {
189    fn as_handle_ref(&self) -> HandleRef {
190        (**self).as_handle_ref()
191    }
192}
193
194impl AsHandleRef for Handle {
195    fn as_handle_ref(&self) -> HandleRef {
196        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
197    }
198}
199
200impl AsHandleRef for HandleRef {
201    fn as_handle_ref(&self) -> HandleRef {
202        self.clone()
203    }
204}
205
206impl AsHandleRef for File {
207    fn as_handle_ref(&self) -> HandleRef {
208        HandleRef::from_file(self)
209    }
210}
211
212impl AsHandleRef for io::Stdin {
213    fn as_handle_ref(&self) -> HandleRef {
214        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
215    }
216}
217
218impl AsHandleRef for io::Stdout {
219    fn as_handle_ref(&self) -> HandleRef {
220        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
221    }
222}
223
224impl AsHandleRef for io::Stderr {
225    fn as_handle_ref(&self) -> HandleRef {
226        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
227    }
228}
229
230impl AsHandleRef for process::ChildStdin {
231    fn as_handle_ref(&self) -> HandleRef {
232        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
233    }
234}
235
236impl AsHandleRef for process::ChildStdout {
237    fn as_handle_ref(&self) -> HandleRef {
238        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
239    }
240}
241
242impl AsHandleRef for process::ChildStderr {
243    fn as_handle_ref(&self) -> HandleRef {
244        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
245    }
246}