summaryrefslogtreecommitdiff
path: root/coreutils/dd.c
diff options
context:
space:
mode:
authorDenis Vlasenko2007-07-27 15:02:00 +0000
committerDenis Vlasenko2007-07-27 15:02:00 +0000
commit75878706174290fbf5faac0215b3b9ae78fa9d6f (patch)
tree91bc2115d527c840803bec00c4b1aa6b9ffdbef8 /coreutils/dd.c
parent1d10aaf11617558592b0215fe85bc42fa444e384 (diff)
downloadbusybox-75878706174290fbf5faac0215b3b9ae78fa9d6f.zip
busybox-75878706174290fbf5faac0215b3b9ae78fa9d6f.tar.gz
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
Diffstat (limited to 'coreutils/dd.c')
-rw-r--r--coreutils/dd.c85
1 files changed, 53 insertions, 32 deletions
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 22ad192..75cf373 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -32,6 +32,9 @@ struct globals {
off_t out_full, out_part, in_full, in_part;
};
#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)
{
@@ -73,10 +76,11 @@ int dd_main(int argc, char **argv);
int dd_main(int argc, char **argv)
{
enum {
- SYNC_FLAG = 1 << 0,
- NOERROR = 1 << 1,
- TRUNC_FLAG = 1 << 2,
- TWOBUFS_FLAG = 1 << 3,
+ FLAG_SYNC = 1 << 0,
+ FLAG_NOERROR = 1 << 1,
+ FLAG_NOTRUNC = 1 << 2,
+ FLAG_TWOBUFS = 1 << 3,
+ FLAG_COUNT = 1 << 4,
};
static const char keywords[] =
"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,
#endif
};
- int flags = TRUNC_FLAG;
- size_t oc = 0, ibs = 512, obs = 512;
+ size_t ibs = 512, obs = 512;
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;
+ /* 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 */
-
- if (ENABLE_FEATURE_DD_SIGNAL_HANDLING) {
- struct sigaction sa;
+ memset(&Z, 0, sizeof(Z));
+ INIT_G();
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = dd_output_status;
- sa.sa_flags = SA_RESTART;
- sigemptyset(&sa.sa_mask);
- sigaction(SIGUSR1, &sa, 0);
- }
+#if ENABLE_FEATURE_DD_SIGNAL_HANDLING
+ sigact.sa_handler = dd_output_status;
+ sigact.sa_flags = SA_RESTART;
+ sigemptyset(&sigact.sa_mask);
+ sigaction(SIGUSR1, &sigact, NULL);
+#endif
for (n = 1; n < argc; n++) {
smalluint key_len;
@@ -162,11 +182,11 @@ int dd_main(int argc, char **argv)
if (what < OP_conv_notrunc)
bb_error_msg_and_die(bb_msg_invalid_arg, arg, "conv");
if (what == OP_conv_notrunc)
- flags &= ~TRUNC_FLAG;
+ flags |= FLAG_NOTRUNC;
if (what == OP_conv_sync)
- flags |= SYNC_FLAG;
+ flags |= FLAG_SYNC;
if (what == OP_conv_noerror)
- flags |= NOERROR;
+ flags |= FLAG_NOERROR;
if (!key) /* no ',' left, so this was the last specifier */
break;
arg = key + 1; /* skip this keyword and ',' */
@@ -180,6 +200,7 @@ int dd_main(int argc, char **argv)
}
/* These can be large: */
if (what == OP_count) {
+ flags |= FLAG_COUNT;
count = XATOU_SFX(arg, dd_suffixes);
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
ibuf = obuf = xmalloc(ibs);
if (ibs != obs) {
- flags |= TWOBUFS_FLAG;
+ flags |= FLAG_TWOBUFS;
obuf = xmalloc(obs);
}
if (infile != NULL)
ifd = xopen(infile, O_RDONLY);
else {
- ifd = STDIN_FILENO;
+ /* ifd = STDIN_FILENO; - it's zero and it's already there */
infile = bb_msg_standard_input;
}
if (outfile != NULL) {
int oflag = O_WRONLY | O_CREAT;
- if (!seek && (flags & TRUNC_FLAG))
+ if (!seek && !(flags & FLAG_NOTRUNC))
oflag |= O_TRUNC;
ofd = xopen(outfile, oflag);
- if (seek && (flags & TRUNC_FLAG)) {
+ if (seek && !(flags & FLAG_NOTRUNC)) {
if (ftruncate(ofd, seek * obs) < 0) {
struct stat st;
@@ -247,14 +268,14 @@ int dd_main(int argc, char **argv)
goto die_outfile;
}
- while (G.in_full + G.in_part != count) {
- if (flags & NOERROR) /* Pre-zero the buffer when for NOERROR */
- memset(ibuf, '\0', ibs);
+ while ((flags & FLAG_COUNT) && (G.in_full + G.in_part != count)) {
+ if (flags & FLAG_NOERROR) /* Pre-zero the buffer if conv=noerror */
+ memset(ibuf, 0, ibs);
n = safe_read(ifd, ibuf, ibs);
if (n == 0)
break;
if (n < 0) {
- if (flags & NOERROR) {
+ if (flags & FLAG_NOERROR) {
n = ibs;
bb_perror_msg("%s", infile);
} else
@@ -264,12 +285,12 @@ int dd_main(int argc, char **argv)
G.in_full++;
else {
G.in_part++;
- if (flags & SYNC_FLAG) {
+ if (flags & FLAG_SYNC) {
memset(ibuf + n, '\0', ibs - n);
n = ibs;
}
}
- if (flags & TWOBUFS_FLAG) {
+ if (flags & FLAG_TWOBUFS) {
char *tmp = ibuf;
while (n) {
size_t d = obs - oc;