Index: head/bin/dd/args.c =================================================================== --- head/bin/dd/args.c +++ head/bin/dd/args.c @@ -57,6 +57,7 @@ static int c_arg(const void *, const void *); static int c_conv(const void *, const void *); +static int c_iflag(const void *, const void *); static int c_oflag(const void *, const void *); static void f_bs(char *); static void f_cbs(char *); @@ -66,6 +67,7 @@ static void f_fillchar(char *); static void f_ibs(char *); static void f_if(char *); +static void f_iflag(char *); static void f_obs(char *); static void f_of(char *); static void f_oflag(char *); @@ -89,6 +91,7 @@ { "fillchar", f_fillchar, C_FILL, C_FILL }, { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, { "if", f_if, C_IF, C_IF }, + { "iflag", f_iflag, 0, 0 }, { "iseek", f_skip, C_SKIP, C_SKIP }, { "obs", f_obs, C_OBS, C_BS|C_OBS }, { "of", f_of, C_OF, C_OF }, @@ -259,7 +262,39 @@ in.name = arg; } +static const struct iflag { + const char *name; + uint64_t set, noset; +} ilist[] = { + { "fullblock", C_IFULLBLOCK, C_SYNC }, +}; + static void +f_iflag(char *arg) +{ + struct iflag *ip, tmp; + + while (arg != NULL) { + tmp.name = strsep(&arg, ","); + ip = bsearch(&tmp, ilist, nitems(ilist), sizeof(struct iflag), + c_iflag); + if (ip == NULL) + errx(1, "unknown iflag %s", tmp.name); + if (ddflags & ip->noset) + errx(1, "%s: illegal conversion combination", tmp.name); + ddflags |= ip->set; + } +} + +static int +c_iflag(const void *a, const void *b) +{ + + return (strcmp(((const struct iflag *)a)->name, + ((const struct iflag *)b)->name)); +} + +static void f_obs(char *arg) { uintmax_t res; @@ -339,7 +374,7 @@ { "parset", C_PARSET, C_PARODD|C_PAREVEN|C_PARNONE, NULL}, { "sparse", C_SPARSE, 0, NULL }, { "swab", C_SWAB, 0, NULL }, - { "sync", C_SYNC, 0, NULL }, + { "sync", C_SYNC, C_IFULLBLOCK, NULL }, { "ucase", C_UCASE, C_LCASE, NULL }, { "unblock", C_UNBLOCK, C_BLOCK, NULL }, }; Index: head/bin/dd/dd.h =================================================================== --- head/bin/dd/dd.h +++ head/bin/dd/dd.h @@ -104,6 +104,7 @@ #define C_FSYNC 0x0000000080000000ULL #define C_FDATASYNC 0x0000000100000000ULL #define C_OFSYNC 0x0000000200000000ULL +#define C_IFULLBLOCK 0x0000000400000000ULL #define C_PARITY (C_PAREVEN | C_PARODD | C_PARNONE | C_PARSET) Index: head/bin/dd/dd.1 =================================================================== --- head/bin/dd/dd.1 +++ head/bin/dd/dd.1 @@ -102,6 +102,22 @@ Read input from .Ar file instead of the standard input. +.It Cm iflag Ns = Ns Ar value Ns Op , Ns Ar value ... +Where +.Cm value +is one of the symbols from the following list. +.Bl -tag -width "fullblock" +.It Cm fullblock +Reading from the input file may not obtain a full block. +When a read returns short, continue reading to fill the block. +Without this flag, +.Cm count +limits the number of times +.Xr read 2 +is called on the input rather than the number of blocks copied in full. +May not be combined with +.Cm conv=sync . +.El .It Cm iseek Ns = Ns Ar n Seek on the input file .Ar n Index: head/bin/dd/dd.c =================================================================== --- head/bin/dd/dd.c +++ head/bin/dd/dd.c @@ -408,13 +408,15 @@ memset(in.dbp, 0, in.dbsz); } - n = read(in.fd, in.dbp, in.dbsz); - if (n == 0) { - in.dbrcnt = 0; + in.dbrcnt = 0; +fill: + n = read(in.fd, in.dbp + in.dbrcnt, in.dbsz - in.dbrcnt); + + /* EOF */ + if (n == 0 && in.dbrcnt == 0) return; - } - /* Read error. */ + /* Read error */ if (n == -1) { /* * If noerror not specified, die. POSIX requires that @@ -438,26 +440,26 @@ /* If sync not specified, omit block and continue. */ if (!(ddflags & C_SYNC)) continue; + } - /* Read errors count as full blocks. */ - in.dbcnt += in.dbrcnt = in.dbsz; - ++st.in_full; + /* If conv=sync, use the entire block. */ + if (ddflags & C_SYNC) + n = in.dbsz; - /* Handle full input blocks. */ - } else if ((size_t)n == (size_t)in.dbsz) { - in.dbcnt += in.dbrcnt = n; - ++st.in_full; + /* Count the bytes read for this block. */ + in.dbrcnt += n; - /* Handle partial input blocks. */ - } else { - /* If sync, use the entire block. */ - if (ddflags & C_SYNC) - in.dbcnt += in.dbrcnt = in.dbsz; - else - in.dbcnt += in.dbrcnt = n; + /* Count the number of full and partial blocks. */ + if (in.dbrcnt == in.dbsz) + ++st.in_full; + else if (ddflags & C_IFULLBLOCK && n != 0) + goto fill; /* these don't count */ + else ++st.in_part; - } + /* Count the total bytes read for this file. */ + in.dbcnt += in.dbrcnt; + /* * POSIX states that if bs is set and no other conversions * than noerror, notrunc or sync are specified, the block @@ -478,6 +480,7 @@ swapbytes(in.dbp, (size_t)n); } + /* Advance to the next block. */ in.dbp += in.dbrcnt; (*cfunc)(); if (need_summary)