Compare commits

...

7 Commits

2 changed files with 73 additions and 62 deletions

View File

@ -41,10 +41,6 @@ with a skip offset of 1 skips one byte into the input and reads from the second
byte onwards. A programmer may think of a file as a zero-indexed array of
bytes; in this analogy, the offset given is the index of the byte at which to
start reading or writing.
Seeks and skips aren\(cqt counted in the output statistics because they're
guaranteed to succeed (or the utility will exit unsuccessfully, before it has
written any data).
.\"
.SH OPTIONS
@ -185,9 +181,20 @@ option is specified, this could make written data nonsensical.
Existing files are not truncated on ouput and are instead overwritten.
Many lowercase options have capitalized variants and vice-versa which can be
confusing. Capitalized options tend to affect output or are more intense
versions of lowercase options.
The options
.B -b
and
.B -B
could be confused for each other, and so could
.B -s
and
.BR -S .
The lowercase option affects input and the capitalized option affects output.
The skipped or sought bytes while processing irregular files, such as streams,
are reported in the diagnostic output, because they were actually read or
written. This is as opposed to bytes skipped while processing regular files,
which are not reported.
.\"
.SH RATIONALE
@ -208,3 +215,4 @@ Copyright \(co 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later
.\"
.SH SEE ALSO
.BR dd (1p)
.BR lseek (3p)

113
src/dj.c
View File

@ -56,7 +56,6 @@ static char *fmt_human = "%d+%d > %d+%d; %d > %d\n";
static char *stdin_name = "<stdin>";
static char *stdout_name = "<stdout>";
static int creat_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
| S_IWOTH; /* Consistent with touch(1p). */
static int read_flags = O_RDONLY; /* Consistent with Busybox dd(1). */
@ -69,15 +68,19 @@ static int write_flags = O_WRONLY | O_CREAT;
static struct Io *
Io_read(struct Io *io){
int t;
assert(io->bs > 0);
assert(io->bufuse < io->bs);
io->bytes += (io->bufuse = read(io->fd, io->buf, io->bs));
io->bufuse += (t = read(io->fd, &(io->buf)[io->bufuse],
io->bs - io->bufuse));
assert(io->bufuse <= io->bs);
io->prec += (0 < io->bufuse && io->bufuse < io->bs);
io->rec += (io->bufuse == io->bs);
io->bytes += t;
io->prec += (0 < io->bufuse && io->bufuse < io->bs);
io->rec += (io->bufuse == io->bs);
return io;
}
@ -90,11 +93,11 @@ Io_write(struct Io *io){
assert(io->bufuse <= io->bs);
if((t = write(io->fd, io->buf, io->bufuse)) > 0)
memmove(io->buf, io->buf + t, (io->bufuse -= t));
memmove(io->buf, &(io->buf)[t], (io->bufuse -= t));
io->bytes += t;
io->prec += (t > 0 && io->bufuse > 0);
io->rec += (t > 0 && io->bufuse == 0);
io->prec += (0 < io->bufuse && 0 < t);
io->rec += (io->bufuse == 0 && 0 < t);
return io;
}
@ -233,58 +236,58 @@ int main(int argc, char *argv[]){
io[i].seek = 0;
}
/* hard skipping */
if(io[0].seek > 0){
do{
if((io[0].bufuse = read(
io[0].fd, io[0].buf, MIN(io[0].bs, io[0].seek)))
== 0)
/* second chance */
io->bufuse = read(
io[0].fd, io[0].buf, MIN(io[0].bs, io[0].seek));
}while((io[0].seek -= io[0].bufuse) > 0 && io[0].bufuse != 0);
io[0].bufuse = 0;
}
/* hard seeking */
if(io[1].seek > 0){
memset(io[1].buf, '\0', io[1].bs);
/* We're going to cheat and use bufuse as the retval for write(2),
* which is fine because it'll be zeroed as this function returns
* anyway. */
size_t t;
do{
if((io[1].bufuse = write(
io[1].fd, io[1].buf, MIN(io[1].bs, io[1].seek)))
== 0)
/* second chance */
io[1].bufuse = write(
io[1].fd, io[1].buf, MIN(io[1].bs, io[1].seek));
}while((io[1].seek -= io[1].bufuse) > 0 && io[1].bufuse != 0);
memset(io[1].buf, '\0',
(t = io[1].bufuse = MIN(io[1].bs, io[1].seek)));
if(Io_write(&io[1])->bufuse == t && !noerror)
Io_write(&io[1]); /* second chance */
}while((io[1].seek -= (t - io[1].bufuse)) > 0 && io[1].bufuse != t);
io[1].bufuse = 0;
}
/* Sought bytes aren't counted in the statistics because successful seeking
* is guaranteed here. */
for(i = 0; i < 2; ++i)
if(io[i].seek > 0)
return oserr(io[i].fn);
if(io[1].seek > 0){
fprintio(stderr, fmt, io);
return oserr(io[1].fn);
}
do{ /* read */
if(Io_read(&io[0])->bufuse == 0 && !noerror)
Io_read(&io[0]); /* second chance */
if(io[0].bufuse == 0) /* that's all she wrote */
break;
do{
assert(io[0].bufuse == 0);
if(io[0].bufuse < io[0].bs){
fprintf(stderr, "%s: Partial read:\n\t", program_name);
fprintio(stderr, fmt, io);
if(!noerror)
count = 1;
if(align >= 0){
/* fill the rest of the ibuf with padding */
memset(io[0].buf + io[0].bufuse, align,
io[0].bs - io[0].bufuse);
io->bufuse = io->bs;
{ /* read */
char skipping;
int t;
if((skipping = (io[0].seek > 0)) && io[0].seek < io[0].bs)
io[0].bufuse = io[0].bs - io[0].seek;
t = io[0].bufuse;
if(Io_read(&io[0])->bufuse == t && !noerror)
Io_read(&io[0]); /* second chance */
if(io[0].bufuse == t) /* that's all she wrote */
break;
if(/* t < io[0].bufuse && */ io[0].bufuse < io[0].bs){
assert(!skipping);
fprintf(stderr, "%s: Partial read:\n\t", program_name);
fprintio(stderr, fmt, io);
if(!noerror)
count = 1;
if(align >= 0){
/* fill the rest of the ibuf with padding */
memset(&(io[0].buf)[io[0].bufuse], align,
io[0].bs - io[0].bufuse);
io->bufuse = io->bs;
}
}
if(skipping){
io[0].bufuse = 0;
count += (count != 0);
continue;
}
}
@ -299,16 +302,16 @@ int main(int argc, char *argv[]){
memcpy(io[1].buf, io[0].buf,
(io[1].bufuse = (n = MIN(io[0].bufuse, io[1].bs))));
/* permute the copied units out of ibuf */
memmove(io[0].buf, io[0].buf + n, (io[0].bufuse -= n));
memmove(io[0].buf, &(io[0].buf)[n], (io[0].bufuse -= n));
}else /* if(io[0].bs < io[1].bs) */ {
int n;
/* drain what we can from ibuf */
memcpy(io[1].buf + io[1].bufuse, io[0].buf,
memcpy(&(io[1].buf)[io[1].bufuse], io[0].buf,
(n = MIN(io[0].bufuse, io[1].bs - io[1].bufuse)));
io[1].bufuse += n;
/* permute out the copied units */
memmove(io[0].buf, io[0].buf + n, io[0].bs - n);
memmove(io[0].buf, &(io[0].buf)[n], io[0].bs - n);
io[0].bufuse -= n;
if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1)
@ -323,7 +326,7 @@ int main(int argc, char *argv[]){
break;
}
if(0 < io[1].bufuse && io[1].bufuse < t){
if(0 < io[1].bufuse /* && io[1].bufuse < t */){
fprintf(stderr, "%s: Partial write:\n\t", program_name);
fprintio(stderr, fmt, io);
if(!noerror)