]>
Commit | Line | Data |
---|---|---|
c295e0f8 XL |
1 | //! Windows-specific extensions to primitives in the [`std::process`] module. |
2 | //! | |
3 | //! [`std::process`]: crate::process | |
62682a34 SL |
4 | |
5 | #![stable(feature = "process_extensions", since = "1.2.0")] | |
6 | ||
136023e0 | 7 | use crate::ffi::OsStr; |
94222f64 XL |
8 | use crate::os::windows::io::{ |
9 | AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, | |
10 | }; | |
532ac7d7 | 11 | use crate::process; |
6a06907d | 12 | use crate::sealed::Sealed; |
532ac7d7 | 13 | use crate::sys; |
60c5eb7d | 14 | use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; |
62682a34 SL |
15 | |
16 | #[stable(feature = "process_extensions", since = "1.2.0")] | |
17 | impl FromRawHandle for process::Stdio { | |
18 | unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio { | |
94222f64 XL |
19 | let handle = sys::handle::Handle::from_raw_handle(handle as *mut _); |
20 | let io = sys::process::Stdio::Handle(handle); | |
21 | process::Stdio::from_inner(io) | |
22 | } | |
23 | } | |
24 | ||
923072b8 | 25 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
26 | impl From<OwnedHandle> for process::Stdio { |
27 | fn from(handle: OwnedHandle) -> process::Stdio { | |
28 | let handle = sys::handle::Handle::from_inner(handle); | |
7453a54e SL |
29 | let io = sys::process::Stdio::Handle(handle); |
30 | process::Stdio::from_inner(io) | |
62682a34 SL |
31 | } |
32 | } | |
33 | ||
34 | #[stable(feature = "process_extensions", since = "1.2.0")] | |
35 | impl AsRawHandle for process::Child { | |
cdc7bbd5 | 36 | #[inline] |
62682a34 | 37 | fn as_raw_handle(&self) -> RawHandle { |
94222f64 XL |
38 | self.as_inner().handle().as_raw_handle() as *mut _ |
39 | } | |
40 | } | |
41 | ||
923072b8 | 42 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
43 | impl AsHandle for process::Child { |
44 | #[inline] | |
45 | fn as_handle(&self) -> BorrowedHandle<'_> { | |
46 | self.as_inner().handle().as_handle() | |
62682a34 SL |
47 | } |
48 | } | |
49 | ||
c30ab7b3 | 50 | #[stable(feature = "into_raw_os", since = "1.4.0")] |
c1a9b12d SL |
51 | impl IntoRawHandle for process::Child { |
52 | fn into_raw_handle(self) -> RawHandle { | |
94222f64 XL |
53 | self.into_inner().into_handle().into_raw_handle() as *mut _ |
54 | } | |
55 | } | |
56 | ||
923072b8 | 57 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
58 | impl From<process::Child> for OwnedHandle { |
59 | fn from(child: process::Child) -> OwnedHandle { | |
60 | child.into_inner().into_handle().into_inner() | |
c1a9b12d SL |
61 | } |
62 | } | |
63 | ||
62682a34 SL |
64 | #[stable(feature = "process_extensions", since = "1.2.0")] |
65 | impl AsRawHandle for process::ChildStdin { | |
cdc7bbd5 | 66 | #[inline] |
62682a34 | 67 | fn as_raw_handle(&self) -> RawHandle { |
94222f64 | 68 | self.as_inner().handle().as_raw_handle() as *mut _ |
62682a34 SL |
69 | } |
70 | } | |
71 | ||
72 | #[stable(feature = "process_extensions", since = "1.2.0")] | |
73 | impl AsRawHandle for process::ChildStdout { | |
cdc7bbd5 | 74 | #[inline] |
62682a34 | 75 | fn as_raw_handle(&self) -> RawHandle { |
94222f64 | 76 | self.as_inner().handle().as_raw_handle() as *mut _ |
62682a34 SL |
77 | } |
78 | } | |
79 | ||
80 | #[stable(feature = "process_extensions", since = "1.2.0")] | |
81 | impl AsRawHandle for process::ChildStderr { | |
cdc7bbd5 | 82 | #[inline] |
62682a34 | 83 | fn as_raw_handle(&self) -> RawHandle { |
94222f64 | 84 | self.as_inner().handle().as_raw_handle() as *mut _ |
62682a34 SL |
85 | } |
86 | } | |
c1a9b12d | 87 | |
c30ab7b3 | 88 | #[stable(feature = "into_raw_os", since = "1.4.0")] |
c1a9b12d SL |
89 | impl IntoRawHandle for process::ChildStdin { |
90 | fn into_raw_handle(self) -> RawHandle { | |
94222f64 | 91 | self.into_inner().into_handle().into_raw_handle() as *mut _ |
c1a9b12d SL |
92 | } |
93 | } | |
94 | ||
c30ab7b3 | 95 | #[stable(feature = "into_raw_os", since = "1.4.0")] |
c1a9b12d SL |
96 | impl IntoRawHandle for process::ChildStdout { |
97 | fn into_raw_handle(self) -> RawHandle { | |
94222f64 | 98 | self.into_inner().into_handle().into_raw_handle() as *mut _ |
c1a9b12d SL |
99 | } |
100 | } | |
101 | ||
c30ab7b3 | 102 | #[stable(feature = "into_raw_os", since = "1.4.0")] |
c1a9b12d SL |
103 | impl IntoRawHandle for process::ChildStderr { |
104 | fn into_raw_handle(self) -> RawHandle { | |
94222f64 | 105 | self.into_inner().into_handle().into_raw_handle() as *mut _ |
c1a9b12d SL |
106 | } |
107 | } | |
a7813a04 | 108 | |
83c7162d | 109 | /// Windows-specific extensions to [`process::ExitStatus`]. |
5869c6ff XL |
110 | /// |
111 | /// This trait is sealed: it cannot be implemented outside the standard library. | |
112 | /// This is so that future additional methods are not breaking changes. | |
5bcae85e | 113 | #[stable(feature = "exit_status_from", since = "1.12.0")] |
6a06907d | 114 | pub trait ExitStatusExt: Sealed { |
a7813a04 XL |
115 | /// Creates a new `ExitStatus` from the raw underlying `u32` return value of |
116 | /// a process. | |
5bcae85e | 117 | #[stable(feature = "exit_status_from", since = "1.12.0")] |
a7813a04 XL |
118 | fn from_raw(raw: u32) -> Self; |
119 | } | |
120 | ||
c30ab7b3 | 121 | #[stable(feature = "exit_status_from", since = "1.12.0")] |
a7813a04 XL |
122 | impl ExitStatusExt for process::ExitStatus { |
123 | fn from_raw(raw: u32) -> Self { | |
124 | process::ExitStatus::from_inner(From::from(raw)) | |
125 | } | |
126 | } | |
476ff2be | 127 | |
83c7162d | 128 | /// Windows-specific extensions to the [`process::Command`] builder. |
6a06907d XL |
129 | /// |
130 | /// This trait is sealed: it cannot be implemented outside the standard library. | |
131 | /// This is so that future additional methods are not breaking changes. | |
32a655c1 | 132 | #[stable(feature = "windows_process_extensions", since = "1.16.0")] |
6a06907d | 133 | pub trait CommandExt: Sealed { |
476ff2be SL |
134 | /// Sets the [process creation flags][1] to be passed to `CreateProcess`. |
135 | /// | |
136 | /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. | |
cc61c64b | 137 | /// |
dfeec247 | 138 | /// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags |
32a655c1 | 139 | #[stable(feature = "windows_process_extensions", since = "1.16.0")] |
476ff2be | 140 | fn creation_flags(&mut self, flags: u32) -> &mut process::Command; |
6a06907d XL |
141 | |
142 | /// Forces all arguments to be wrapped in quote (`"`) characters. | |
143 | /// | |
144 | /// This is useful for passing arguments to [MSYS2/Cygwin][1] based | |
145 | /// executables: these programs will expand unquoted arguments containing | |
146 | /// wildcard characters (`?` and `*`) by searching for any file paths | |
147 | /// matching the wildcard pattern. | |
148 | /// | |
149 | /// Adding quotes has no effect when passing arguments to programs | |
150 | /// that use [msvcrt][2]. This includes programs built with both | |
151 | /// MinGW and MSVC. | |
152 | /// | |
153 | /// [1]: <https://github.com/msys2/MSYS2-packages/issues/2176> | |
154 | /// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx> | |
155 | #[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")] | |
156 | fn force_quotes(&mut self, enabled: bool) -> &mut process::Command; | |
136023e0 XL |
157 | |
158 | /// Append literal text to the command line without any quoting or escaping. | |
159 | /// | |
160 | /// This is useful for passing arguments to `cmd.exe /c`, which doesn't follow | |
161 | /// `CommandLineToArgvW` escaping rules. | |
04454e1e | 162 | #[stable(feature = "windows_process_extensions_raw_arg", since = "1.62.0")] |
136023e0 | 163 | fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut process::Command; |
923072b8 FG |
164 | |
165 | /// When [`process::Command`] creates pipes, request that our side is always async. | |
166 | /// | |
167 | /// By default [`process::Command`] may choose to use pipes where both ends | |
168 | /// are opened for synchronous read or write operations. By using | |
169 | /// `async_pipes(true)`, this behavior is overridden so that our side is | |
170 | /// always async. | |
171 | /// | |
172 | /// This is important because if doing async I/O a pipe or a file has to be | |
173 | /// opened for async access. | |
174 | /// | |
175 | /// The end of the pipe sent to the child process will always be synchronous | |
176 | /// regardless of this option. | |
177 | /// | |
178 | /// # Example | |
179 | /// | |
180 | /// ``` | |
181 | /// #![feature(windows_process_extensions_async_pipes)] | |
182 | /// use std::os::windows::process::CommandExt; | |
183 | /// use std::process::{Command, Stdio}; | |
184 | /// | |
185 | /// # let program = ""; | |
186 | /// | |
187 | /// Command::new(program) | |
188 | /// .async_pipes(true) | |
189 | /// .stdin(Stdio::piped()) | |
190 | /// .stdout(Stdio::piped()) | |
191 | /// .stderr(Stdio::piped()); | |
192 | /// ``` | |
193 | #[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")] | |
194 | fn async_pipes(&mut self, always_async: bool) -> &mut process::Command; | |
476ff2be SL |
195 | } |
196 | ||
32a655c1 | 197 | #[stable(feature = "windows_process_extensions", since = "1.16.0")] |
476ff2be SL |
198 | impl CommandExt for process::Command { |
199 | fn creation_flags(&mut self, flags: u32) -> &mut process::Command { | |
200 | self.as_inner_mut().creation_flags(flags); | |
201 | self | |
202 | } | |
6a06907d XL |
203 | |
204 | fn force_quotes(&mut self, enabled: bool) -> &mut process::Command { | |
205 | self.as_inner_mut().force_quotes(enabled); | |
206 | self | |
207 | } | |
136023e0 XL |
208 | |
209 | fn raw_arg<S: AsRef<OsStr>>(&mut self, raw_text: S) -> &mut process::Command { | |
210 | self.as_inner_mut().raw_arg(raw_text.as_ref()); | |
211 | self | |
212 | } | |
923072b8 FG |
213 | |
214 | fn async_pipes(&mut self, always_async: bool) -> &mut process::Command { | |
215 | // FIXME: This currently has an intentional no-op implementation. | |
216 | // For the time being our side of the pipes will always be async. | |
217 | // Once the ecosystem has adjusted, we may then be able to start making | |
218 | // use of synchronous pipes within the standard library. | |
219 | let _ = always_async; | |
220 | self | |
221 | } | |
476ff2be | 222 | } |
04454e1e FG |
223 | |
224 | #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")] | |
225 | pub trait ChildExt: Sealed { | |
226 | /// Extracts the main thread raw handle, without taking ownership | |
227 | #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")] | |
228 | fn main_thread_handle(&self) -> BorrowedHandle<'_>; | |
229 | } | |
230 | ||
231 | #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")] | |
232 | impl ChildExt for process::Child { | |
233 | fn main_thread_handle(&self) -> BorrowedHandle<'_> { | |
234 | self.handle.main_thread_handle() | |
235 | } | |
236 | } |