~nabijaczleweli/voreutils

60382426fdc1a2e8bd9cd7a753dc717050bda25f — наб 15 days ago dcdc8f9 trunk
Manually exhaust data passed to dd commit_write() instead of assuming it always does everything

Turns out Linux writev() is annoying to interrupt I must've failed
last time and concluded it can't be done
2 files changed, 29 insertions(+), 8 deletions(-)

M cmd/dd.cpp
M man/dd.1
M cmd/dd.cpp => cmd/dd.cpp +25 -8
@@ 552,10 552,27 @@ int main(int, const char * const * argv) {
			write_adv_off = write_off;
			last_sought   = true;
		} else {
			while((wr = writev(1, iovs_beg, iovs_end - iovs_beg)) == -1 && errno == EINTR)
			wr = 0;
		rewrite:
			ssize_t iwr;
			while((iwr = writev(1, iovs_beg, iovs_end - iovs_beg)) == -1 && errno == EINTR)
				;
			if(wr == -1)
			if(iwr == -1)
				return std::fprintf(stderr, "%s: %s: %s\n", argv[0], opt_of ?: "stdout", std::strerror(errno)), write_err = true, false;
			wr += iwr;

			for(std::size_t remaining = iwr; iovs_beg != iovs_end;)
				if(remaining >= iovs_beg->iov_len) {
					remaining -= iovs_beg->iov_len;
					++iovs_beg;
				} else {
					iovs_beg->iov_len -= remaining;
					iovs_beg->iov_base = static_cast<std::uint8_t *>(iovs_beg->iov_base) + remaining;
					break;
				}
			if(iovs_beg != iovs_end)
				goto rewrite;

			write_off += wr;
			if(oflags.second.nocache)
				advise(1, write_off, write_adv_off);


@@ 569,10 586,10 @@ int main(int, const char * const * argv) {
	auto append_writebuf = [&](auto beg, auto end) {
		auto ret = true;
		while(ret && static_cast<std::size_t>((end - beg) + (buffer_out_cur - buffer_out)) >= obs) {
			const auto ichunk         = std::min(static_cast<std::size_t>(obs - (buffer_out_cur - buffer_out)), static_cast<std::size_t>(end - beg));
			const struct iovec iovs[] = {{buffer_out, static_cast<std::size_t>(buffer_out_cur - buffer_out)}, {beg, ichunk}};
			ret                       = commit_write(std::begin(iovs), std::end(iovs));
			buffer_out_cur            = buffer_out;
			const auto ichunk   = std::min(static_cast<std::size_t>(obs - (buffer_out_cur - buffer_out)), static_cast<std::size_t>(end - beg));
			struct iovec iovs[] = {{buffer_out, static_cast<std::size_t>(buffer_out_cur - buffer_out)}, {beg, ichunk}};
			ret                 = commit_write(std::begin(iovs), std::end(iovs));
			buffer_out_cur      = buffer_out;
			beg += ichunk;
		}
		std::memcpy(buffer_out_cur, beg, end - beg);


@@ 685,7 702,7 @@ int main(int, const char * const * argv) {
		}

		if(direct_copy) {
			const struct iovec iov { buffer_in, static_cast<std::size_t>(rd) };
			struct iovec iov { buffer_in, static_cast<std::size_t>(rd) };
			if(!commit_write(&iov, &iov + 1))
				goto break2;
			continue;


@@ 741,7 758,7 @@ int main(int, const char * const * argv) {
	}

	if(buffer_out_cur != buffer_out) {
		const struct iovec iov { buffer_out, static_cast<std::size_t>(buffer_out_cur - buffer_out) };
		struct iovec iov { buffer_out, static_cast<std::size_t>(buffer_out_cur - buffer_out) };
		commit_write(&iov, &iov + 1);
	}


M man/dd.1 => man/dd.1 +4 -0
@@ 137,6 137,10 @@ Accumulate until at least
bytes available
.El
.Pp
Each block is written in its entirety as part of one
.Xr write 2
call, or, if that returns short, retried until exhaustion.
.Pp
.Cm conv Ns = Ns Cm block Ns \&| Ns Cm unblock
view the input as a continuous stream of bytes:
they do