@@ -43,7 +43,7 @@ use std::time;
43
43
use clap:: { crate_version, Arg , Command } ;
44
44
use gcd:: Gcd ;
45
45
use uucore:: display:: Quotable ;
46
- use uucore:: error:: { FromIo , UResult } ;
46
+ use uucore:: error:: { set_exit_code , FromIo , UResult } ;
47
47
use uucore:: { format_usage, help_about, help_section, help_usage, show_error} ;
48
48
49
49
const ABOUT : & str = help_about ! ( "dd.md" ) ;
@@ -143,14 +143,25 @@ impl Source {
143
143
Err ( e) => Err ( e) ,
144
144
} ,
145
145
#[ cfg( unix) ]
146
- Self :: StdinFile ( f) => match io:: copy ( & mut f. take ( n) , & mut io:: sink ( ) ) {
147
- Ok ( m) if m < n => {
148
- show_error ! ( "'standard input': cannot skip to specified offset" ) ;
149
- Ok ( m)
146
+ Self :: StdinFile ( f) => {
147
+ if let Ok ( Some ( len) ) = try_get_len_of_block_device ( f) {
148
+ if len < n {
149
+ // GNU compatibility:
150
+ // this case prints the stats but sets the exit code to 1
151
+ show_error ! ( "'standard input': cannot skip: Invalid argument" ) ;
152
+ set_exit_code ( 1 ) ;
153
+ return Ok ( len) ;
154
+ }
150
155
}
151
- Ok ( m) => Ok ( m) ,
152
- Err ( e) => Err ( e) ,
153
- } ,
156
+ match io:: copy ( & mut f. take ( n) , & mut io:: sink ( ) ) {
157
+ Ok ( m) if m < n => {
158
+ show_error ! ( "'standard input': cannot skip to specified offset" ) ;
159
+ Ok ( m)
160
+ }
161
+ Ok ( m) => Ok ( m) ,
162
+ Err ( e) => Err ( e) ,
163
+ }
164
+ }
154
165
Self :: File ( f) => f. seek ( io:: SeekFrom :: Start ( n) ) ,
155
166
#[ cfg( unix) ]
156
167
Self :: Fifo ( f) => io:: copy ( & mut f. take ( n) , & mut io:: sink ( ) ) ,
@@ -426,7 +437,18 @@ impl Dest {
426
437
fn seek ( & mut self , n : u64 ) -> io:: Result < u64 > {
427
438
match self {
428
439
Self :: Stdout ( stdout) => io:: copy ( & mut io:: repeat ( 0 ) . take ( n) , stdout) ,
429
- Self :: File ( f, _) => f. seek ( io:: SeekFrom :: Start ( n) ) ,
440
+ Self :: File ( f, _) => {
441
+ if let Ok ( Some ( len) ) = try_get_len_of_block_device ( f) {
442
+ if len < n {
443
+ // GNU compatibility:
444
+ // this case prints the stats but sets the exit code to 1
445
+ show_error ! ( "'standard output': cannot seek: Invalid argument" ) ;
446
+ set_exit_code ( 1 ) ;
447
+ return Ok ( len) ;
448
+ }
449
+ }
450
+ f. seek ( io:: SeekFrom :: Start ( n) )
451
+ }
430
452
#[ cfg( unix) ]
431
453
Self :: Fifo ( f) => {
432
454
// Seeking in a named pipe means *reading* from the pipe.
@@ -925,6 +947,23 @@ fn is_stdout_redirected_to_seekable_file() -> bool {
925
947
}
926
948
}
927
949
950
+ /// Try to get the len if it is a block device
951
+ fn try_get_len_of_block_device ( file : & mut File ) -> io:: Result < Option < u64 > > {
952
+ #[ cfg( not( unix) ) ]
953
+ return Ok ( None ) ;
954
+
955
+ let ftype = file. metadata ( ) ?. file_type ( ) ;
956
+ #[ cfg( unix) ]
957
+ if !ftype. is_block_device ( ) {
958
+ return Ok ( None ) ;
959
+ }
960
+
961
+ // FIXME: this can be replaced by file.stream_len() when stable.
962
+ let len = file. seek ( SeekFrom :: End ( 0 ) ) ?;
963
+ file. rewind ( ) ?;
964
+ Ok ( Some ( len) )
965
+ }
966
+
928
967
/// Decide whether the named file is a named pipe, also known as a FIFO.
929
968
#[ cfg( unix) ]
930
969
fn is_fifo ( filename : & str ) -> bool {
0 commit comments