Changeset View
Changeset View
Standalone View
Standalone View
bin/dd/dd.c
Show First 20 Lines • Show All 471 Lines • ▼ Show 20 Lines | dd_in(void) | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Clean up any remaining I/O and flush output. If necessary, the output file | * Clean up any remaining I/O and flush output. If necessary, the output file | ||||
* is truncated. | * is truncated. | ||||
*/ | */ | ||||
static void | static void | ||||
dd_close(void) | dd_close(void) | ||||
danfe: Why explicit cast to `off_t` is needed for zero? | |||||
Done Inline ActionsENOIDEA. :) I just copied code from some other place in the dd.c. I can only guess it's perhaps used to workaround some early cc(1) idiosyncrasy. sobomax: ENOIDEA. :) I just copied code from some other place in the dd.c. I can only guess it's perhaps… | |||||
Not Done Inline ActionsIt's because this code is old. K&R required you cast all long args. off_t is a long arg, so it has to be cast. It hasn't been required since we've had a ANSI compiler in the tree (so ~30 years, eg 4.4BSD could have ditched it). imp: It's because this code is old. K&R required you cast all long args. off_t is a long arg, so it… | |||||
{ | { | ||||
if (cfunc == def) | if (cfunc == def) | ||||
def_close(); | def_close(); | ||||
else if (cfunc == block) | else if (cfunc == block) | ||||
block_close(); | block_close(); | ||||
else if (cfunc == unblock) | else if (cfunc == unblock) | ||||
unblock_close(); | unblock_close(); | ||||
if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) { | if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) { | ||||
Show All 13 Lines | dd_close(void) | ||||
* up to the end of the hole (without having to write any data). | * up to the end of the hole (without having to write any data). | ||||
*/ | */ | ||||
if (out.seek_offset > 0 && (out.flags & ISTRUNC)) { | if (out.seek_offset > 0 && (out.flags & ISTRUNC)) { | ||||
if (ftruncate(out.fd, out.seek_offset) == -1) | if (ftruncate(out.fd, out.seek_offset) == -1) | ||||
err(1, "truncating %s", out.name); | err(1, "truncating %s", out.name); | ||||
} | } | ||||
} | } | ||||
static ssize_t | |||||
dsk_trim(int d_fd, size_t size) | |||||
{ | |||||
off_t ioarg[2], npos; | |||||
int eval; | |||||
ioarg[0] = lseek(d_fd, (off_t)0, SEEK_CUR); | |||||
if (ioarg[0] < 0) | |||||
return (ioarg[0]); | |||||
ioarg[1] = size; | |||||
eval = ioctl(d_fd, DIOCGDELETE, ioarg); | |||||
if (eval != 0) | |||||
return (-1); | |||||
npos = lseek(d_fd, size, SEEK_CUR); | |||||
if (npos < 0) | |||||
return (npos); | |||||
return (npos - ioarg[0]); | |||||
} | |||||
void | void | ||||
dd_out(int force) | dd_out(int force) | ||||
{ | { | ||||
u_char *outp; | u_char *outp; | ||||
size_t cnt, n; | size_t cnt, n; | ||||
ssize_t nw; | ssize_t nw; | ||||
static int warned; | static int warned; | ||||
int sparse; | int sparse; | ||||
Done Inline ActionsHere sparse is checked as boolean (no != 0)... danfe: Here `sparse` is checked as boolean (no `!= 0`)... | |||||
/* | /* | ||||
* Write one or more blocks out. The common case is writing a full | * Write one or more blocks out. The common case is writing a full | ||||
* output block in a single write; increment the full block stats. | * output block in a single write; increment the full block stats. | ||||
* Otherwise, we're into partial block writes. If a partial write, | * Otherwise, we're into partial block writes. If a partial write, | ||||
* and it's a character device, just warn. If a tape device, quit. | * and it's a character device, just warn. If a tape device, quit. | ||||
* | * | ||||
* The partial writes represent two cases. 1: Where the input block | * The partial writes represent two cases. 1: Where the input block | ||||
* was less than expected so the output block was less than expected. | * was less than expected so the output block was less than expected. | ||||
* 2: Where the input block was the right size but we were forced to | * 2: Where the input block was the right size but we were forced to | ||||
* write the block in multiple chunks. The original versions of dd(1) | * write the block in multiple chunks. The original versions of dd(1) | ||||
* never wrote a block in more than a single write, so the latter case | * never wrote a block in more than a single write, so the latter case | ||||
* never happened. | * never happened. | ||||
* | * | ||||
* One special case is if we're forced to do the write -- in that case | * One special case is if we're forced to do the write -- in that case | ||||
* we play games with the buffer size, and it's usually a partial write. | * we play games with the buffer size, and it's usually a partial write. | ||||
*/ | */ | ||||
outp = out.db; | outp = out.db; | ||||
/* | /* | ||||
* If force, first try to write all pending data, else try to write | * If force, first try to write all pending data, else try to write | ||||
* just one block. Subsequently always write data one full block at | * just one block. Subsequently always write data one full block at | ||||
* a time at most. | * a time at most. | ||||
Done Inline Actions... yet here, it is checked correctly (as int). Also, since it is ||, the order does not matter, and sparse can also be checked before ddflags like in the expression above? danfe: ... yet here, it is checked correctly (as int). Also, since it is `||`, the order does not… | |||||
*/ | */ | ||||
for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { | for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { | ||||
cnt = n; | cnt = n; | ||||
do { | do { | ||||
sparse = 0; | sparse = 0; | ||||
if (ddflags & C_SPARSE) { | if (ddflags & (C_SPARSE | C_TRIM)) { | ||||
/* Is buffer sparse? */ | /* Is buffer sparse? */ | ||||
sparse = BISZERO(outp, cnt); | sparse = BISZERO(outp, cnt); | ||||
} | } | ||||
if (sparse && !force) { | if (sparse && !force && !(ddflags & C_TRIM)) { | ||||
pending += cnt; | pending += cnt; | ||||
nw = cnt; | nw = cnt; | ||||
} else { | } else { | ||||
if (pending != 0) { | if (pending != 0) { | ||||
/* | /* | ||||
* Seek past hole. Note that we need to record the | * Seek past hole. Note that we need to record the | ||||
* reached offset, because we might have no more data | * reached offset, because we might have no more data | ||||
* to write, in which case we'll need to call | * to write, in which case we'll need to call | ||||
* ftruncate to extend the file size. | * ftruncate to extend the file size. | ||||
*/ | */ | ||||
out.seek_offset = lseek(out.fd, pending, SEEK_CUR); | out.seek_offset = lseek(out.fd, pending, SEEK_CUR); | ||||
if (out.seek_offset == -1) | if (out.seek_offset == -1) | ||||
err(2, "%s: seek error creating sparse file", | err(2, "%s: seek error creating sparse file", | ||||
out.name); | out.name); | ||||
pending = 0; | pending = 0; | ||||
} | } | ||||
if (cnt) { | if (cnt) { | ||||
if (!sparse || !(ddflags & C_TRIM)) { | |||||
nw = write(out.fd, outp, cnt); | nw = write(out.fd, outp, cnt); | ||||
out.seek_offset = 0; | } else { | ||||
nw = dsk_trim(out.fd, cnt); | |||||
} | |||||
} else { | } else { | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
if (nw <= 0) { | if (nw <= 0) { | ||||
if (nw == 0) | if (nw == 0) | ||||
errx(1, "%s: end of device", out.name); | errx(1, "%s: end of device", out.name); | ||||
Show All 36 Lines |
Why explicit cast to off_t is needed for zero?