summaryrefslogtreecommitdiffstats
path: root/bin/dd
diff options
context:
space:
mode:
authorsjg <sjg@FreeBSD.org>2014-05-08 23:54:15 +0000
committersjg <sjg@FreeBSD.org>2014-05-08 23:54:15 +0000
commited3fc70bf5a8edaf648093b11acca450802244ef (patch)
tree8ce0ddd0e6f508bd20c77429c448969589170fae /bin/dd
parentd4e443e0426fee44056ba3c1123455666d083aef (diff)
parenta2e6be0add027bf3e713c0d56ba9715b83a01144 (diff)
downloadFreeBSD-src-ed3fc70bf5a8edaf648093b11acca450802244ef.zip
FreeBSD-src-ed3fc70bf5a8edaf648093b11acca450802244ef.tar.gz
Merge from head
Diffstat (limited to 'bin/dd')
-rw-r--r--bin/dd/conv.c2
-rw-r--r--bin/dd/dd.c74
-rw-r--r--bin/dd/dd.h4
-rw-r--r--bin/dd/misc.c20
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);
OpenPOWER on IntegriCloud