@@ -183,6 +183,32 @@ impl Num {
183183 }
184184}
185185
186+ /// Read and discard `n` bytes from `reader` using a buffer of size `buf_size`.
187+ ///
188+ /// This is more efficient than `io::copy` with `BufReader` because it reads
189+ /// directly in `buf_size`-sized chunks, matching GNU dd's behavior.
190+ /// Returns the total number of bytes actually read.
191+ fn read_and_discard < R : Read > ( reader : & mut R , n : u64 , buf_size : usize ) -> io:: Result < u64 > {
192+ let mut buf = vec ! [ 0u8 ; buf_size] ;
193+ let mut total = 0u64 ;
194+ let mut remaining = n;
195+
196+ while remaining > 0 {
197+ let to_read = cmp:: min ( remaining, buf_size as u64 ) as usize ;
198+ match reader. read ( & mut buf[ ..to_read] ) {
199+ Ok ( 0 ) => break , // EOF
200+ Ok ( bytes_read) => {
201+ total += bytes_read as u64 ;
202+ remaining -= bytes_read as u64 ;
203+ }
204+ Err ( e) if e. kind ( ) == io:: ErrorKind :: Interrupted => continue ,
205+ Err ( e) => return Err ( e) ,
206+ }
207+ }
208+
209+ Ok ( total)
210+ }
211+
186212/// Data sources.
187213///
188214/// Use [`Source::stdin_as_file`] if available to enable more
@@ -219,20 +245,19 @@ impl Source {
219245 Self :: StdinFile ( f)
220246 }
221247
222- fn skip ( & mut self , n : u64 ) -> io:: Result < u64 > {
248+ fn skip ( & mut self , n : u64 , ibs : usize ) -> io:: Result < u64 > {
223249 match self {
224250 #[ cfg( not( unix) ) ]
225- Self :: Stdin ( stdin) => match io:: copy ( & mut stdin. take ( n) , & mut io:: sink ( ) ) {
226- Ok ( m) if m < n => {
251+ Self :: Stdin ( stdin) => {
252+ let m = read_and_discard ( stdin, n, ibs) ?;
253+ if m < n {
227254 show_error ! (
228255 "{}" ,
229256 translate!( "dd-error-cannot-skip-offset" , "file" => "standard input" )
230257 ) ;
231- Ok ( m)
232258 }
233- Ok ( m) => Ok ( m) ,
234- Err ( e) => Err ( e) ,
235- } ,
259+ Ok ( m)
260+ }
236261 #[ cfg( unix) ]
237262 Self :: StdinFile ( f) => {
238263 if let Ok ( Some ( len) ) = try_get_len_of_block_device ( f) {
@@ -247,21 +272,18 @@ impl Source {
247272 return Ok ( len) ;
248273 }
249274 }
250- match io:: copy ( & mut f. take ( n) , & mut io:: sink ( ) ) {
251- Ok ( m) if m < n => {
252- show_error ! (
253- "{}" ,
254- translate!( "dd-error-cannot-skip-offset" , "file" => "standard input" )
255- ) ;
256- Ok ( m)
257- }
258- Ok ( m) => Ok ( m) ,
259- Err ( e) => Err ( e) ,
275+ let m = read_and_discard ( f, n, ibs) ?;
276+ if m < n {
277+ show_error ! (
278+ "{}" ,
279+ translate!( "dd-error-cannot-skip-offset" , "file" => "standard input" )
280+ ) ;
260281 }
282+ Ok ( m)
261283 }
262284 Self :: File ( f) => f. seek ( SeekFrom :: Current ( n. try_into ( ) . unwrap ( ) ) ) ,
263285 #[ cfg( unix) ]
264- Self :: Fifo ( f) => io :: copy ( & mut f . take ( n ) , & mut io :: sink ( ) ) ,
286+ Self :: Fifo ( f) => read_and_discard ( f , n , ibs ) ,
265287 }
266288 }
267289
@@ -346,7 +368,7 @@ impl<'a> Input<'a> {
346368 }
347369 }
348370 if settings. skip > 0 {
349- src. skip ( settings. skip ) ?;
371+ src. skip ( settings. skip , settings . ibs ) ?;
350372 }
351373 Ok ( Self { src, settings } )
352374 }
@@ -369,7 +391,7 @@ impl<'a> Input<'a> {
369391
370392 let mut src = Source :: File ( src) ;
371393 if settings. skip > 0 {
372- src. skip ( settings. skip ) ?;
394+ src. skip ( settings. skip , settings . ibs ) ?;
373395 }
374396 Ok ( Self { src, settings } )
375397 }
@@ -383,7 +405,7 @@ impl<'a> Input<'a> {
383405 opts. custom_flags ( make_linux_iflags ( & settings. iflags ) . unwrap_or ( 0 ) ) ;
384406 let mut src = Source :: Fifo ( opts. open ( filename) ?) ;
385407 if settings. skip > 0 {
386- src. skip ( settings. skip ) ?;
408+ src. skip ( settings. skip , settings . ibs ) ?;
387409 }
388410 Ok ( Self { src, settings } )
389411 }
@@ -605,7 +627,8 @@ impl Dest {
605627 }
606628 }
607629
608- fn seek ( & mut self , n : u64 ) -> io:: Result < u64 > {
630+ #[ cfg_attr( not( unix) , allow( unused_variables) ) ]
631+ fn seek ( & mut self , n : u64 , obs : usize ) -> io:: Result < u64 > {
609632 match self {
610633 Self :: Stdout ( stdout) => io:: copy ( & mut io:: repeat ( 0 ) . take ( n) , stdout) ,
611634 Self :: File ( f, _) => {
@@ -627,7 +650,7 @@ impl Dest {
627650 #[ cfg( unix) ]
628651 Self :: Fifo ( f) => {
629652 // Seeking in a named pipe means *reading* from the pipe.
630- io :: copy ( & mut f . take ( n ) , & mut io :: sink ( ) )
653+ read_and_discard ( f , n , obs )
631654 }
632655 #[ cfg( unix) ]
633656 Self :: Sink => Ok ( 0 ) ,
@@ -781,7 +804,7 @@ impl<'a> Output<'a> {
781804 /// Instantiate this struct with stdout as a destination.
782805 fn new_stdout ( settings : & ' a Settings ) -> UResult < Self > {
783806 let mut dst = Dest :: Stdout ( io:: stdout ( ) ) ;
784- dst. seek ( settings. seek )
807+ dst. seek ( settings. seek , settings . obs )
785808 . map_err_context ( || translate ! ( "dd-error-write-error" ) ) ?;
786809 Ok ( Self { dst, settings } )
787810 }
@@ -829,7 +852,7 @@ impl<'a> Output<'a> {
829852 Density :: Dense
830853 } ;
831854 let mut dst = Dest :: File ( dst, density) ;
832- dst. seek ( settings. seek )
855+ dst. seek ( settings. seek , settings . obs )
833856 . map_err_context ( || translate ! ( "dd-error-failed-to-seek" ) ) ?;
834857 Ok ( Self { dst, settings } )
835858 }
@@ -859,7 +882,7 @@ impl<'a> Output<'a> {
859882 // file for reading. But then we need to close the file and
860883 // re-open it for writing.
861884 if settings. seek > 0 {
862- Dest :: Fifo ( File :: open ( filename) ?) . seek ( settings. seek ) ?;
885+ Dest :: Fifo ( File :: open ( filename) ?) . seek ( settings. seek , settings . obs ) ?;
863886 }
864887 // If `count=0`, then we don't bother opening the file for
865888 // writing because that would cause this process to block
0 commit comments