diff options
author | sjg <sjg@FreeBSD.org> | 2014-05-08 23:54:15 +0000 |
---|---|---|
committer | sjg <sjg@FreeBSD.org> | 2014-05-08 23:54:15 +0000 |
commit | ed3fc70bf5a8edaf648093b11acca450802244ef (patch) | |
tree | 8ce0ddd0e6f508bd20c77429c448969589170fae /bin/dd | |
parent | d4e443e0426fee44056ba3c1123455666d083aef (diff) | |
parent | a2e6be0add027bf3e713c0d56ba9715b83a01144 (diff) | |
download | FreeBSD-src-ed3fc70bf5a8edaf648093b11acca450802244ef.zip FreeBSD-src-ed3fc70bf5a8edaf648093b11acca450802244ef.tar.gz |
Merge from head
Diffstat (limited to 'bin/dd')
-rw-r--r-- | bin/dd/conv.c | 2 | ||||
-rw-r--r-- | bin/dd/dd.c | 74 | ||||
-rw-r--r-- | bin/dd/dd.h | 4 | ||||
-rw-r--r-- | bin/dd/misc.c | 20 |
4 files changed, 62 insertions, 38 deletions
diff --git a/bin/dd/conv.c b/bin/dd/conv.c index cd66258..2ffba1e 100644 --- a/bin/dd/conv.c +++ b/bin/dd/conv.c @@ -74,7 +74,7 @@ def(void) dd_out(0); /* - * Ddout copies the leftover output to the beginning of + * dd_out copies the leftover output to the beginning of * the buffer and resets the output buffer. Reset the * input buffer to match it. */ diff --git a/bin/dd/dd.c b/bin/dd/dd.c index 7e5bd91..8ae11a7 100644 --- a/bin/dd/dd.c +++ b/bin/dd/dd.c @@ -50,8 +50,8 @@ __FBSDID("$FreeBSD$"); #include <sys/conf.h> #include <sys/disklabel.h> #include <sys/filio.h> -#include <sys/time.h> +#include <assert.h> #include <ctype.h> #include <err.h> #include <errno.h> @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> #include "dd.h" @@ -76,6 +77,7 @@ STAT st; /* statistics */ void (*cfunc)(void); /* conversion function */ uintmax_t cpy_cnt; /* # of blocks to copy */ static off_t pending = 0; /* pending seek if sparse */ +static off_t last_sp = 0; /* size of last added sparse block */ u_int ddflags = 0; /* conversion options */ size_t cbsz; /* conversion block size */ uintmax_t files_cnt = 1; /* # of files to copy */ @@ -123,7 +125,6 @@ static void setup(void) { u_int cnt; - struct timeval tv; if (in.name == NULL) { in.name = "stdin"; @@ -173,6 +174,8 @@ setup(void) } else if ((in.db = malloc(MAX(in.dbsz, cbsz) + cbsz)) == NULL || (out.db = malloc(out.dbsz + cbsz)) == NULL) err(1, "output buffer"); + + /* dbp is the first free position in each buffer. */ in.dbp = in.db; out.dbp = out.db; @@ -240,8 +243,8 @@ setup(void) ctab = casetab; } - (void)gettimeofday(&tv, NULL); - st.start = tv.tv_sec + tv.tv_usec * 1e-6; + if (clock_gettime(CLOCK_MONOTONIC, &st.start)) + err(1, "clock_gettime"); } static void @@ -434,8 +437,15 @@ dd_out(int force) * we play games with the buffer size, and it's usually a partial write. */ outp = out.db; + + /* + * If force, first try to write all pending data, else try to write + * just one block. Subsequently always write data one full block at + * a time at most. + */ for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { - for (cnt = n;; cnt -= nw) { + cnt = n; + do { sparse = 0; if (ddflags & C_SPARSE) { sparse = 1; /* Is buffer sparse? */ @@ -447,18 +457,24 @@ dd_out(int force) } if (sparse && !force) { pending += cnt; + last_sp = cnt; nw = cnt; } else { if (pending != 0) { - if (force) - pending--; + /* If forced to write, and we have no + * data left, we need to write the last + * sparse block explicitly. + */ + if (force && cnt == 0) { + pending -= last_sp; + assert(outp == out.db); + memset(outp, 0, cnt); + } if (lseek(out.fd, pending, SEEK_CUR) == -1) err(2, "%s: seek error creating sparse file", out.name); - if (force) - write(out.fd, outp, 1); - pending = 0; + pending = last_sp = 0; } if (cnt) nw = write(out.fd, outp, cnt); @@ -473,27 +489,29 @@ dd_out(int force) err(1, "%s", out.name); nw = 0; } + outp += nw; st.bytes += nw; - if ((size_t)nw == n) { - if (n != out.dbsz) - ++st.out_part; - else - ++st.out_full; - break; - } - ++st.out_part; - if ((size_t)nw == cnt) - break; - if (out.flags & ISTAPE) - errx(1, "%s: short write on tape device", - out.name); - if (out.flags & ISCHR && !warned) { - warned = 1; - warnx("%s: short write on character device", - out.name); + + if ((size_t)nw == n && n == out.dbsz) + ++st.out_full; + else + ++st.out_part; + + if ((size_t) nw != cnt) { + if (out.flags & ISTAPE) + errx(1, "%s: short write on tape device", + out.name); + if (out.flags & ISCHR && !warned) { + warned = 1; + warnx("%s: short write on character device", + out.name); + } } - } + + cnt -= nw; + } while (cnt != 0); + if ((out.dbcnt -= n) < out.dbsz) break; } diff --git a/bin/dd/dd.h b/bin/dd/dd.h index dace845..a8b45e5 100644 --- a/bin/dd/dd.h +++ b/bin/dd/dd.h @@ -41,7 +41,7 @@ typedef struct { /* XXX ssize_t? */ size_t dbcnt; /* current buffer byte count */ size_t dbrcnt; /* last read byte count */ - size_t dbsz; /* buffer size */ + size_t dbsz; /* block size */ #define ISCHR 0x01 /* character device (warn on short) */ #define ISPIPE 0x02 /* pipe-like (see position.c) */ @@ -64,7 +64,7 @@ typedef struct { uintmax_t trunc; /* # of truncated records */ uintmax_t swab; /* # of odd-length swab blocks */ uintmax_t bytes; /* # of bytes written */ - double start; /* start time of dd */ + struct timespec start; /* start time of dd */ } STAT; /* Flags (in ddflags). */ diff --git a/bin/dd/misc.c b/bin/dd/misc.c index 61f843b..eb1227b 100644 --- a/bin/dd/misc.c +++ b/bin/dd/misc.c @@ -40,14 +40,15 @@ static char sccsid[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94"; __FBSDID("$FreeBSD$"); #include <sys/types.h> -#include <sys/time.h> +#include <err.h> #include <errno.h> #include <inttypes.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> #include "dd.h" @@ -56,16 +57,21 @@ __FBSDID("$FreeBSD$"); void summary(void) { - struct timeval tv; - double secs; + struct timespec end, ts_res; + double secs, res; if (ddflags & C_NOINFO) return; - (void)gettimeofday(&tv, NULL); - secs = tv.tv_sec + tv.tv_usec * 1e-6 - st.start; - if (secs < 1e-6) - secs = 1e-6; + if (clock_gettime(CLOCK_MONOTONIC, &end)) + err(1, "clock_gettime"); + if (clock_getres(CLOCK_MONOTONIC, &ts_res)) + err(1, "clock_getres"); + secs = (end.tv_sec - st.start.tv_sec) + \ + (end.tv_nsec - st.start.tv_nsec) * 1e-9; + res = ts_res.tv_sec + ts_res.tv_nsec * 1e-9; + if (secs < res) + secs = res; (void)fprintf(stderr, "%ju+%ju records in\n%ju+%ju records out\n", st.in_full, st.in_part, st.out_full, st.out_part); |