@@ -20,10 +20,6 @@ pub struct PipeReader(AnonPipe);
2020#[ derive( Debug ) ]
2121pub struct PipeWriter ( AnonPipe ) ;
2222
23- /// The owned fd provided is not a pipe.
24- #[ derive( Debug ) ]
25- pub struct NotAPipeError ;
26-
2723impl PipeReader {
2824 /// Create a new [`PipeReader`] instance that shares the same underlying file description.
2925 pub fn try_clone ( & self ) -> io:: Result < Self > {
@@ -89,7 +85,11 @@ mod unix {
8985 use super :: * ;
9086
9187 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+ } ,
9393 sys:: {
9494 fd:: FileDesc ,
9595 pipe:: { anon_pipe, AnonPipe } ,
@@ -139,23 +139,61 @@ mod unix {
139139 impl_traits ! ( PipeReader ) ;
140140 impl_traits ! ( PipeWriter ) ;
141141
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+ }
144178 }
145179
146180 impl TryFrom < OwnedFd > for PipeReader {
147- type Error = NotAPipeError ;
181+ type Error = io :: Error ;
148182
149183 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 )
151187 }
152188 }
153189
154190 impl TryFrom < OwnedFd > for PipeWriter {
155- type Error = NotAPipeError ;
191+ type Error = io :: Error ;
156192
157193 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 )
159197 }
160198 }
161199}
@@ -225,15 +263,15 @@ mod windows {
225263 }
226264
227265 impl TryFrom < OwnedHandle > for PipeReader {
228- type Error = NotAPipeError ;
266+ type Error = io :: Error ;
229267
230268 fn try_from ( owned_handle : OwnedHandle ) -> Result < Self , Self :: Error > {
231269 Ok ( Self ( owned_handle_to_anon_pipe ( owned_handle) ) )
232270 }
233271 }
234272
235273 impl TryFrom < OwnedHandle > for PipeWriter {
236- type Error = NotAPipeError ;
274+ type Error = io :: Error ;
237275
238276 fn try_from ( owned_handle : OwnedHandle ) -> Result < Self , Self :: Error > {
239277 Ok ( Self ( owned_handle_to_anon_pipe ( owned_handle) ) )
0 commit comments