@@ -60,6 +60,63 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
6060 // A 64kb pipe capacity is the same as a typical Linux default.
6161 const PIPE_BUFFER_CAPACITY : u32 = 64 * 1024 ;
6262
63+ #[ cfg( target_vendor = "rust9x" ) ]
64+ {
65+ // Since Windows 9X/ME does not support creating named pipes (only connecting to remote pipes
66+ // created on NT), we'll have to make do with anonymous pipes, without overlapped I/O. In
67+ // particular, this means that we'll have to do reading from two threads in the case where both
68+ // stdout and stderr being piped (see `read2`).
69+
70+ // 9X/ME *does* have a kernel32 export entry for `CreateNamedPipe`, so an availability check
71+ // would not work. We're just gonna check the bit that's only set on non-unicode Windows
72+ // versions instead...
73+
74+ // The `AnonPipe` impl used in `read2` below needs to be able to cancel the overlapped i/o
75+ // operation, so we also have to check for `CancelIo` being available. This means that the
76+ // "modern" path is taken only for NT4+.
77+ if !crate :: sys:: compat:: checks:: supports_async_io ( ) {
78+ let size = mem:: size_of :: < c:: SECURITY_ATTRIBUTES > ( ) ;
79+ let mut sa = c:: SECURITY_ATTRIBUTES {
80+ nLength : size as u32 ,
81+ lpSecurityDescriptor : ptr:: null_mut ( ) ,
82+ // We follow the old "Creating a Child Process with Redirected Input and Output" MSDN
83+ // entry (pre-`SetHandleInformation`) here, duplicating the handle that is not being
84+ // sent to the child process as non-inheritable and then closing the inheritable one.
85+ // Usually, this would be racy, but this function is only called in `Stdio::to_handle`,
86+ // which is in turn only called form `process::spawn`, which acquires a lock on process
87+ // spawning because of this.
88+ bInheritHandle : c:: TRUE ,
89+ } ;
90+
91+ unsafe {
92+ let mut read_pipe = mem:: zeroed ( ) ;
93+ let mut write_pipe = mem:: zeroed ( ) ;
94+ crate :: sys:: cvt ( c:: CreatePipe (
95+ & mut read_pipe,
96+ & mut write_pipe,
97+ & mut sa,
98+ PIPE_BUFFER_CAPACITY ,
99+ ) ) ?;
100+ let read_pipe = Handle :: from_raw_handle ( read_pipe) ;
101+ let write_pipe = Handle :: from_raw_handle ( write_pipe) ;
102+
103+ let ( ours_inheritable, theirs) =
104+ if ours_readable { ( read_pipe, write_pipe) } else { ( write_pipe, read_pipe) } ;
105+
106+ // Make `ours` non-inheritable by duplicating it with the approriate setting
107+ let ours = ours_inheritable. duplicate ( 0 , false , c:: DUPLICATE_SAME_ACCESS ) ?;
108+
109+ // close the old, inheritable handle to the pipe end that is ours
110+ drop ( ours_inheritable) ;
111+
112+ return Ok ( Pipes {
113+ ours : AnonPipe { inner : ours } ,
114+ theirs : AnonPipe { inner : theirs } ,
115+ } ) ;
116+ }
117+ }
118+ }
119+
63120 // Note that we specifically do *not* use `CreatePipe` here because
64121 // unfortunately the anonymous pipes returned do not support overlapped
65122 // operations. Instead, we create a "hopefully unique" name and create a
@@ -232,6 +289,11 @@ impl AnonPipe {
232289 }
233290
234291 pub fn read ( & self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
292+ #[ cfg( target_vendor = "rust9x" ) ]
293+ if !crate :: sys:: compat:: checks:: supports_async_io ( ) {
294+ return self . inner . read ( buf) ;
295+ }
296+
235297 let result = unsafe {
236298 let len = crate :: cmp:: min ( buf. len ( ) , u32:: MAX as usize ) as u32 ;
237299 let ptr = buf. as_mut_ptr ( ) ;
@@ -251,6 +313,11 @@ impl AnonPipe {
251313 }
252314
253315 pub fn read_buf ( & self , mut buf : BorrowedCursor < ' _ > ) -> io:: Result < ( ) > {
316+ #[ cfg( target_vendor = "rust9x" ) ]
317+ if !crate :: sys:: compat:: checks:: supports_async_io ( ) {
318+ return self . inner . read_buf ( buf) ;
319+ }
320+
254321 let result = unsafe {
255322 let len = crate :: cmp:: min ( buf. capacity ( ) , u32:: MAX as usize ) as u32 ;
256323 let ptr = buf. as_mut ( ) . as_mut_ptr ( ) . cast :: < u8 > ( ) ;
@@ -289,6 +356,11 @@ impl AnonPipe {
289356 }
290357
291358 pub fn write ( & self , buf : & [ u8 ] ) -> io:: Result < usize > {
359+ #[ cfg( target_vendor = "rust9x" ) ]
360+ if !crate :: sys:: compat:: checks:: supports_async_io ( ) {
361+ return self . inner . write ( buf) ;
362+ }
363+
292364 unsafe {
293365 let len = crate :: cmp:: min ( buf. len ( ) , u32:: MAX as usize ) as u32 ;
294366 self . alertable_io_internal ( |overlapped, callback| {
@@ -408,6 +480,24 @@ pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) ->
408480 let p1 = p1. into_handle ( ) ;
409481 let p2 = p2. into_handle ( ) ;
410482
483+ #[ cfg( target_vendor = "rust9x" ) ]
484+ if !crate :: sys:: compat:: checks:: supports_async_io ( ) {
485+ // Since we are using anonymous pipes (= without overlapped I/O support) here, we can't do
486+ // async waiting on both stdout and stderr at the same time on one thread, so we have to
487+ // spawn an additional thread to do the waiting for the second pipe.
488+
489+ // See https://github.com/rust-lang/rust/pull/31618, where this was removed initially.
490+ let second_pipe = crate :: thread:: spawn ( move || {
491+ let mut ret = Vec :: new ( ) ;
492+ ( & p2) . read_to_end ( & mut ret) . map ( |_| ret)
493+ } ) ;
494+
495+ ( & p1) . read_to_end ( v1) ?;
496+ * v2 = second_pipe. join ( ) . unwrap ( ) ?;
497+
498+ return Ok ( ( ) ) ;
499+ }
500+
411501 let mut p1 = AsyncPipe :: new ( p1, v1) ?;
412502 let mut p2 = AsyncPipe :: new ( p2, v2) ?;
413503 let objs = [ p1. event . as_raw_handle ( ) , p2. event . as_raw_handle ( ) ] ;
0 commit comments