dd: fix bug where we assume count=INT_MAX when count is unspecified;

shrink dd while at it

function                                             old     new   delta
dd_main                                             1453    1368     -85
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-85)             Total: -85 bytes
   text    data     bss     dec     hex filename
 669216    2668   13616  685500   a75bc busybox_old
 669128    2668   13616  685412   a7564 busybox_unstripped
This commit is contained in:
Denis Vlasenko
2007-07-27 15:02:00 +00:00
parent 1d10aaf116
commit 7587870617

View File

@@ -32,6 +32,9 @@ struct globals {
off_t out_full, out_part, in_full, in_part; off_t out_full, out_part, in_full, in_part;
}; };
#define G (*(struct globals*)&bb_common_bufsiz1) #define G (*(struct globals*)&bb_common_bufsiz1)
/* We have to zero it out because of NOEXEC */
#define INIT_G() memset(&G, 0, sizeof(G))
static void dd_output_status(int ATTRIBUTE_UNUSED cur_signal) static void dd_output_status(int ATTRIBUTE_UNUSED cur_signal)
{ {
@@ -73,10 +76,11 @@ int dd_main(int argc, char **argv);
int dd_main(int argc, char **argv) int dd_main(int argc, char **argv)
{ {
enum { enum {
SYNC_FLAG = 1 << 0, FLAG_SYNC = 1 << 0,
NOERROR = 1 << 1, FLAG_NOERROR = 1 << 1,
TRUNC_FLAG = 1 << 2, FLAG_NOTRUNC = 1 << 2,
TWOBUFS_FLAG = 1 << 3, FLAG_TWOBUFS = 1 << 3,
FLAG_COUNT = 1 << 4,
}; };
static const char keywords[] = static const char keywords[] =
"bs=\0""count=\0""seek=\0""skip=\0""if=\0""of=\0" "bs=\0""count=\0""seek=\0""skip=\0""if=\0""of=\0"
@@ -100,25 +104,41 @@ int dd_main(int argc, char **argv)
OP_conv_noerror, OP_conv_noerror,
#endif #endif
}; };
int flags = TRUNC_FLAG; size_t ibs = 512, obs = 512;
size_t oc = 0, ibs = 512, obs = 512;
ssize_t n, w; ssize_t n, w;
off_t seek = 0, skip = 0, count = OFF_T_MAX;
int ifd, ofd;
const char *infile = NULL, *outfile = NULL;
char *ibuf, *obuf; char *ibuf, *obuf;
/* And these are all zeroed at once! */
struct {
int flags;
int ifd, ofd;
size_t oc;
off_t count;
off_t seek, skip;
const char *infile, *outfile;
#if ENABLE_FEATURE_DD_SIGNAL_HANDLING
struct sigaction sigact;
#endif
} Z;
#define flags (Z.flags )
#define ifd (Z.ifd )
#define ofd (Z.ofd )
#define oc (Z.oc )
#define count (Z.count )
#define seek (Z.seek )
#define skip (Z.skip )
#define infile (Z.infile )
#define outfile (Z.outfile)
#define sigact (Z.sigact )
memset(&G, 0, sizeof(G)); /* because of NOEXEC */ memset(&Z, 0, sizeof(Z));
INIT_G();
if (ENABLE_FEATURE_DD_SIGNAL_HANDLING) { #if ENABLE_FEATURE_DD_SIGNAL_HANDLING
struct sigaction sa; sigact.sa_handler = dd_output_status;
sigact.sa_flags = SA_RESTART;
memset(&sa, 0, sizeof(sa)); sigemptyset(&sigact.sa_mask);
sa.sa_handler = dd_output_status; sigaction(SIGUSR1, &sigact, NULL);
sa.sa_flags = SA_RESTART; #endif
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, 0);
}
for (n = 1; n < argc; n++) { for (n = 1; n < argc; n++) {
smalluint key_len; smalluint key_len;
@@ -162,11 +182,11 @@ int dd_main(int argc, char **argv)
if (what < OP_conv_notrunc) if (what < OP_conv_notrunc)
bb_error_msg_and_die(bb_msg_invalid_arg, arg, "conv"); bb_error_msg_and_die(bb_msg_invalid_arg, arg, "conv");
if (what == OP_conv_notrunc) if (what == OP_conv_notrunc)
flags &= ~TRUNC_FLAG; flags |= FLAG_NOTRUNC;
if (what == OP_conv_sync) if (what == OP_conv_sync)
flags |= SYNC_FLAG; flags |= FLAG_SYNC;
if (what == OP_conv_noerror) if (what == OP_conv_noerror)
flags |= NOERROR; flags |= FLAG_NOERROR;
if (!key) /* no ',' left, so this was the last specifier */ if (!key) /* no ',' left, so this was the last specifier */
break; break;
arg = key + 1; /* skip this keyword and ',' */ arg = key + 1; /* skip this keyword and ',' */
@@ -180,6 +200,7 @@ int dd_main(int argc, char **argv)
} }
/* These can be large: */ /* These can be large: */
if (what == OP_count) { if (what == OP_count) {
flags |= FLAG_COUNT;
count = XATOU_SFX(arg, dd_suffixes); count = XATOU_SFX(arg, dd_suffixes);
continue; continue;
} }
@@ -201,24 +222,24 @@ int dd_main(int argc, char **argv)
//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
ibuf = obuf = xmalloc(ibs); ibuf = obuf = xmalloc(ibs);
if (ibs != obs) { if (ibs != obs) {
flags |= TWOBUFS_FLAG; flags |= FLAG_TWOBUFS;
obuf = xmalloc(obs); obuf = xmalloc(obs);
} }
if (infile != NULL) if (infile != NULL)
ifd = xopen(infile, O_RDONLY); ifd = xopen(infile, O_RDONLY);
else { else {
ifd = STDIN_FILENO; /* ifd = STDIN_FILENO; - it's zero and it's already there */
infile = bb_msg_standard_input; infile = bb_msg_standard_input;
} }
if (outfile != NULL) { if (outfile != NULL) {
int oflag = O_WRONLY | O_CREAT; int oflag = O_WRONLY | O_CREAT;
if (!seek && (flags & TRUNC_FLAG)) if (!seek && !(flags & FLAG_NOTRUNC))
oflag |= O_TRUNC; oflag |= O_TRUNC;
ofd = xopen(outfile, oflag); ofd = xopen(outfile, oflag);
if (seek && (flags & TRUNC_FLAG)) { if (seek && !(flags & FLAG_NOTRUNC)) {
if (ftruncate(ofd, seek * obs) < 0) { if (ftruncate(ofd, seek * obs) < 0) {
struct stat st; struct stat st;
@@ -247,14 +268,14 @@ int dd_main(int argc, char **argv)
goto die_outfile; goto die_outfile;
} }
while (G.in_full + G.in_part != count) { while ((flags & FLAG_COUNT) && (G.in_full + G.in_part != count)) {
if (flags & NOERROR) /* Pre-zero the buffer when for NOERROR */ if (flags & FLAG_NOERROR) /* Pre-zero the buffer if conv=noerror */
memset(ibuf, '\0', ibs); memset(ibuf, 0, ibs);
n = safe_read(ifd, ibuf, ibs); n = safe_read(ifd, ibuf, ibs);
if (n == 0) if (n == 0)
break; break;
if (n < 0) { if (n < 0) {
if (flags & NOERROR) { if (flags & FLAG_NOERROR) {
n = ibs; n = ibs;
bb_perror_msg("%s", infile); bb_perror_msg("%s", infile);
} else } else
@@ -264,12 +285,12 @@ int dd_main(int argc, char **argv)
G.in_full++; G.in_full++;
else { else {
G.in_part++; G.in_part++;
if (flags & SYNC_FLAG) { if (flags & FLAG_SYNC) {
memset(ibuf + n, '\0', ibs - n); memset(ibuf + n, '\0', ibs - n);
n = ibs; n = ibs;
} }
} }
if (flags & TWOBUFS_FLAG) { if (flags & FLAG_TWOBUFS) {
char *tmp = ibuf; char *tmp = ibuf;
while (n) { while (n) {
size_t d = obs - oc; size_t d = obs - oc;