On 23/10/2026 16:38, Iván Ezequiel Rodriguez wrote:
With iflag=count_bytes or iflag=skip_bytes, a short read from a
non-seekable input could stop the copy or skip early, so fewer
bytes than requested were processed.  Meet the byte budget even
when individual reads are short, and diagnose partial reads in
these modes when bs= is used without iflag=fullblock (including
when only a byte remnant remains).

Keep a single skip() read/error path; only progress accounting
differs between record-oriented and byte-oriented modes.  The same
scanargs split feeds both skip_bytes and seek_bytes call sites.

* src/dd.c (scanargs): Enable warn_partial_read for
skip_bytes/max_bytes.
(skip): Byte-oriented skip/seek accumulates discarded input.
(dd_copy): Track remaining bytes for count_bytes; debit
conv=noerror,sync substitutions with need.
* tests/dd/count-bytes-pipe.sh: LD_PRELOAD short-read repro,
fifo cases, skip EOF remnant, seek_bytes, and probed strace EIO.
* tests/local.mk: Reference the new test.
* NEWS: Mention the fix.

I wouldn't categorize it as a fix, as we already output
the following warning in this case:

  warning: partial read (... bytes); suggest iflag=fullblock

So this would be an improvement really.

There are a few issues with this though.
It adds a regression making count= mandatory:

  $ src/dd iflag=count_bytes if=/dev/null status=none
  dd: invalid number: ‘count’

Also we've deprecated the count_bytes and skip_bytes flags,
so I would avoid mentioning/testing them, instead referring
to count=...B and skip=...B.

Also the test is WAY too complicated.
Do you really generate that manually?
If not can you say what tools you used.

I think something simple like this should work:

  short_read_dd_ ()
  {
    local delay="$1"
    { printf a; sleep "$delay"; printf bcdefghijkl; } |
      dd bs=8 status=noxfer "$operand" > out 2> err || return 1
    compare exp out || return 1
    test "$operand" = skip=10B || compare exp-err err
  }

  printf abcdefghij > exp || framework_failure_
  operand='count=10B'
  printf '1+2 records %s\n' 'in' 'out' > exp-err || framework_failure_
  retry_delay_ short_read_dd_ .1 6 || fail=1

  printf kl > exp || framework_failure_
  operand='skip=10B'
  retry_delay_ short_read_dd_ .5 2 || fail=1


Actually I'm thinking of a simpler change to the source also.

Leave it with me.

thanks,
Padraig



Reply via email to