Skip to content

feat(#83): read member content from an archive container - #457

Merged
helly25 merged 4 commits into
mainfrom
feat/83-read-member-content
Aug 11, 2026
Merged

feat(#83): read member content from an archive container#457
helly25 merged 4 commits into
mainfrom
feat/83-read-member-content

Conversation

@helly25

@helly25 helly25 commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Adds ReadMemberOfFile(path, member, max_bytes) to the archive reader - the entry point the content-side predicates need, so -grep, -content and {hash} can eventually see inside a container instead of only listing it.

Design points, each pinned by a test:

  • Streaming, single pass, stopping at the match, so reading an early member of a huge archive never decompresses the rest. kBlockSize moves from a function-local constant into the file-scope anonymous namespace, shared with ListMembersOfFile.
  • Member names are matched normalized: a leading ./ is ignored on either side, and so is a trailing /. Tar writes the same member several ways (dir/x vs ./dir/x, and a directory as dir/), so neither spelling can be authoritative. The trailing-slash half matters for the error contract: a lookup for dir now FINDS the directory and reports "no content" rather than misreporting "no such member".
  • Every failure is a distinct status, because a caller has to tell them apart: NotFound (no such member), FailedPrecondition (member has no content, e.g. a directory), InvalidArgument (not an archive at all), DataLoss (broken archive) and ResourceExhausted (bomb guard).
  • The bomb guard bounds the read loop, not the declared size: a small header can promise a huge expansion, so the header size is used only to reserve. max_bytes is inclusive - content exactly at the limit is fine.

The test fixture gains WriteArchive / WriteArchiveWithDirectory, since the existing MakeArchive is in-memory while this entry point streams from a path.

Part of #83. Not armed for auto-merge; queued behind #450 / #455 / #456.

helly25 and others added 3 commits August 11, 2026 01:42
Adds `ReadMemberOfFile(path, member, max_bytes)` to the archive reader - the
entry point the content-side predicates need, so `-grep`, `-content` and
`{hash}` can eventually see inside a container instead of only listing it.

Design points, each pinned by a test:

- Streaming, single pass, stopping at the match, so reading an early member of
  a huge archive never decompresses the rest. `kBlockSize` moves from a
  function-local constant into the file-scope anonymous namespace, shared with
  `ListMembersOfFile`.
- Member names are matched NORMALIZED: a leading `./` is ignored on either
  side, and so is a trailing `/`. Tar writes the same member several ways
  (`dir/x` vs `./dir/x`, and a directory as `dir/`), so neither spelling can be
  authoritative. The trailing-slash half matters for the error contract: a
  lookup for `dir` now FINDS the directory and reports "no content" rather than
  misreporting "no such member".
- Every failure is a distinct status, because a caller has to tell them apart:
  `NotFound` (no such member), `FailedPrecondition` (member has no content,
  e.g. a directory), `InvalidArgument` (not an archive at all), `DataLoss`
  (broken archive) and `ResourceExhausted` (bomb guard).
- The bomb guard bounds the READ LOOP, not the declared size: a small header
  can promise a huge expansion, so the header size is used only to `reserve`.
  `max_bytes` is inclusive - content exactly at the limit is fine.

The test fixture gains `WriteArchive` / `WriteArchiveWithDirectory`, since the
existing `MakeArchive` is in-memory while this entry point streams from a path.
@helly25
helly25 merged commit 8ee5d15 into main Aug 11, 2026
11 checks passed
@helly25
helly25 deleted the feat/83-read-member-content branch August 11, 2026 01:30
helly25 added a commit that referenced this pull request Aug 11, 2026
Conflict: #455 (archive VFS backend) and this branch each appended targets to
extra_modules/archive/BUILD.bazel. Both sets are kept.

Also does what this PR promised once #457 landed: `archive_reader.cc` drops its
local copy of the member-name normalization and uses the shared
`NormalizeMemberName` from the member-path library, so the rule exists once for
both readers rather than being duplicated on main.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant