diff options
author | Thomas Quinot <thomas@FreeBSD.org> | 2014-05-07 19:33:29 +0000 |
---|---|---|
committer | Thomas Quinot <thomas@FreeBSD.org> | 2014-05-07 19:33:29 +0000 |
commit | aa7a161b407bcfc565396e93138f38ab059467c0 (patch) | |
tree | 4706b9b8d40564ba7f2cf3a7979e41bc05a4ff61 | |
parent | f8a6c905bf5f61ea6e21c1991ff74326cafef8fa (diff) | |
download | src-aa7a161b407bcfc565396e93138f38ab059467c0.tar.gz src-aa7a161b407bcfc565396e93138f38ab059467c0.zip |
Notes
-rw-r--r-- | bin/dd/dd.c | 67 |
1 files changed, 43 insertions, 24 deletions
diff --git a/bin/dd/dd.c b/bin/dd/dd.c index 8048b6a99d5d..6b4b4f047aa2 100644 --- a/bin/dd/dd.c +++ b/bin/dd/dd.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <sys/disklabel.h> #include <sys/filio.h> +#include <assert.h> #include <ctype.h> #include <err.h> #include <errno.h> @@ -77,6 +78,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 */ @@ -174,6 +176,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; @@ -436,8 +440,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? */ @@ -449,18 +460,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); @@ -475,27 +492,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; } |