@@ -35,6 +35,9 @@ use std::ffi::OsString;
3535use std:: fs:: Metadata ;
3636use std:: fs:: { File , OpenOptions } ;
3737use std:: io:: { self , Read , Seek , SeekFrom , Write } ;
38+ use std:: mem:: ManuallyDrop ;
39+ use std:: ops:: Deref ;
40+ use std:: ops:: DerefMut ;
3841#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
3942use std:: os:: fd:: AsFd ;
4043#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
@@ -205,6 +208,34 @@ fn read_and_discard<R: Read>(reader: &mut R, n: u64, buf_size: usize) -> io::Res
205208 Ok ( total)
206209}
207210
211+ #[ cfg( unix) ]
212+ struct StdinRaw ( ManuallyDrop < File > ) ;
213+
214+ #[ cfg( unix) ]
215+ impl StdinRaw {
216+ fn new ( ) -> Self {
217+ let fd = io:: stdin ( ) . as_raw_fd ( ) ;
218+ let f = unsafe { File :: from_raw_fd ( fd) } ;
219+ Self ( ManuallyDrop :: new ( f) )
220+ }
221+ }
222+
223+ #[ cfg( unix) ]
224+ impl Deref for StdinRaw {
225+ type Target = File ;
226+
227+ fn deref ( & self ) -> & Self :: Target {
228+ & self . 0
229+ }
230+ }
231+
232+ #[ cfg( unix) ]
233+ impl DerefMut for StdinRaw {
234+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
235+ & mut self . 0
236+ }
237+ }
238+
208239/// Data sources.
209240///
210241/// Use [`Source::stdin_as_file`] if available to enable more
@@ -219,7 +250,7 @@ enum Source {
219250
220251 /// Input from stdin, opened from its file descriptor.
221252 #[ cfg( unix) ]
222- StdinFile ( File ) ,
253+ StdinRaw ( StdinRaw ) ,
223254
224255 /// Input from a named pipe, also known as a FIFO.
225256 #[ cfg( unix) ]
@@ -229,16 +260,14 @@ enum Source {
229260impl Source {
230261 /// Create a source from stdin using its raw file descriptor.
231262 ///
232- /// This returns an instance of the `Source::StdinFile ` variant,
263+ /// This returns an instance of the `Source::StdinRaw ` variant,
233264 /// using the raw file descriptor of [`io::Stdin`] to create
234265 /// the [`File`] parameter. You can use this instead of
235266 /// `Source::Stdin` to allow reading from stdin without consuming
236267 /// the entire contents of stdin when this process terminates.
237268 #[ cfg( unix) ]
238- fn stdin_as_file ( ) -> Self {
239- let fd = io:: stdin ( ) . as_raw_fd ( ) ;
240- let f = unsafe { File :: from_raw_fd ( fd) } ;
241- Self :: StdinFile ( f)
269+ fn stdin_raw ( ) -> Self {
270+ Self :: StdinRaw ( StdinRaw :: new ( ) )
242271 }
243272
244273 fn skip ( & mut self , n : u64 , ibs : usize ) -> io:: Result < u64 > {
@@ -255,7 +284,7 @@ impl Source {
255284 Ok ( m)
256285 }
257286 #[ cfg( unix) ]
258- Self :: StdinFile ( f) => {
287+ Self :: StdinRaw ( f) => {
259288 if let Ok ( Some ( len) ) = try_get_len_of_block_device ( f)
260289 && len < n
261290 {
@@ -284,7 +313,7 @@ impl Source {
284313 // ESPIPE means the file descriptor is not seekable (e.g., a pipe),
285314 // so fall back to reading and discarding bytes using ibs-sized buffer
286315 Some ( Err ( e) ) if e. raw_os_error ( ) == Some ( libc:: ESPIPE ) => {
287- let m = read_and_discard ( f, n, ibs) ?;
316+ let m = read_and_discard :: < File > ( f, n, ibs) ?;
288317 if m < n {
289318 show_error ! (
290319 "{}" ,
@@ -335,7 +364,7 @@ impl Read for Source {
335364 Self :: Stdin ( stdin) => stdin. read ( buf) ,
336365 Self :: File ( f) => f. read ( buf) ,
337366 #[ cfg( unix) ]
338- Self :: StdinFile ( f) => f. read ( buf) ,
367+ Self :: StdinRaw ( f) => f. read ( buf) ,
339368 #[ cfg( unix) ]
340369 Self :: Fifo ( f) => f. read ( buf) ,
341370 }
@@ -379,9 +408,9 @@ impl<'a> Input<'a> {
379408 }
380409 } ;
381410 #[ cfg( unix) ]
382- let mut src = Source :: stdin_as_file ( ) ;
411+ let mut src = Source :: stdin_raw ( ) ;
383412 #[ cfg( unix) ]
384- if let Source :: StdinFile ( f) = & src
413+ if let Source :: StdinRaw ( f) = & src
385414 && settings. iflags . directory
386415 && !f. metadata ( ) ?. is_dir ( )
387416 {
0 commit comments