@@ -29,18 +29,43 @@ pub struct AnonPipe {
29
29
inner : Handle ,
30
30
}
31
31
32
- pub fn anon_pipe ( ) -> io:: Result < ( AnonPipe , AnonPipe ) > {
32
+ pub struct Pipes {
33
+ pub ours : AnonPipe ,
34
+ pub theirs : AnonPipe ,
35
+ }
36
+
37
+ /// Although this looks similar to `anon_pipe` in the Unix module it's actually
38
+ /// subtly different. Here we'll return two pipes in the `Pipes` return value,
39
+ /// but one is intended for "us" where as the other is intended for "someone
40
+ /// else".
41
+ ///
42
+ /// Currently the only use case for this function is pipes for stdio on
43
+ /// processes in the standard library, so "ours" is the one that'll stay in our
44
+ /// process whereas "theirs" will be inherited to a child.
45
+ ///
46
+ /// The ours/theirs pipes are *not* specifically readable or writable. Each
47
+ /// one only supports a read or a write, but which is which depends on the
48
+ /// boolean flag given. If `ours_readable` is true then `ours` is readable where
49
+ /// `theirs` is writable. Conversely if `ours_readable` is false then `ours` is
50
+ /// writable where `theirs` is readable.
51
+ ///
52
+ /// Also note that the `ours` pipe is always a handle opened up in overlapped
53
+ /// mode. This means that technically speaking it should only ever be used
54
+ /// with `OVERLAPPED` instances, but also works out ok if it's only ever used
55
+ /// once at a time (which we do indeed guarantee).
56
+ pub fn anon_pipe ( ours_readable : bool ) -> io:: Result < Pipes > {
33
57
// Note that we specifically do *not* use `CreatePipe` here because
34
58
// unfortunately the anonymous pipes returned do not support overlapped
35
- // operations.
36
- //
37
- // Instead, we create a "hopefully unique" name and create a named pipe
38
- // which has overlapped operations enabled.
59
+ // operations. Instead, we create a "hopefully unique" name and create a
60
+ // named pipe which has overlapped operations enabled.
39
61
//
40
- // Once we do this, we connect do it as usual via `CreateFileW`, and then we
41
- // return those reader/writer halves.
62
+ // Once we do this, we connect do it as usual via `CreateFileW`, and then
63
+ // we return those reader/writer halves. Note that the `ours` pipe return
64
+ // value is always the named pipe, whereas `theirs` is just the normal file.
65
+ // This should hopefully shield us from child processes which assume their
66
+ // stdout is a named pipe, which would indeed be odd!
42
67
unsafe {
43
- let reader ;
68
+ let ours ;
44
69
let mut name;
45
70
let mut tries = 0 ;
46
71
let mut reject_remote_clients_flag = c:: PIPE_REJECT_REMOTE_CLIENTS ;
@@ -54,11 +79,16 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
54
79
. encode_wide ( )
55
80
. chain ( Some ( 0 ) )
56
81
. collect :: < Vec < _ > > ( ) ;
82
+ let mut flags = c:: FILE_FLAG_FIRST_PIPE_INSTANCE |
83
+ c:: FILE_FLAG_OVERLAPPED ;
84
+ if ours_readable {
85
+ flags |= c:: PIPE_ACCESS_INBOUND ;
86
+ } else {
87
+ flags |= c:: PIPE_ACCESS_OUTBOUND ;
88
+ }
57
89
58
90
let handle = c:: CreateNamedPipeW ( wide_name. as_ptr ( ) ,
59
- c:: PIPE_ACCESS_INBOUND |
60
- c:: FILE_FLAG_FIRST_PIPE_INSTANCE |
61
- c:: FILE_FLAG_OVERLAPPED ,
91
+ flags,
62
92
c:: PIPE_TYPE_BYTE |
63
93
c:: PIPE_READMODE_BYTE |
64
94
c:: PIPE_WAIT |
@@ -101,21 +131,28 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
101
131
}
102
132
return Err ( err)
103
133
}
104
- reader = Handle :: new ( handle) ;
134
+ ours = Handle :: new ( handle) ;
105
135
break
106
136
}
107
137
108
- // Connect to the named pipe we just created in write-only mode (also
109
- // overlapped for async I/O below).
138
+ // Connect to the named pipe we just created. This handle is going to be
139
+ // returned in `theirs`, so if `ours` is readable we want this to be
140
+ // writable, otherwise if `ours` is writable we want this to be
141
+ // readable.
142
+ //
143
+ // Additionally we don't enable overlapped mode on this because most
144
+ // client processes aren't enabled to work with that.
110
145
let mut opts = OpenOptions :: new ( ) ;
111
- opts. write ( true ) ;
112
- opts. read ( false ) ;
146
+ opts. write ( ours_readable ) ;
147
+ opts. read ( !ours_readable ) ;
113
148
opts. share_mode ( 0 ) ;
114
- opts. attributes ( c:: FILE_FLAG_OVERLAPPED ) ;
115
- let writer = File :: open ( Path :: new ( & name) , & opts) ?;
116
- let writer = AnonPipe { inner : writer. into_handle ( ) } ;
149
+ let theirs = File :: open ( Path :: new ( & name) , & opts) ?;
150
+ let theirs = AnonPipe { inner : theirs. into_handle ( ) } ;
117
151
118
- Ok ( ( AnonPipe { inner : reader } , AnonPipe { inner : writer. into_handle ( ) } ) )
152
+ Ok ( Pipes {
153
+ ours : AnonPipe { inner : ours } ,
154
+ theirs : AnonPipe { inner : theirs. into_handle ( ) } ,
155
+ } )
119
156
}
120
157
}
121
158
0 commit comments