diff options
Diffstat (limited to 'coreutils')
| -rw-r--r-- | coreutils/dd.c | 111 |
1 files changed, 80 insertions, 31 deletions
diff --git a/coreutils/dd.c b/coreutils/dd.c index b5f3cbec5..24d7f0b84 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" |
| @@ -137,16 +139,18 @@ enum { | |||
| 137 | FLAG_IFLAG_SHIFT = 5, | 139 | FLAG_IFLAG_SHIFT = 5, |
| 138 | FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, | 140 | FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, |
| 139 | FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, | 141 | FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, |
| 142 | FLAG_IDIRECT = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, | ||
| 140 | /* end of input flags */ | 143 | /* end of input flags */ |
| 141 | /* start of output flags */ | 144 | /* start of output flags */ |
| 142 | FLAG_OFLAG_SHIFT = 7, | 145 | FLAG_OFLAG_SHIFT = 8, |
| 143 | FLAG_SEEK_BYTES = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, | 146 | FLAG_SEEK_BYTES = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, |
| 144 | FLAG_APPEND = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, | 147 | FLAG_APPEND = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS, |
| 148 | FLAG_ODIRECT = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS, | ||
| 145 | /* end of output flags */ | 149 | /* end of output flags */ |
| 146 | FLAG_TWOBUFS = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS, | 150 | FLAG_TWOBUFS = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS, |
| 147 | FLAG_COUNT = 1 << 10, | 151 | FLAG_COUNT = 1 << 12, |
| 148 | FLAG_STATUS_NONE = 1 << 11, | 152 | FLAG_STATUS_NONE = 1 << 13, |
| 149 | FLAG_STATUS_NOXFER = 1 << 12, | 153 | FLAG_STATUS_NOXFER = 1 << 14, |
| 150 | }; | 154 | }; |
| 151 | 155 | ||
| 152 | static void dd_output_status(int UNUSED_PARAM cur_signal) | 156 | static void dd_output_status(int UNUSED_PARAM cur_signal) |
| @@ -192,12 +196,50 @@ static void dd_output_status(int UNUSED_PARAM cur_signal) | |||
| 192 | #endif | 196 | #endif |
| 193 | } | 197 | } |
| 194 | 198 | ||
| 199 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
| 200 | static int clear_O_DIRECT(int fd) | ||
| 201 | { | ||
| 202 | if (errno == EINVAL) { | ||
| 203 | int fl = fcntl(fd, F_GETFL); | ||
| 204 | if (fl & O_DIRECT) { | ||
| 205 | fcntl(fd, F_SETFL, fl & ~O_DIRECT); | ||
| 206 | return 1; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | #endif | ||
| 212 | |||
| 213 | static ssize_t dd_read(void *ibuf, size_t ibs) | ||
| 214 | { | ||
| 215 | ssize_t n; | ||
| 216 | |||
| 217 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
| 218 | read_again: | ||
| 219 | if (G.flags & FLAG_FULLBLOCK) | ||
| 220 | n = full_read(ifd, ibuf, ibs); | ||
| 221 | else | ||
| 222 | #endif | ||
| 223 | n = safe_read(ifd, ibuf, ibs); | ||
| 224 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
| 225 | if (n < 0 && (G.flags & FLAG_IDIRECT) && clear_O_DIRECT(ifd)) | ||
| 226 | goto read_again; | ||
| 227 | #endif | ||
| 228 | return n; | ||
| 229 | } | ||
| 230 | |||
| 195 | static bool write_and_stats(const void *buf, size_t len, size_t obs, | 231 | static bool write_and_stats(const void *buf, size_t len, size_t obs, |
| 196 | const char *filename) | 232 | const char *filename) |
| 197 | { | 233 | { |
| 198 | ssize_t n; | 234 | ssize_t n; |
| 199 | 235 | ||
| 236 | IF_FEATURE_DD_IBS_OBS(write_again:) | ||
| 200 | n = full_write(ofd, buf, len); | 237 | n = full_write(ofd, buf, len); |
| 238 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
| 239 | if (n < 0 && (G.flags & FLAG_ODIRECT) && clear_O_DIRECT(ofd)) | ||
| 240 | goto write_again; | ||
| 241 | #endif | ||
| 242 | |||
| 201 | #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE | 243 | #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE |
| 202 | if (n > 0) | 244 | if (n > 0) |
| 203 | G.total_bytes += n; | 245 | G.total_bytes += n; |
| @@ -254,6 +296,14 @@ static int parse_comma_flags(char *val, const char *words, const char *error_in) | |||
| 254 | } | 296 | } |
| 255 | #endif | 297 | #endif |
| 256 | 298 | ||
| 299 | static void *alloc_buf(size_t size) | ||
| 300 | { | ||
| 301 | /* Important for "{i,o}flag=direct" - buffers must be page aligned */ | ||
| 302 | if (size >= bb_getpagesize()) | ||
| 303 | return xmmap_anon(size); | ||
| 304 | return xmalloc(size); | ||
| 305 | } | ||
| 306 | |||
| 257 | int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 307 | int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| 258 | int dd_main(int argc UNUSED_PARAM, char **argv) | 308 | int dd_main(int argc UNUSED_PARAM, char **argv) |
| 259 | { | 309 | { |
| @@ -267,9 +317,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
| 267 | static const char conv_words[] ALIGN1 = | 317 | static const char conv_words[] ALIGN1 = |
| 268 | "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; | 318 | "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; |
| 269 | static const char iflag_words[] ALIGN1 = | 319 | static const char iflag_words[] ALIGN1 = |
| 270 | "skip_bytes\0""fullblock\0"; | 320 | "skip_bytes\0""fullblock\0""direct\0"; |
| 271 | static const char oflag_words[] ALIGN1 = | 321 | static const char oflag_words[] ALIGN1 = |
| 272 | "seek_bytes\0append\0"; | 322 | "seek_bytes\0append\0""direct\0"; |
| 273 | #endif | 323 | #endif |
| 274 | #if ENABLE_FEATURE_DD_STATUS | 324 | #if ENABLE_FEATURE_DD_STATUS |
| 275 | static const char status_words[] ALIGN1 = | 325 | static const char status_words[] ALIGN1 = |
| @@ -310,7 +360,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
| 310 | //swab swap every pair of input bytes: will abort on non-even reads | 360 | //swab swap every pair of input bytes: will abort on non-even reads |
| 311 | OP_iflag_skip_bytes, | 361 | OP_iflag_skip_bytes, |
| 312 | OP_iflag_fullblock, | 362 | OP_iflag_fullblock, |
| 363 | OP_iflag_direct, | ||
| 313 | OP_oflag_seek_bytes, | 364 | OP_oflag_seek_bytes, |
| 365 | OP_oflag_direct, | ||
| 314 | #endif | 366 | #endif |
| 315 | }; | 367 | }; |
| 316 | smallint exitcode = EXIT_FAILURE; | 368 | smallint exitcode = EXIT_FAILURE; |
| @@ -426,13 +478,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
| 426 | #endif | 478 | #endif |
| 427 | } /* end of "for (argv[i])" */ | 479 | } /* end of "for (argv[i])" */ |
| 428 | 480 | ||
| 429 | //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever | 481 | ibuf = alloc_buf(ibs); |
| 430 | ibuf = xmalloc(ibs); | ||
| 431 | obuf = ibuf; | 482 | obuf = ibuf; |
| 432 | #if ENABLE_FEATURE_DD_IBS_OBS | 483 | #if ENABLE_FEATURE_DD_IBS_OBS |
| 433 | if (ibs != obs) { | 484 | if (ibs != obs) { |
| 434 | G.flags |= FLAG_TWOBUFS; | 485 | G.flags |= FLAG_TWOBUFS; |
| 435 | obuf = xmalloc(obs); | 486 | obuf = alloc_buf(obs); |
| 436 | } | 487 | } |
| 437 | #endif | 488 | #endif |
| 438 | 489 | ||
| @@ -444,7 +495,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
| 444 | #endif | 495 | #endif |
| 445 | 496 | ||
| 446 | if (infile) { | 497 | if (infile) { |
| 447 | xmove_fd(xopen(infile, O_RDONLY), ifd); | 498 | int iflag = O_RDONLY; |
| 499 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
| 500 | if (G.flags & FLAG_IDIRECT) | ||
| 501 | iflag |= O_DIRECT; | ||
| 502 | #endif | ||
| 503 | xmove_fd(xopen(infile, iflag), ifd); | ||
| 448 | } else { | 504 | } else { |
| 449 | infile = bb_msg_standard_input; | 505 | infile = bb_msg_standard_input; |
| 450 | } | 506 | } |
| @@ -455,7 +511,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
| 455 | oflag |= O_TRUNC; | 511 | oflag |= O_TRUNC; |
| 456 | if (G.flags & FLAG_APPEND) | 512 | if (G.flags & FLAG_APPEND) |
| 457 | oflag |= O_APPEND; | 513 | oflag |= O_APPEND; |
| 458 | 514 | #if ENABLE_FEATURE_DD_IBS_OBS | |
| 515 | if (G.flags & FLAG_ODIRECT) | ||
| 516 | oflag |= O_DIRECT; | ||
| 517 | #endif | ||
| 459 | xmove_fd(xopen(outfile, oflag), ofd); | 518 | xmove_fd(xopen(outfile, oflag), ofd); |
| 460 | 519 | ||
| 461 | if (seek && !(G.flags & FLAG_NOTRUNC)) { | 520 | if (seek && !(G.flags & FLAG_NOTRUNC)) { |
| @@ -478,13 +537,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
| 478 | size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs; | 537 | size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs; |
| 479 | if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) { | 538 | if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) { |
| 480 | do { | 539 | do { |
| 481 | ssize_t n; | 540 | ssize_t n = dd_read(ibuf, blocksz); |
| 482 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
| 483 | if (G.flags & FLAG_FULLBLOCK) | ||
| 484 | n = full_read(ifd, ibuf, blocksz); | ||
| 485 | else | ||
| 486 | #endif | ||
| 487 | n = safe_read(ifd, ibuf, blocksz); | ||
| 488 | if (n < 0) | 541 | if (n < 0) |
| 489 | goto die_infile; | 542 | goto die_infile; |
| 490 | if (n == 0) | 543 | if (n == 0) |
| @@ -499,13 +552,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
| 499 | } | 552 | } |
| 500 | 553 | ||
| 501 | while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { | 554 | while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { |
| 502 | ssize_t n; | 555 | ssize_t n = dd_read(ibuf, ibs); |
| 503 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
| 504 | if (G.flags & FLAG_FULLBLOCK) | ||
| 505 | n = full_read(ifd, ibuf, ibs); | ||
| 506 | else | ||
| 507 | #endif | ||
| 508 | n = safe_read(ifd, ibuf, ibs); | ||
| 509 | if (n == 0) | 556 | if (n == 0) |
| 510 | break; | 557 | break; |
| 511 | if (n < 0) { | 558 | if (n < 0) { |
| @@ -600,11 +647,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
| 600 | if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE)) | 647 | if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE)) |
| 601 | dd_output_status(0); | 648 | dd_output_status(0); |
| 602 | 649 | ||
| 650 | #if 0 /* can't just free(), they can be mmap()ed */ | ||
| 603 | if (ENABLE_FEATURE_CLEAN_UP) { | 651 | if (ENABLE_FEATURE_CLEAN_UP) { |
| 604 | free(obuf); | 652 | free(obuf); |
| 605 | if (G.flags & FLAG_TWOBUFS) | 653 | if (G.flags & FLAG_TWOBUFS) |
| 606 | free(ibuf); | 654 | free(ibuf); |
| 607 | } | 655 | } |
| 656 | #endif | ||
| 608 | 657 | ||
| 609 | return exitcode; | 658 | return exitcode; |
| 610 | } | 659 | } |
