ls: round block counts up when scaling to a block size - #14330
ls: round block counts up when scaling to a block size#14330Socialpranker wants to merge 1 commit into
Conversation
|
GNU testsuite comparison: |
it is old, please try with master binaries |
A partly used block still occupies a whole block, so scaling an allocation to the block size rounds up. `ls -s --block-size=1000` on a 4096-byte allocation reported 4 blocks instead of 5, and every non-divisor block size was off the same way. The `total` line had a second, related defect: it summed the already scaled per-file figures, so the rounding error was repeated once per entry. It now sums the allocated bytes and scales the sum once. Splits the two steps apart: `get_block_bytes` reports the allocation in bytes and `scale_block_bytes` scales it, rounding up. Non-unix keeps its file-size fallback unscaled, as before.
53428ea to
147af14
Compare
|
Rebased onto current main (147af14 on b7519db) — no conflicts, ls.rs untouched upstream in this window. Re-ran the differential A/B against GNU coreutils 9.11, built from the official release tarball (not the distro package used before): 17 block sizes × 9 flag combinations over a directory with 6 files, a subdirectory, a symlink and a FIFO — 153 cases total. Before the fix: 77/153 differed from GNU. After: 0/153 differ, 0 regressions. Rounding and the The remaining suffix-only block-size cases (bare Separately: the two |
ls -s --block-size=1000on a 4096-byte allocation printed 4 blocks. A blockthat is only partly used still occupies a whole block, so it is 5:
Every block size that is not a divisor of the allocation was off the same way:
--block-size=Mon a 4 KiB file printed0,--block-size=3000printed 1where it should print 2.
--block-size=512,2048and the default1024divide evenly on a 4 KiB allocation, which is why the existing tests never
caught it.
The
totallinetotalhad a second defect on top of the first. It summed the already scaledper-file figures, so the rounding error was repeated once per entry:
GNU adds up the allocated bytes and scales the sum once. Rounding up per file
and then adding, which is what a one-line fix in the scaling function alone
would produce, overshoots by up to one block per entry.
So the two steps are split apart:
get_block_bytesreports the allocation inbytes,
scale_block_bytesscales a byte count to the block size and rounds up.The per-file cell scales one file;
totalscales the sum.-h/--sipass thebyte count through, as before, since the human-readable formatter scales it
itself.
Non-unix has no allocation figure and falls back to the file size, which was
never scaled here.
scale_block_bytesleaves it alone, so that path isunchanged;
cargo check --target x86_64-pc-windows-gnuis clean.How the GNU behavior was established
By running the installed GNU binary as a black box and recording its output --
the rounding rule and the
totalsemantics above are both read off thetranscripts shown here. I did not read GNU coreutils source.
Testing
cargo test --features ls --no-default-features -- test_ls: 160 passed, 0failed (159 pre-existing, 1 new). No existing test needed a change.
test_ls_block_size_rounds_upderives its expectations from thefilesystem's own
blocks()rather than assuming a 4 KiB granularity, andreturns early when the allocation divides evenly, so it cannot fail spuriously
on a filesystem with a different allocation unit.
ls.rsalone (test file untouched) makes the newtest fail.
cargo fmt --all --checkandcargo clippy -p uu_ls --all-targets: clean.debian:stable-slim, 17 blocksizes x 9 flag combinations over a directory of 6 files, a subdirectory, a
symlink and a FIFO: 63 cases moved from differing to byte-identical, 0
regressions. The
LS_BLOCK_SIZE,BLOCK_SIZEandBLOCKSIZEpaths matchGNU too, where they did not before.
The 27 cases that still differ are all suffix-only block sizes (
K,KB,M),where GNU prints the unit with the number (
4K, not4). That is a separatedefect in a different place -- the same one #13655 is fixing for
du-- and thefigures themselves now agree there as well.
Disclosure
Prepared with AI assistance (Claude Opus 5, via Claude Code), per the AI policy
in CONTRIBUTING.md. Every GNU behavior quoted above came from running the
installed binary, not from reading GPL source. All testing was run locally.