]> git.lizzy.rs Git - rust.git/blob - library/std/src/os/windows/io/handle.rs
0ecac6b447570503f17951036dc032077824f97d
[rust.git] / library / std / src / os / windows / io / handle.rs
1 //! Owned and borrowed OS handles.
2
3 #![unstable(feature = "io_safety", issue = "87074")]
4
5 use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
6 use crate::fmt;
7 use crate::fs;
8 use crate::io;
9 use crate::marker::PhantomData;
10 use crate::mem::forget;
11 use crate::ptr;
12 use crate::sys::c;
13 use crate::sys::cvt;
14 use crate::sys_common::{AsInner, FromInner, IntoInner};
15
16 /// A borrowed handle.
17 ///
18 /// This has a lifetime parameter to tie it to the lifetime of something that
19 /// owns the handle.
20 ///
21 /// This uses `repr(transparent)` and has the representation of a host handle,
22 /// so it can be used in FFI in places where a handle is passed as an argument,
23 /// it is not captured or consumed.
24 ///
25 /// Note that it *may* have the value `-1`, which in `BorrowedHandle` always
26 /// represents a valid handle value, such as [the current process handle], and
27 /// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See
28 /// [here] for the full story.
29 ///
30 /// And, it *may* have the value `NULL` (0), which can occur when consoles are
31 /// detached from processes, or when `windows_subsystem` is used.
32 ///
33 /// This type's `.to_owned()` implementation returns another `BorrowedHandle`
34 /// rather than an `OwnedHandle`. It just makes a trivial copy of the raw
35 /// handle, which is then borrowed under the same lifetime.
36 ///
37 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
38 /// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
39 #[derive(Copy, Clone)]
40 #[repr(transparent)]
41 #[unstable(feature = "io_safety", issue = "87074")]
42 pub struct BorrowedHandle<'handle> {
43     handle: RawHandle,
44     _phantom: PhantomData<&'handle OwnedHandle>,
45 }
46
47 /// An owned handle.
48 ///
49 /// This closes the handle on drop.
50 ///
51 /// Note that it *may* have the value `-1`, which in `OwnedHandle` always
52 /// represents a valid handle value, such as [the current process handle], and
53 /// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See
54 /// [here] for the full story.
55 ///
56 /// And, it *may* have the value `NULL` (0), which can occur when consoles are
57 /// detached from processes, or when `windows_subsystem` is used.
58 ///
59 /// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
60 /// it must not be used with handles to open registry keys which need to be
61 /// closed with [`RegCloseKey`] instead.
62 ///
63 /// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
64 /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
65 ///
66 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
67 /// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
68 #[repr(transparent)]
69 #[unstable(feature = "io_safety", issue = "87074")]
70 pub struct OwnedHandle {
71     handle: RawHandle,
72 }
73
74 /// FFI type for handles in return values or out parameters, where `NULL` is used
75 /// as a sentry value to indicate errors, such as in the return value of `CreateThread`. This uses
76 /// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
77 /// FFI declarations.
78 ///
79 /// The only thing you can usefully do with a `HandleOrNull` is to convert it into an
80 /// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
81 /// `NULL`. This ensures that such FFI calls cannot start using the handle without
82 /// checking for `NULL` first.
83 ///
84 /// This type may hold any handle value that [`OwnedHandle`] may hold. As with `OwnedHandle`, when
85 /// it holds `-1`, that value is interpreted as a valid handle value, such as
86 /// [the current process handle], and not `INVALID_HANDLE_VALUE`.
87 ///
88 /// If this holds a non-null handle, it will close the handle on drop.
89 ///
90 /// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
91 #[repr(transparent)]
92 #[unstable(feature = "io_safety", issue = "87074")]
93 #[derive(Debug)]
94 pub struct HandleOrNull(OwnedHandle);
95
96 /// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
97 /// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
98 /// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
99 /// FFI declarations.
100 ///
101 /// The only thing you can usefully do with a `HandleOrInvalid` is to convert it into an
102 /// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
103 /// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
104 /// checking for `INVALID_HANDLE_VALUE` first.
105 ///
106 /// This type may hold any handle value that [`OwnedHandle`] may hold, except that when it holds
107 /// `-1`, that value is interpreted to mean `INVALID_HANDLE_VALUE`.
108 ///
109 /// If holds a handle other than `INVALID_HANDLE_VALUE`, it will close the handle on drop.
110 #[repr(transparent)]
111 #[unstable(feature = "io_safety", issue = "87074")]
112 #[derive(Debug)]
113 pub struct HandleOrInvalid(OwnedHandle);
114
115 // The Windows [`HANDLE`] type may be transferred across and shared between
116 // thread boundaries (despite containing a `*mut void`, which in general isn't
117 // `Send` or `Sync`).
118 //
119 // [`HANDLE`]: std::os::windows::raw::HANDLE
120 unsafe impl Send for OwnedHandle {}
121 unsafe impl Send for HandleOrNull {}
122 unsafe impl Send for HandleOrInvalid {}
123 unsafe impl Send for BorrowedHandle<'_> {}
124 unsafe impl Sync for OwnedHandle {}
125 unsafe impl Sync for HandleOrNull {}
126 unsafe impl Sync for HandleOrInvalid {}
127 unsafe impl Sync for BorrowedHandle<'_> {}
128
129 impl BorrowedHandle<'_> {
130     /// Return a `BorrowedHandle` holding the given raw handle.
131     ///
132     /// # Safety
133     ///
134     /// The resource pointed to by `handle` must be a valid open handle, it
135     /// must remain open for the duration of the returned `BorrowedHandle`.
136     ///
137     /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
138     /// sometimes a valid handle value. See [here] for the full story.
139     ///
140     /// And, it *may* have the value `NULL` (0), which can occur when consoles are
141     /// detached from processes, or when `windows_subsystem` is used.
142     ///
143     /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
144     #[inline]
145     #[unstable(feature = "io_safety", issue = "87074")]
146     pub const unsafe fn borrow_raw(handle: RawHandle) -> Self {
147         Self { handle, _phantom: PhantomData }
148     }
149 }
150
151 impl TryFrom<HandleOrNull> for OwnedHandle {
152     type Error = NullHandleError;
153
154     #[inline]
155     fn try_from(handle_or_null: HandleOrNull) -> Result<Self, NullHandleError> {
156         let owned_handle = handle_or_null.0;
157         if owned_handle.handle.is_null() {
158             // Don't call `CloseHandle`; it'd be harmless, except that it could
159             // overwrite the `GetLastError` error.
160             forget(owned_handle);
161
162             Err(NullHandleError(()))
163         } else {
164             Ok(owned_handle)
165         }
166     }
167 }
168
169 impl OwnedHandle {
170     /// Creates a new `OwnedHandle` instance that shares the same underlying file handle
171     /// as the existing `OwnedHandle` instance.
172     pub fn try_clone(&self) -> crate::io::Result<Self> {
173         self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)
174     }
175
176     pub(crate) fn duplicate(
177         &self,
178         access: c::DWORD,
179         inherit: bool,
180         options: c::DWORD,
181     ) -> io::Result<Self> {
182         let handle = self.as_raw_handle();
183
184         // `Stdin`, `Stdout`, and `Stderr` can all hold null handles, such as
185         // in a process with a detached console. `DuplicateHandle` would fail
186         // if we passed it a null handle, but we can treat null as a valid
187         // handle which doesn't do any I/O, and allow it to be duplicated.
188         if handle.is_null() {
189             return unsafe { Ok(Self::from_raw_handle(handle)) };
190         }
191
192         let mut ret = ptr::null_mut();
193         cvt(unsafe {
194             let cur_proc = c::GetCurrentProcess();
195             c::DuplicateHandle(
196                 cur_proc,
197                 handle,
198                 cur_proc,
199                 &mut ret,
200                 access,
201                 inherit as c::BOOL,
202                 options,
203             )
204         })?;
205         unsafe { Ok(Self::from_raw_handle(ret)) }
206     }
207
208     /// Allow child processes to inherit the handle.
209     #[cfg(not(target_vendor = "uwp"))]
210     pub(crate) fn set_inheritable(&self) -> io::Result<()> {
211         cvt(unsafe {
212             c::SetHandleInformation(
213                 self.as_raw_handle(),
214                 c::HANDLE_FLAG_INHERIT,
215                 c::HANDLE_FLAG_INHERIT,
216             )
217         })?;
218         Ok(())
219     }
220 }
221
222 impl TryFrom<HandleOrInvalid> for OwnedHandle {
223     type Error = InvalidHandleError;
224
225     #[inline]
226     fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, InvalidHandleError> {
227         let owned_handle = handle_or_invalid.0;
228         if owned_handle.handle == c::INVALID_HANDLE_VALUE {
229             // Don't call `CloseHandle`; it'd be harmless, except that it could
230             // overwrite the `GetLastError` error.
231             forget(owned_handle);
232
233             Err(InvalidHandleError(()))
234         } else {
235             Ok(owned_handle)
236         }
237     }
238 }
239
240 /// This is the error type used by [`HandleOrNull`] when attempting to convert
241 /// into a handle, to indicate that the value is null.
242 // The empty field prevents constructing this, and allows extending it in the future.
243 #[unstable(feature = "io_safety", issue = "87074")]
244 #[derive(Debug, Clone, PartialEq, Eq)]
245 pub struct NullHandleError(());
246
247 #[unstable(feature = "io_safety", issue = "87074")]
248 impl fmt::Display for NullHandleError {
249     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
250         "A HandleOrNull could not be converted to a handle because it was null".fmt(fmt)
251     }
252 }
253
254 #[unstable(feature = "io_safety", issue = "87074")]
255 impl crate::error::Error for NullHandleError {}
256
257 /// This is the error type used by [`HandleOrInvalid`] when attempting to
258 /// convert into a handle, to indicate that the value is
259 /// `INVALID_HANDLE_VALUE`.
260 // The empty field prevents constructing this, and allows extending it in the future.
261 #[unstable(feature = "io_safety", issue = "87074")]
262 #[derive(Debug, Clone, PartialEq, Eq)]
263 pub struct InvalidHandleError(());
264
265 #[unstable(feature = "io_safety", issue = "87074")]
266 impl fmt::Display for InvalidHandleError {
267     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
268         "A HandleOrInvalid could not be converted to a handle because it was INVALID_HANDLE_VALUE"
269             .fmt(fmt)
270     }
271 }
272
273 #[unstable(feature = "io_safety", issue = "87074")]
274 impl crate::error::Error for InvalidHandleError {}
275
276 impl AsRawHandle for BorrowedHandle<'_> {
277     #[inline]
278     fn as_raw_handle(&self) -> RawHandle {
279         self.handle
280     }
281 }
282
283 impl AsRawHandle for OwnedHandle {
284     #[inline]
285     fn as_raw_handle(&self) -> RawHandle {
286         self.handle
287     }
288 }
289
290 impl IntoRawHandle for OwnedHandle {
291     #[inline]
292     fn into_raw_handle(self) -> RawHandle {
293         let handle = self.handle;
294         forget(self);
295         handle
296     }
297 }
298
299 impl FromRawHandle for OwnedHandle {
300     #[inline]
301     unsafe fn from_raw_handle(handle: RawHandle) -> Self {
302         Self { handle }
303     }
304 }
305
306 impl HandleOrNull {
307     /// Constructs a new instance of `Self` from the given `RawHandle` returned
308     /// from a Windows API that uses null to indicate failure, such as
309     /// `CreateThread`.
310     ///
311     /// Use `HandleOrInvalid` instead of `HandleOrNull` for APIs that
312     /// use `INVALID_HANDLE_VALUE` to indicate failure.
313     ///
314     /// # Safety
315     ///
316     /// The passed `handle` value must either satisfy the safety requirements
317     /// of [`FromRawHandle::from_raw_handle`], or be null. Note that not all
318     /// Windows APIs use null for errors; see [here] for the full story.
319     ///
320     /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
321     #[inline]
322     pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
323         Self(OwnedHandle::from_raw_handle(handle))
324     }
325 }
326
327 impl HandleOrInvalid {
328     /// Constructs a new instance of `Self` from the given `RawHandle` returned
329     /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
330     /// failure, such as `CreateFileW`.
331     ///
332     /// Use `HandleOrNull` instead of `HandleOrInvalid` for APIs that
333     /// use null to indicate failure.
334     ///
335     /// # Safety
336     ///
337     /// The passed `handle` value must either satisfy the safety requirements
338     /// of [`FromRawHandle::from_raw_handle`], or be
339     /// `INVALID_HANDLE_VALUE` (-1). Note that not all Windows APIs use
340     /// `INVALID_HANDLE_VALUE` for errors; see [here] for the full story.
341     ///
342     /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
343     #[inline]
344     pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
345         Self(OwnedHandle::from_raw_handle(handle))
346     }
347 }
348
349 impl Drop for OwnedHandle {
350     #[inline]
351     fn drop(&mut self) {
352         unsafe {
353             let _ = c::CloseHandle(self.handle);
354         }
355     }
356 }
357
358 impl fmt::Debug for BorrowedHandle<'_> {
359     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360         f.debug_struct("BorrowedHandle").field("handle", &self.handle).finish()
361     }
362 }
363
364 impl fmt::Debug for OwnedHandle {
365     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366         f.debug_struct("OwnedHandle").field("handle", &self.handle).finish()
367     }
368 }
369
370 /// A trait to borrow the handle from an underlying object.
371 #[unstable(feature = "io_safety", issue = "87074")]
372 pub trait AsHandle {
373     /// Borrows the handle.
374     ///
375     /// # Example
376     ///
377     /// ```rust,no_run
378     /// # #![feature(io_safety)]
379     /// use std::fs::File;
380     /// # use std::io;
381     /// use std::os::windows::io::{AsHandle, BorrowedHandle};
382     ///
383     /// let mut f = File::open("foo.txt")?;
384     /// let borrowed_handle: BorrowedHandle<'_> = f.as_handle();
385     /// # Ok::<(), io::Error>(())
386     /// ```
387     fn as_handle(&self) -> BorrowedHandle<'_>;
388 }
389
390 #[unstable(feature = "io_safety", issue = "87074")]
391 impl<T: AsHandle> AsHandle for &T {
392     #[inline]
393     fn as_handle(&self) -> BorrowedHandle<'_> {
394         T::as_handle(self)
395     }
396 }
397
398 #[unstable(feature = "io_safety", issue = "87074")]
399 impl<T: AsHandle> AsHandle for &mut T {
400     #[inline]
401     fn as_handle(&self) -> BorrowedHandle<'_> {
402         T::as_handle(self)
403     }
404 }
405
406 impl AsHandle for BorrowedHandle<'_> {
407     #[inline]
408     fn as_handle(&self) -> BorrowedHandle<'_> {
409         *self
410     }
411 }
412
413 impl AsHandle for OwnedHandle {
414     #[inline]
415     fn as_handle(&self) -> BorrowedHandle<'_> {
416         // Safety: `OwnedHandle` and `BorrowedHandle` have the same validity
417         // invariants, and the `BorrowdHandle` is bounded by the lifetime
418         // of `&self`.
419         unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
420     }
421 }
422
423 impl AsHandle for fs::File {
424     #[inline]
425     fn as_handle(&self) -> BorrowedHandle<'_> {
426         self.as_inner().as_handle()
427     }
428 }
429
430 impl From<fs::File> for OwnedHandle {
431     #[inline]
432     fn from(file: fs::File) -> OwnedHandle {
433         file.into_inner().into_inner().into_inner().into()
434     }
435 }
436
437 impl From<OwnedHandle> for fs::File {
438     #[inline]
439     fn from(owned: OwnedHandle) -> Self {
440         Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned)))
441     }
442 }
443
444 impl AsHandle for crate::io::Stdin {
445     #[inline]
446     fn as_handle(&self) -> BorrowedHandle<'_> {
447         unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
448     }
449 }
450
451 impl<'a> AsHandle for crate::io::StdinLock<'a> {
452     #[inline]
453     fn as_handle(&self) -> BorrowedHandle<'_> {
454         unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
455     }
456 }
457
458 impl AsHandle for crate::io::Stdout {
459     #[inline]
460     fn as_handle(&self) -> BorrowedHandle<'_> {
461         unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
462     }
463 }
464
465 impl<'a> AsHandle for crate::io::StdoutLock<'a> {
466     #[inline]
467     fn as_handle(&self) -> BorrowedHandle<'_> {
468         unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
469     }
470 }
471
472 impl AsHandle for crate::io::Stderr {
473     #[inline]
474     fn as_handle(&self) -> BorrowedHandle<'_> {
475         unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
476     }
477 }
478
479 impl<'a> AsHandle for crate::io::StderrLock<'a> {
480     #[inline]
481     fn as_handle(&self) -> BorrowedHandle<'_> {
482         unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
483     }
484 }
485
486 impl AsHandle for crate::process::ChildStdin {
487     #[inline]
488     fn as_handle(&self) -> BorrowedHandle<'_> {
489         unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
490     }
491 }
492
493 impl From<crate::process::ChildStdin> for OwnedHandle {
494     #[inline]
495     fn from(child_stdin: crate::process::ChildStdin) -> OwnedHandle {
496         unsafe { OwnedHandle::from_raw_handle(child_stdin.into_raw_handle()) }
497     }
498 }
499
500 impl AsHandle for crate::process::ChildStdout {
501     #[inline]
502     fn as_handle(&self) -> BorrowedHandle<'_> {
503         unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
504     }
505 }
506
507 impl From<crate::process::ChildStdout> for OwnedHandle {
508     #[inline]
509     fn from(child_stdout: crate::process::ChildStdout) -> OwnedHandle {
510         unsafe { OwnedHandle::from_raw_handle(child_stdout.into_raw_handle()) }
511     }
512 }
513
514 impl AsHandle for crate::process::ChildStderr {
515     #[inline]
516     fn as_handle(&self) -> BorrowedHandle<'_> {
517         unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
518     }
519 }
520
521 impl From<crate::process::ChildStderr> for OwnedHandle {
522     #[inline]
523     fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle {
524         unsafe { OwnedHandle::from_raw_handle(child_stderr.into_raw_handle()) }
525     }
526 }
527
528 impl<T> AsHandle for crate::thread::JoinHandle<T> {
529     #[inline]
530     fn as_handle(&self) -> BorrowedHandle<'_> {
531         unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
532     }
533 }
534
535 impl<T> From<crate::thread::JoinHandle<T>> for OwnedHandle {
536     #[inline]
537     fn from(join_handle: crate::thread::JoinHandle<T>) -> OwnedHandle {
538         join_handle.into_inner().into_handle().into_inner()
539     }
540 }