Add iflag=fullblock to dd
Normally, count=n means read(2) will be called n times on the input to dd. If the read() returns short, as may happen when reading from a pipe, fewer bytes will be copied from the input. With conv=sync the buffer is padded with zeros to fill the rest of the block. iflag=fullblock causes dd to continue reading until the block is full, so that count=n means n full blocks are copied. This flag is compatible with illumos and GNU dd and is used in the ZFS test suite. Submitted by: Ryan Moeller Reviewed by: manpages, mmacy@ MFC after: 1 week Sponsored by: iXsystems, Inc. Differential Revision: https://reviews.freebsd.org/D21441
This commit is contained in:
parent
919156e34c
commit
b52c534bff
@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
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_files(char *);
|
||||
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 @@ static const struct arg {
|
||||
{ "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,6 +262,38 @@ f_if(char *arg)
|
||||
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)
|
||||
{
|
||||
@ -339,7 +374,7 @@ static const struct conv {
|
||||
{ "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 },
|
||||
};
|
||||
|
16
bin/dd/dd.1
16
bin/dd/dd.1
@ -102,6 +102,22 @@ bytes instead of the default 512.
|
||||
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
|
||||
|
51
bin/dd/dd.c
51
bin/dd/dd.c
@ -408,13 +408,15 @@ dd_in(void)
|
||||
memset(in.dbp, 0, in.dbsz);
|
||||
}
|
||||
|
||||
n = read(in.fd, in.dbp, in.dbsz);
|
||||
if (n == 0) {
|
||||
in.dbrcnt = 0;
|
||||
return;
|
||||
}
|
||||
in.dbrcnt = 0;
|
||||
fill:
|
||||
n = read(in.fd, in.dbp + in.dbrcnt, in.dbsz - in.dbrcnt);
|
||||
|
||||
/* Read error. */
|
||||
/* EOF */
|
||||
if (n == 0 && in.dbrcnt == 0)
|
||||
return;
|
||||
|
||||
/* Read error */
|
||||
if (n == -1) {
|
||||
/*
|
||||
* If noerror not specified, die. POSIX requires that
|
||||
@ -438,26 +440,26 @@ dd_in(void)
|
||||
/* 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;
|
||||
|
||||
/* Handle full input blocks. */
|
||||
} else if ((size_t)n == (size_t)in.dbsz) {
|
||||
in.dbcnt += in.dbrcnt = n;
|
||||
++st.in_full;
|
||||
|
||||
/* 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;
|
||||
++st.in_part;
|
||||
}
|
||||
|
||||
/* If conv=sync, use the entire block. */
|
||||
if (ddflags & C_SYNC)
|
||||
n = in.dbsz;
|
||||
|
||||
/* Count the bytes read for this block. */
|
||||
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 @@ dd_in(void)
|
||||
swapbytes(in.dbp, (size_t)n);
|
||||
}
|
||||
|
||||
/* Advance to the next block. */
|
||||
in.dbp += in.dbrcnt;
|
||||
(*cfunc)();
|
||||
if (need_summary)
|
||||
|
@ -104,6 +104,7 @@ typedef struct {
|
||||
#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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user