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