OSDN Git Service

dd: fix bug where we assume count=INT_MAX when count is unspecified;
authorDenis Vlasenko <vda.linux@googlemail.com>
Fri, 27 Jul 2007 15:02:00 +0000 (15:02 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Fri, 27 Jul 2007 15:02:00 +0000 (15:02 -0000)
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

coreutils/dd.c

index 22ad192..75cf373 100644 (file)
@@ -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;