format, clawhdf5: cut every Storage read to the range asked for

ExtentBytes and read_exact_at/read_upto rejected short results but passed
longer-than-asked ones through, and FileData forwarded them too, so a
Storage that broke read_at's contract by returning extra bytes had them
decoded or returned as data (a contiguous dataset read gained 37 junk
bytes). gather_storage alone trimmed.

- storage::exact_len (new, pub): a read of len bytes as exactly len — cut
  when longer, an error when short. read_exact_at, read_upto and
  ExtentBytes (so chunk fetches and selection gathers) go through it.
- FileData cuts a backend's answer to what it asked for before laying the
  cache image over it.
- Tests: over a storage that appends 37 junk bytes to every read, every
  format-crate fixture reads exactly as from the slice
  (overlong_reads_are_cut_to_the_range_asked_for), and every facade
  fixture opens and reads through File::open_storage as through File::open
  (overlong_storage_reads_identically). Both failed before.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
osobh
2026-09-26 18:43:05 -05:00
co-authored by Claude Opus 5.5
parent 89e7977943
commit 6185874f9c
5 changed files with 225 additions and 90 deletions
+4
View File
@@ -69,6 +69,10 @@
- Each extent's bounds error is the one the slice readers gave, reported
when the read reaches that extent, so a damaged file fails with the
same error, in the same order, through either path.
- A backend that answers a read with more bytes than asked (breaking
`read_at`'s contract) never has the extra bytes used: every read is
cut to the range asked for (`storage::exact_len`), and a short answer
inside the file is an error.
- **No behaviour change for in-memory and mapped files:** with
`as_contiguous()` every path slices the file as before (checked below).
- Tests (2026-09-26, tank):