@@ -25,7 +25,7 @@ use progress::ProgUpdateType;
2525use progress:: { ProgUpdate , ReadStat , StatusLevel , WriteStat , gen_prog_updater} ;
2626#[ cfg( target_os = "linux" ) ]
2727use progress:: { check_and_reset_sigusr1, install_sigusr1_handler} ;
28- use uucore:: io :: OwnedFileDescriptorOrHandle ;
28+ use uucore:: stdio :: { StdinRaw , StdoutRaw } ;
2929use uucore:: translate;
3030
3131use std:: cmp;
@@ -37,15 +37,12 @@ use std::fs::{File, OpenOptions};
3737use std:: io:: { self , Read , Seek , SeekFrom , Write } ;
3838#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
3939use std:: os:: fd:: AsFd ;
40+ #[ cfg( unix) ]
41+ use std:: os:: unix:: fs:: FileTypeExt ;
4042#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
4143use std:: os:: unix:: fs:: OpenOptionsExt ;
42- #[ cfg( unix) ]
43- use std:: os:: unix:: {
44- fs:: FileTypeExt ,
45- io:: { AsRawFd , FromRawFd } ,
46- } ;
4744#[ cfg( windows) ]
48- use std:: os:: windows:: { fs:: MetadataExt , io :: AsHandle } ;
45+ use std:: os:: windows:: fs:: MetadataExt ;
4946use std:: path:: Path ;
5047use std:: sync:: atomic:: AtomicU8 ;
5148use std:: sync:: { Arc , atomic:: Ordering :: Relaxed , mpsc} ;
@@ -178,20 +175,20 @@ impl Num {
178175 }
179176}
180177
181- /// Read and discard `n` bytes from `reader ` using a buffer of size `buf_size`.
178+ /// Read and discard `n` bytes from `file ` using a buffer of size `buf_size`.
182179///
183180/// This is more efficient than `io::copy` with `BufReader` because it reads
184181/// directly in `buf_size`-sized chunks, matching GNU dd's behavior.
185182/// Returns the total number of bytes actually read.
186- fn read_and_discard < R : Read > ( reader : & mut R , n : u64 , buf_size : usize ) -> io:: Result < u64 > {
183+ fn read_and_discard ( file : & mut File , n : u64 , buf_size : usize ) -> io:: Result < u64 > {
187184 // todo: consider splice()ing to /dev/null on Linux
188185 let mut buf = Vec :: with_capacity ( buf_size) ;
189186 let mut total = 0u64 ;
190187 let mut remaining = n;
191188 while remaining > 0 {
192189 let to_read = cmp:: min ( remaining, buf_size as u64 ) ;
193190 buf. clear ( ) ;
194- match reader . by_ref ( ) . take ( to_read) . read_to_end ( & mut buf) {
191+ match file . take ( to_read) . read_to_end ( & mut buf) {
195192 Ok ( 0 ) => break , // EOF
196193 Ok ( bytes_read) => {
197194 total += bytes_read as u64 ;
@@ -207,44 +204,25 @@ fn read_and_discard<R: Read>(reader: &mut R, n: u64, buf_size: usize) -> io::Res
207204
208205/// Data sources.
209206///
210- /// Use [`Source::stdin_as_file `] if available to enable more
207+ /// Use [`Source::StdinRaw `] if available to enable more
211208/// fine-grained access to reading from stdin.
212209enum Source {
213- /// Input from stdin.
214- #[ cfg( not( unix) ) ]
215- Stdin ( io:: Stdin ) ,
216-
217210 /// Input from a file.
218211 File ( File ) ,
219212
220213 /// Input from stdin, opened from its file descriptor.
221- #[ cfg( unix) ]
222- StdinFile ( File ) ,
214+ StdinRaw ( StdinRaw ) ,
223215
224216 /// Input from a named pipe, also known as a FIFO.
225217 #[ cfg( unix) ]
226218 Fifo ( File ) ,
227219}
228220
229221impl Source {
230- /// Create a source from stdin using its raw file descriptor.
231- ///
232- /// This returns an instance of the `Source::StdinFile` variant,
233- /// using the raw file descriptor of [`io::Stdin`] to create
234- /// the [`File`] parameter. You can use this instead of
235- /// `Source::Stdin` to allow reading from stdin without consuming
236- /// the entire contents of stdin when this process terminates.
237- #[ 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)
242- }
243-
244222 fn skip ( & mut self , n : u64 , ibs : usize ) -> io:: Result < u64 > {
245223 match self {
246224 #[ cfg( not( unix) ) ]
247- Self :: Stdin ( stdin) => {
225+ Self :: StdinRaw ( stdin) => {
248226 let m = read_and_discard ( stdin, n, ibs) ?;
249227 if m < n {
250228 show_error ! (
@@ -255,8 +233,8 @@ impl Source {
255233 Ok ( m)
256234 }
257235 #[ cfg( unix) ]
258- Self :: StdinFile ( f ) => {
259- if let Ok ( Some ( len) ) = try_get_len_of_block_device ( f )
236+ Self :: StdinRaw ( stdin ) => {
237+ if let Ok ( Some ( len) ) = try_get_len_of_block_device ( stdin )
260238 && len < n
261239 {
262240 // GNU compatibility:
@@ -269,9 +247,9 @@ impl Source {
269247 return Ok ( len) ;
270248 }
271249 // Get file length before seeking to avoid race condition
272- let file_len = f . metadata ( ) . as_ref ( ) . map_or ( u64:: MAX , Metadata :: len) ;
250+ let file_len = stdin . metadata ( ) . as_ref ( ) . map_or ( u64:: MAX , Metadata :: len) ;
273251 // Try seek first; fall back to read if not seekable
274- match n. try_into ( ) . ok ( ) . map ( |n| f . seek ( SeekFrom :: Current ( n) ) ) {
252+ match n. try_into ( ) . ok ( ) . map ( |n| stdin . seek ( SeekFrom :: Current ( n) ) ) {
275253 Some ( Ok ( pos) ) => {
276254 if pos > file_len {
277255 show_error ! (
@@ -284,7 +262,7 @@ impl Source {
284262 // ESPIPE means the file descriptor is not seekable (e.g., a pipe),
285263 // so fall back to reading and discarding bytes using ibs-sized buffer
286264 Some ( Err ( e) ) if e. raw_os_error ( ) == Some ( libc:: ESPIPE ) => {
287- let m = read_and_discard ( f , n, ibs) ?;
265+ let m = read_and_discard ( stdin , n, ibs) ?;
288266 if m < n {
289267 show_error ! (
290268 "{}" ,
@@ -331,11 +309,8 @@ impl Source {
331309impl Read for Source {
332310 fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
333311 match self {
334- #[ cfg( not( unix) ) ]
335- Self :: Stdin ( stdin) => stdin. read ( buf) ,
336312 Self :: File ( f) => f. read ( buf) ,
337- #[ cfg( unix) ]
338- Self :: StdinFile ( f) => f. read ( buf) ,
313+ Self :: StdinRaw ( f) => f. read ( buf) ,
339314 #[ cfg( unix) ]
340315 Self :: Fifo ( f) => f. read ( buf) ,
341316 }
@@ -359,10 +334,11 @@ struct Input<'a> {
359334impl < ' a > Input < ' a > {
360335 /// Instantiate this struct with stdin as a source.
361336 fn new_stdin ( settings : & ' a Settings ) -> UResult < Self > {
337+ let stdin = uucore:: stdio:: stdin_raw ( ) ;
338+
362339 #[ cfg( not( unix) ) ]
363340 let mut src = {
364- let f = File :: from ( io:: stdin ( ) . as_handle ( ) . try_clone_to_owned ( ) ?) ;
365- let is_file = if let Ok ( metadata) = f. metadata ( ) {
341+ let is_file = if let Ok ( metadata) = stdin. metadata ( ) {
366342 // this hack is needed as there is no other way on windows
367343 // to differentiate between the case where `seek` works
368344 // on a file handle or not. i.e. when the handle is no real
@@ -373,15 +349,15 @@ impl<'a> Input<'a> {
373349 false
374350 } ;
375351 if is_file {
376- Source :: File ( f )
352+ Source :: File ( stdin . try_clone ( ) ? )
377353 } else {
378- Source :: Stdin ( io :: stdin ( ) )
354+ Source :: StdinRaw ( stdin)
379355 }
380356 } ;
381357 #[ cfg( unix) ]
382- let mut src = Source :: stdin_as_file ( ) ;
358+ let mut src = Source :: StdinRaw ( stdin ) ;
383359 #[ cfg( unix) ]
384- if let Source :: StdinFile ( f) = & src
360+ if let Source :: StdinRaw ( f) = & src
385361 && settings. iflags . directory
386362 && !f. metadata ( ) ?. is_dir ( )
387363 {
@@ -599,7 +575,7 @@ enum Density {
599575/// Data destinations.
600576enum Dest {
601577 /// Output to stdout.
602- Stdout ( File ) ,
578+ StdoutRaw ( StdoutRaw ) ,
603579
604580 /// Output to a file.
605581 ///
@@ -619,7 +595,7 @@ enum Dest {
619595impl Dest {
620596 fn fsync ( & mut self ) -> io:: Result < ( ) > {
621597 match self {
622- Self :: Stdout ( stdout) => stdout. flush ( ) ,
598+ Self :: StdoutRaw ( stdout) => stdout. flush ( ) ,
623599 Self :: File ( f, _) => {
624600 f. flush ( ) ?;
625601 f. sync_all ( )
@@ -636,7 +612,7 @@ impl Dest {
636612
637613 fn fdatasync ( & mut self ) -> io:: Result < ( ) > {
638614 match self {
639- Self :: Stdout ( stdout) => stdout. flush ( ) ,
615+ Self :: StdoutRaw ( stdout) => stdout. flush ( ) ,
640616 Self :: File ( f, _) => {
641617 f. flush ( ) ?;
642618 f. sync_data ( )
@@ -654,7 +630,7 @@ impl Dest {
654630 #[ cfg_attr( not( unix) , allow( unused_variables) ) ]
655631 fn seek ( & mut self , n : u64 , obs : usize ) -> io:: Result < u64 > {
656632 match self {
657- Self :: Stdout ( stdout) => io:: copy ( & mut io:: repeat ( 0 ) . take ( n) , stdout) ,
633+ Self :: StdoutRaw ( stdout) => io:: copy ( & mut io:: repeat ( 0 ) . take ( n) , & mut * * stdout) ,
658634 Self :: File ( f, _) => {
659635 #[ cfg( unix) ]
660636 if let Ok ( Some ( len) ) = try_get_len_of_block_device ( f)
@@ -790,7 +766,7 @@ impl Write for Dest {
790766 Err ( e) => Err ( e) ,
791767 }
792768 }
793- Self :: Stdout ( stdout) => stdout. write ( buf) ,
769+ Self :: StdoutRaw ( stdout) => stdout. write ( buf) ,
794770 #[ cfg( unix) ]
795771 Self :: Fifo ( f) => f. write ( buf) ,
796772 #[ cfg( unix) ]
@@ -800,7 +776,7 @@ impl Write for Dest {
800776
801777 fn flush ( & mut self ) -> io:: Result < ( ) > {
802778 match self {
803- Self :: Stdout ( stdout) => stdout. flush ( ) ,
779+ Self :: StdoutRaw ( stdout) => stdout. flush ( ) ,
804780 Self :: File ( f, _) => f. flush ( ) ,
805781 #[ cfg( unix) ]
806782 Self :: Fifo ( f) => f. flush ( ) ,
@@ -827,8 +803,8 @@ struct Output<'a> {
827803impl < ' a > Output < ' a > {
828804 /// Instantiate this struct with stdout as a destination.
829805 fn new_stdout ( settings : & ' a Settings ) -> UResult < Self > {
830- let fx = OwnedFileDescriptorOrHandle :: from ( io :: stdout ( ) ) ? ;
831- let mut dst = Dest :: Stdout ( fx . into_file ( ) ) ;
806+ let stdout = uucore :: stdio :: stdout_raw ( ) ;
807+ let mut dst = Dest :: StdoutRaw ( stdout ) ;
832808 dst. seek ( settings. seek , settings. obs )
833809 . map_err_context ( || translate ! ( "dd-error-write-error" ) ) ?;
834810 Ok ( Self { dst, settings } )
@@ -888,16 +864,17 @@ impl<'a> Output<'a> {
888864 /// already opened by the system (stdout) and has a state
889865 /// (current position) that shall be used.
890866 fn new_file_from_stdout ( settings : & ' a Settings ) -> UResult < Self > {
891- let fx = OwnedFileDescriptorOrHandle :: from ( io :: stdout ( ) ) ? ;
867+ let stdout = uucore :: stdio :: stdout_raw ( ) ;
892868 #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
893869 if let Some ( libc_flags) = make_linux_oflags ( & settings. oflags ) {
894870 nix:: fcntl:: fcntl (
895- fx . as_raw ( ) . as_fd ( ) ,
871+ stdout . as_fd ( ) ,
896872 FcntlArg :: F_SETFL ( OFlag :: from_bits_retain ( libc_flags) ) ,
897873 ) ?;
898874 }
899875
900- Self :: prepare_file ( fx. into_file ( ) , settings)
876+ // TODO: avoid cloning the underlying file handle
877+ Self :: prepare_file ( stdout. try_clone ( ) ?, settings)
901878 }
902879
903880 /// Instantiate this struct with the given named pipe as a destination.
0 commit comments