@@ -20,10 +20,6 @@ pub struct PipeReader(AnonPipe);
20
20
#[ derive( Debug ) ]
21
21
pub struct PipeWriter ( AnonPipe ) ;
22
22
23
- /// The owned fd provided is not a pipe.
24
- #[ derive( Debug ) ]
25
- pub struct NotAPipeError ;
26
-
27
23
impl PipeReader {
28
24
/// Create a new [`PipeReader`] instance that shares the same underlying file description.
29
25
pub fn try_clone ( & self ) -> io:: Result < Self > {
@@ -89,7 +85,11 @@ mod unix {
89
85
use super :: * ;
90
86
91
87
use crate :: {
92
- os:: fd:: { AsFd , AsRawFd , BorrowedFd , FromRawFd , IntoRawFd , OwnedFd , RawFd } ,
88
+ fs:: File ,
89
+ os:: {
90
+ fd:: { AsFd , AsRawFd , BorrowedFd , FromRawFd , IntoRawFd , OwnedFd , RawFd } ,
91
+ unix:: fs:: FileTypeExt ,
92
+ } ,
93
93
sys:: {
94
94
fd:: FileDesc ,
95
95
pipe:: { anon_pipe, AnonPipe } ,
@@ -139,23 +139,61 @@ mod unix {
139
139
impl_traits ! ( PipeReader ) ;
140
140
impl_traits ! ( PipeWriter ) ;
141
141
142
- fn owned_fd_to_anon_pipe ( owned_fd : OwnedFd ) -> AnonPipe {
143
- AnonPipe :: from_inner ( FileDesc :: from_inner ( owned_fd) )
142
+ fn convert_to_pipe ( owned_fd : OwnedFd ) -> io:: Result < AnonPipe > {
143
+ let file = File :: from ( owned_fd) ;
144
+ if file. metadata ( ) ?. file_type ( ) . is_fifo ( ) {
145
+ Ok ( AnonPipe :: from_inner ( FileDesc :: from_inner ( OwnedFd :: from ( file) ) ) )
146
+ } else {
147
+ Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput , "Not a pipe" ) )
148
+ }
149
+ }
150
+
151
+ enum AccessMode {
152
+ Readable ,
153
+ Writable ,
154
+ }
155
+
156
+ fn check_access_mode ( pipe : AnonPipe , expected_access_mode : AccessMode ) -> io:: Result < AnonPipe > {
157
+ let ret = unsafe { libc:: fcntl ( pipe. as_raw_fd ( ) , libc:: F_GETFL ) } ;
158
+ let access_mode = ret & libc:: O_ACCMODE ;
159
+ let expected_access_mode_str = match expected_access_mode {
160
+ AccessMode :: Readable => "readable" ,
161
+ AccessMode :: Writable => "writable" ,
162
+ } ;
163
+ let expected_access_mode = match expected_access_mode {
164
+ AccessMode :: Readable => libc:: O_RDONLY ,
165
+ AccessMode :: Writable => libc:: O_WRONLY ,
166
+ } ;
167
+
168
+ if ret == -1 {
169
+ Err ( io:: Error :: last_os_error ( ) )
170
+ } else if access_mode == libc:: O_RDWR && access_mode == expected_access_mode {
171
+ Err ( io:: Error :: new (
172
+ io:: ErrorKind :: InvalidInput ,
173
+ format ! ( "Pipe {} is not {}" , pipe. as_raw_fd( ) , expected_access_mode_str) ,
174
+ ) )
175
+ } else {
176
+ Ok ( pipe)
177
+ }
144
178
}
145
179
146
180
impl TryFrom < OwnedFd > for PipeReader {
147
- type Error = NotAPipeError ;
181
+ type Error = io :: Error ;
148
182
149
183
fn try_from ( owned_fd : OwnedFd ) -> Result < Self , Self :: Error > {
150
- Ok ( Self ( owned_fd_to_anon_pipe ( owned_fd) ) )
184
+ convert_to_pipe ( owned_fd)
185
+ . and_then ( |pipe| check_access_mode ( pipe, AccessMode :: Readable ) )
186
+ . map ( Self )
151
187
}
152
188
}
153
189
154
190
impl TryFrom < OwnedFd > for PipeWriter {
155
- type Error = NotAPipeError ;
191
+ type Error = io :: Error ;
156
192
157
193
fn try_from ( owned_fd : OwnedFd ) -> Result < Self , Self :: Error > {
158
- Ok ( Self ( owned_fd_to_anon_pipe ( owned_fd) ) )
194
+ convert_to_pipe ( owned_fd)
195
+ . and_then ( |pipe| check_access_mode ( pipe, AccessMode :: Writable ) )
196
+ . map ( Self )
159
197
}
160
198
}
161
199
}
@@ -225,15 +263,15 @@ mod windows {
225
263
}
226
264
227
265
impl TryFrom < OwnedHandle > for PipeReader {
228
- type Error = NotAPipeError ;
266
+ type Error = io :: Error ;
229
267
230
268
fn try_from ( owned_handle : OwnedHandle ) -> Result < Self , Self :: Error > {
231
269
Ok ( Self ( owned_handle_to_anon_pipe ( owned_handle) ) )
232
270
}
233
271
}
234
272
235
273
impl TryFrom < OwnedHandle > for PipeWriter {
236
- type Error = NotAPipeError ;
274
+ type Error = io :: Error ;
237
275
238
276
fn try_from ( owned_handle : OwnedHandle ) -> Result < Self , Self :: Error > {
239
277
Ok ( Self ( owned_handle_to_anon_pipe ( owned_handle) ) )
0 commit comments