diff options
Diffstat (limited to 'coreutils/dd.c')
-rw-r--r-- | coreutils/dd.c | 116 |
1 files changed, 83 insertions, 33 deletions
diff --git a/coreutils/dd.c b/coreutils/dd.c index 042355e24..c150ef5bc 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c | |||
@@ -59,7 +59,7 @@ | |||
59 | //usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]\n" | 59 | //usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]\n" |
60 | //usage: IF_FEATURE_DD_IBS_OBS( | 60 | //usage: IF_FEATURE_DD_IBS_OBS( |
61 | //usage: " [conv=notrunc|noerror|sync|fsync]\n" | 61 | //usage: " [conv=notrunc|noerror|sync|fsync]\n" |
62 | //usage: " [iflag=skip_bytes|fullblock] [oflag=seek_bytes|append]" | 62 | //usage: " [iflag=skip_bytes|fullblock|direct] [oflag=seek_bytes|append|direct]" |
63 | //usage: ) | 63 | //usage: ) |
64 | //usage:#define dd_full_usage "\n\n" | 64 | //usage:#define dd_full_usage "\n\n" |
65 | //usage: "Copy a file with converting and formatting\n" | 65 | //usage: "Copy a file with converting and formatting\n" |
@@ -82,9 +82,11 @@ | |||
82 | //usage: "\n conv=fsync Physically write data out before finishing" | 82 | //usage: "\n conv=fsync Physically write data out before finishing" |
83 | //usage: "\n conv=swab Swap every pair of bytes" | 83 | //usage: "\n conv=swab Swap every pair of bytes" |
84 | //usage: "\n iflag=skip_bytes skip=N is in bytes" | 84 | //usage: "\n iflag=skip_bytes skip=N is in bytes" |
85 | //usage: "\n iflag=fullblock Read full blocks" | ||
86 | //usage: "\n oflag=seek_bytes seek=N is in bytes" | 85 | //usage: "\n oflag=seek_bytes seek=N is in bytes" |
87 | //usage: "\n oflag=append Open output file in append mode" | 86 | //usage: "\n iflag=direct O_DIRECT input" |
87 | //usage: "\n oflag=direct O_DIRECT output" | ||
88 | //usage: "\n iflag=fullblock Read full blocks" | ||
89 | //usage: "\n oflag=append Open output in append mode" | ||
88 | //usage: ) | 90 | //usage: ) |
89 | //usage: IF_FEATURE_DD_STATUS( | 91 | //usage: IF_FEATURE_DD_STATUS( |
90 | //usage: "\n status=noxfer Suppress rate output" | 92 | //usage: "\n status=noxfer Suppress rate output" |
@@ -140,16 +142,18 @@ enum { | |||
140 | FLAG_IFLAG_SHIFT = 5, | 142 | FLAG_IFLAG_SHIFT = 5, |
141 | FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, | 143 | FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, |
142 | FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, | 144 | FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, |
145 | FLAG_IDIRECT = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, | ||
143 | /* end of input flags */ | 146 | /* end of input flags */ |
144 | /* start of output flags */ | 147 | /* start of output flags */ |
145 | FLAG_OFLAG_SHIFT = 7, | 148 | FLAG_OFLAG_SHIFT = 8, |
146 | FLAG_SEEK_BYTES = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, | 149 | FLAG_SEEK_BYTES = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, |
147 | FLAG_APPEND = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, | 150 | FLAG_APPEND = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS, |
151 | FLAG_ODIRECT = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS, | ||
148 | /* end of output flags */ | 152 | /* end of output flags */ |
149 | FLAG_TWOBUFS = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS, | 153 | FLAG_TWOBUFS = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS, |
150 | FLAG_COUNT = 1 << 10, | 154 | FLAG_COUNT = 1 << 12, |
151 | FLAG_STATUS_NONE = 1 << 11, | 155 | FLAG_STATUS_NONE = 1 << 13, |
152 | FLAG_STATUS_NOXFER = 1 << 12, | 156 | FLAG_STATUS_NOXFER = 1 << 14, |
153 | }; | 157 | }; |
154 | 158 | ||
155 | static void dd_output_status(int UNUSED_PARAM cur_signal) | 159 | static void dd_output_status(int UNUSED_PARAM cur_signal) |
@@ -195,12 +199,50 @@ static void dd_output_status(int UNUSED_PARAM cur_signal) | |||
195 | #endif | 199 | #endif |
196 | } | 200 | } |
197 | 201 | ||
202 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
203 | static int clear_O_DIRECT(int fd) | ||
204 | { | ||
205 | if (errno == EINVAL) { | ||
206 | int fl = fcntl(fd, F_GETFL); | ||
207 | if (fl & O_DIRECT) { | ||
208 | fcntl(fd, F_SETFL, fl & ~O_DIRECT); | ||
209 | return 1; | ||
210 | } | ||
211 | } | ||
212 | return 0; | ||
213 | } | ||
214 | #endif | ||
215 | |||
216 | static ssize_t dd_read(void *ibuf, size_t ibs) | ||
217 | { | ||
218 | ssize_t n; | ||
219 | |||
220 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
221 | read_again: | ||
222 | if (G.flags & FLAG_FULLBLOCK) | ||
223 | n = full_read(ifd, ibuf, ibs); | ||
224 | else | ||
225 | #endif | ||
226 | n = safe_read(ifd, ibuf, ibs); | ||
227 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
228 | if (n < 0 && (G.flags & FLAG_IDIRECT) && clear_O_DIRECT(ifd)) | ||
229 | goto read_again; | ||
230 | #endif | ||
231 | return n; | ||
232 | } | ||
233 | |||
198 | static bool write_and_stats(const void *buf, size_t len, size_t obs, | 234 | static bool write_and_stats(const void *buf, size_t len, size_t obs, |
199 | const char *filename) | 235 | const char *filename) |
200 | { | 236 | { |
201 | ssize_t n; | 237 | ssize_t n; |
202 | 238 | ||
239 | IF_FEATURE_DD_IBS_OBS(write_again:) | ||
203 | n = full_write(ofd, buf, len); | 240 | n = full_write(ofd, buf, len); |
241 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
242 | if (n < 0 && (G.flags & FLAG_ODIRECT) && clear_O_DIRECT(ofd)) | ||
243 | goto write_again; | ||
244 | #endif | ||
245 | |||
204 | #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE | 246 | #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE |
205 | if (n > 0) | 247 | if (n > 0) |
206 | G.total_bytes += n; | 248 | G.total_bytes += n; |
@@ -257,6 +299,16 @@ static int parse_comma_flags(char *val, const char *words, const char *error_in) | |||
257 | } | 299 | } |
258 | #endif | 300 | #endif |
259 | 301 | ||
302 | static void *alloc_buf(size_t size) | ||
303 | { | ||
304 | #if !ENABLE_PLATFORM_MINGW32 | ||
305 | /* Important for "{i,o}flag=direct" - buffers must be page aligned */ | ||
306 | if (size >= bb_getpagesize()) | ||
307 | return xmmap_anon(size); | ||
308 | #endif | ||
309 | return xmalloc(size); | ||
310 | } | ||
311 | |||
260 | int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 312 | int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
261 | int dd_main(int argc UNUSED_PARAM, char **argv) | 313 | int dd_main(int argc UNUSED_PARAM, char **argv) |
262 | { | 314 | { |
@@ -270,9 +322,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
270 | static const char conv_words[] ALIGN1 = | 322 | static const char conv_words[] ALIGN1 = |
271 | "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; | 323 | "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; |
272 | static const char iflag_words[] ALIGN1 = | 324 | static const char iflag_words[] ALIGN1 = |
273 | "skip_bytes\0""fullblock\0"; | 325 | "skip_bytes\0""fullblock\0""direct\0"; |
274 | static const char oflag_words[] ALIGN1 = | 326 | static const char oflag_words[] ALIGN1 = |
275 | "seek_bytes\0append\0"; | 327 | "seek_bytes\0append\0""direct\0"; |
276 | #endif | 328 | #endif |
277 | #if ENABLE_FEATURE_DD_STATUS | 329 | #if ENABLE_FEATURE_DD_STATUS |
278 | static const char status_words[] ALIGN1 = | 330 | static const char status_words[] ALIGN1 = |
@@ -313,7 +365,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
313 | //swab swap every pair of input bytes: will abort on non-even reads | 365 | //swab swap every pair of input bytes: will abort on non-even reads |
314 | OP_iflag_skip_bytes, | 366 | OP_iflag_skip_bytes, |
315 | OP_iflag_fullblock, | 367 | OP_iflag_fullblock, |
368 | OP_iflag_direct, | ||
316 | OP_oflag_seek_bytes, | 369 | OP_oflag_seek_bytes, |
370 | OP_oflag_direct, | ||
317 | #endif | 371 | #endif |
318 | }; | 372 | }; |
319 | smallint exitcode = EXIT_FAILURE; | 373 | smallint exitcode = EXIT_FAILURE; |
@@ -429,13 +483,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
429 | #endif | 483 | #endif |
430 | } /* end of "for (argv[i])" */ | 484 | } /* end of "for (argv[i])" */ |
431 | 485 | ||
432 | //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever | 486 | ibuf = alloc_buf(ibs); |
433 | ibuf = xmalloc(ibs); | ||
434 | obuf = ibuf; | 487 | obuf = ibuf; |
435 | #if ENABLE_FEATURE_DD_IBS_OBS | 488 | #if ENABLE_FEATURE_DD_IBS_OBS |
436 | if (ibs != obs) { | 489 | if (ibs != obs) { |
437 | G.flags |= FLAG_TWOBUFS; | 490 | G.flags |= FLAG_TWOBUFS; |
438 | obuf = xmalloc(obs); | 491 | obuf = alloc_buf(obs); |
439 | } | 492 | } |
440 | #endif | 493 | #endif |
441 | 494 | ||
@@ -447,10 +500,15 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
447 | #endif | 500 | #endif |
448 | 501 | ||
449 | if (infile) { | 502 | if (infile) { |
503 | int iflag = O_RDONLY; | ||
504 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
505 | if (G.flags & FLAG_IDIRECT) | ||
506 | iflag |= O_DIRECT; | ||
507 | #endif | ||
450 | #if !ENABLE_PLATFORM_MINGW32 | 508 | #if !ENABLE_PLATFORM_MINGW32 |
451 | xmove_fd(xopen(infile, O_RDONLY), ifd); | 509 | xmove_fd(xopen(infile, iflag), ifd); |
452 | #else | 510 | #else |
453 | xmove_fd(mingw_xopen(infile, O_RDONLY), ifd); | 511 | xmove_fd(mingw_xopen(infile, iflag), ifd); |
454 | update_dev_fd(get_dev_type(infile), ifd); | 512 | update_dev_fd(get_dev_type(infile), ifd); |
455 | #endif | 513 | #endif |
456 | } else { | 514 | } else { |
@@ -463,7 +521,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
463 | oflag |= O_TRUNC; | 521 | oflag |= O_TRUNC; |
464 | if (G.flags & FLAG_APPEND) | 522 | if (G.flags & FLAG_APPEND) |
465 | oflag |= O_APPEND; | 523 | oflag |= O_APPEND; |
466 | 524 | #if ENABLE_FEATURE_DD_IBS_OBS | |
525 | if (G.flags & FLAG_ODIRECT) | ||
526 | oflag |= O_DIRECT; | ||
527 | #endif | ||
467 | xmove_fd(xopen(outfile, oflag), ofd); | 528 | xmove_fd(xopen(outfile, oflag), ofd); |
468 | 529 | ||
469 | #if ENABLE_PLATFORM_MINGW32 | 530 | #if ENABLE_PLATFORM_MINGW32 |
@@ -508,13 +569,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
508 | size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs; | 569 | size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs; |
509 | if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) { | 570 | if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) { |
510 | do { | 571 | do { |
511 | ssize_t n; | 572 | ssize_t n = dd_read(ibuf, blocksz); |
512 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
513 | if (G.flags & FLAG_FULLBLOCK) | ||
514 | n = full_read(ifd, ibuf, blocksz); | ||
515 | else | ||
516 | #endif | ||
517 | n = safe_read(ifd, ibuf, blocksz); | ||
518 | if (n < 0) | 573 | if (n < 0) |
519 | goto die_infile; | 574 | goto die_infile; |
520 | if (n == 0) | 575 | if (n == 0) |
@@ -529,14 +584,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
529 | } | 584 | } |
530 | 585 | ||
531 | while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { | 586 | while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { |
532 | ssize_t n; | 587 | ssize_t n = dd_read(ibuf, ibs); |
533 | |||
534 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
535 | if (G.flags & FLAG_FULLBLOCK) | ||
536 | n = full_read(ifd, ibuf, ibs); | ||
537 | else | ||
538 | #endif | ||
539 | n = safe_read(ifd, ibuf, ibs); | ||
540 | if (n == 0) | 588 | if (n == 0) |
541 | break; | 589 | break; |
542 | if (n < 0) { | 590 | if (n < 0) { |
@@ -631,11 +679,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
631 | if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE)) | 679 | if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE)) |
632 | dd_output_status(0); | 680 | dd_output_status(0); |
633 | 681 | ||
682 | #if 0 /* can't just free(), they can be mmap()ed */ | ||
634 | if (ENABLE_FEATURE_CLEAN_UP) { | 683 | if (ENABLE_FEATURE_CLEAN_UP) { |
635 | free(obuf); | 684 | free(obuf); |
636 | if (G.flags & FLAG_TWOBUFS) | 685 | if (G.flags & FLAG_TWOBUFS) |
637 | free(ibuf); | 686 | free(ibuf); |
638 | } | 687 | } |
688 | #endif | ||
639 | 689 | ||
640 | return exitcode; | 690 | return exitcode; |
641 | } | 691 | } |