@@ -60,6 +60,63 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
60
60
// A 64kb pipe capacity is the same as a typical Linux default.
61
61
const PIPE_BUFFER_CAPACITY : u32 = 64 * 1024 ;
62
62
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
+
63
120
// Note that we specifically do *not* use `CreatePipe` here because
64
121
// unfortunately the anonymous pipes returned do not support overlapped
65
122
// operations. Instead, we create a "hopefully unique" name and create a
@@ -232,6 +289,11 @@ impl AnonPipe {
232
289
}
233
290
234
291
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
+
235
297
let result = unsafe {
236
298
let len = crate :: cmp:: min ( buf. len ( ) , u32:: MAX as usize ) as u32 ;
237
299
let ptr = buf. as_mut_ptr ( ) ;
@@ -251,6 +313,11 @@ impl AnonPipe {
251
313
}
252
314
253
315
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
+
254
321
let result = unsafe {
255
322
let len = crate :: cmp:: min ( buf. capacity ( ) , u32:: MAX as usize ) as u32 ;
256
323
let ptr = buf. as_mut ( ) . as_mut_ptr ( ) . cast :: < u8 > ( ) ;
@@ -289,6 +356,11 @@ impl AnonPipe {
289
356
}
290
357
291
358
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
+
292
364
unsafe {
293
365
let len = crate :: cmp:: min ( buf. len ( ) , u32:: MAX as usize ) as u32 ;
294
366
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>) ->
408
480
let p1 = p1. into_handle ( ) ;
409
481
let p2 = p2. into_handle ( ) ;
410
482
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
+
411
501
let mut p1 = AsyncPipe :: new ( p1, v1) ?;
412
502
let mut p2 = AsyncPipe :: new ( p2, v2) ?;
413
503
let objs = [ p1. event . as_raw_handle ( ) , p2. event . as_raw_handle ( ) ] ;
0 commit comments