stat: GNU parity for device numbers and the default record - #101
Open
kelp wants to merge 6 commits into
Open
Conversation
Nine failing tests for issue #92. Unit tests build a synthetic StatResult so the renderers can be driven with a minor above 255 without a real device node; integration tests diff our output against GNU stat on /dev/null and on a scanned /dev node whose minor exceeds 255. Red on Linux: %T, -t field 10, and the default Device line all truncate minor 260 to 4, and no file type gets GNU's "Device type: M,m" suffix. Red on macOS for the suffix only; the Darwin encoding tests pass, pinning that path as untouched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VapqXpB1wtGk5Cb9KeMSok
%t/%T, the -t terse fields, and the default Device line each kept their own copy of the dev_t bit layout. The Linux copy masked the minor with 0xff, dropping the high bits the kernel packs further up, so any device with a minor above 255 rendered wrong: stat -c '%t %T' /dev/binder gave "a 4" where GNU gives "a 104". All three now call devMajor/devMinor, leaving makeDev and those two helpers as the only code that knows the layout. macOS masks were already identical to the helpers, so that path is unchanged. Also adds GNU's "Device type: MAJ,MIN" field, which the default output never emitted. Character and block special files get it, and their Links column widens to five to match; every other file type renders as before. Fixes #92 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VapqXpB1wtGk5Cb9KeMSok
Eight failing tests for issue #98. GNU's default_format puts a literal tab after the Size field and literal spaces after Blocks, IO Block, and Inode. Our format strings fold those separators into the pad widths, so they render identically for everyday values and vanish entirely once a field overflows its pad. Three unit tests cover the Size line and are ungated: one pins GNU's exact bytes for a 1383-byte file, two drive synthetic sizes and block counts past the pad. Two more cover the Device line with an 11-digit inode, Linux-gated like their issue-92 neighbours because the dev_t layout differs. The integration helper diffs the whole record against GNU for a regular file, a directory, and /dev/null, replacing the grep '^Device:' scoping those earlier tests needed. Red on both platforms: expected '\x09' after the size field, found '\x42' -- the B of Blocks. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VapqXpB1wtGk5Cb9KeMSok
The green phase fell back to a briefing embedded from an earlier dd run when none was passed in, so a bug fix could be implemented against another bug's notes. Re-scout instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VapqXpB1wtGk5Cb9KeMSok
GNU's default_format puts a literal tab after the Size field and literal spaces after Blocks, IO Block, and Inode. We folded each separator into the preceding pad width, which renders identically for everyday values and drops the separator entirely once a field overflows its pad: a 10GB file printed "10737418240Blocks:", and an 11-digit inode left one space before Links where GNU leaves two. Three format literals now match coreutils 9.5 byte for byte. On Linux, stat FILE is identical to /usr/bin/stat FILE for a regular file, a directory, and /dev/null, which lets the whole record be diffed against GNU instead of just the Device line. Fixes #98 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VapqXpB1wtGk5Cb9KeMSok
The EXAMPLES record rendered the separator as spaces, which is what the code used to emit. Also notes the fix in the changelog. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VapqXpB1wtGk5Cb9KeMSok
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two related GNU-parity fixes in
stat's default output, both found bydiffing our record against
/usr/bin/staton Linux.Device minor numbers above 255 (#92)
%t/%T, the-tterse fields, and the defaultDevice:line eachcarried their own copy of the
dev_tbit layout. The Linux copy maskedthe minor with
0xff, dropping the high bits the kernel packs furtherup, so
stat -c '%t %T' /dev/bindergavea 4where GNU givesa 104.All three now call
devMajor/devMinor, leavingmakeDevand those twohelpers as the only code that knows the layout. macOS was already
correct and is unchanged.
Also adds GNU's
Device type: MAJ,MINfield, which we never emitted.Character and block special files get it, and their
Linkscolumnwidens to five to match.
Default-record separators (#98)
GNU separates
Size:fromBlocks:with a tab, and follows theBlocks,IO BlockandInodefields with literal spaces. We foldedeach separator into the preceding column's pad width. That renders
identically for everyday values, which is why it went unnoticed, but the
separator disappears entirely once a field outgrows its pad:
10737418240Blocks:— no separator at allLinks:, not twoThe issue reported only the missing tab; the other two divergences are
the same defect and turned up while checking whether the rest of the
line was genuinely equivalent or merely coincidentally aligned. Fix is
three format literals, matched against coreutils 9.5
default_format.Still divergent, out of scope here: GNU's
%Nshell-quoting of filenames (
File: 'my file'). We never quote.Tests
Red was verified on both platforms before each fix, failing for the
right reason — for #98,
expected '\x09'after the size field,found '\x42', theBofBlocks.GNU's literal bytes, two driving values past the pads), two
Linux-gated Device-line tests with an 11-digit inode, and three
integration cases diffing the whole record against GNU for a
regular file, a directory and
/dev/null.grep '^Device:'scoping stat: GNU%t/%Tuse a Linux major/minor mask that doesn't match howdevis composed #92'stests needed; those narrower checks stay as defense in depth.
zig build testByte-level check on Linux —
diffofcat -Aoutput against/usr/bin/statis identical for/etc/passwd,/dev/nulland/tmp.Closes #92
Closes #98
🤖 Generated with Claude Code
https://claude.ai/code/session_01VapqXpB1wtGk5Cb9KeMSok