read: of two links with one name, the first wins everywhere

A valid group has one link per name, but a damaged or hand-made one can
have two. resolve_child followed the first soft link of the name, the
listing skipped a dangling one and listed the name via a later link, and
path resolution followed the last symbolic link: three answers. All now
take the first link of the name (header message order in a compact group,
name index order in a dense one) and ignore the rest, even if the first
dangles. That is libhdf5's rule for compact groups (H5G__compact_lookup
stops at the first Link message); h5py opens nothing for a dangling first
link although a later one resolves. For a dense group libhdf5
binary-searches the index and may land on another of several exact
duplicates; documented on first_link_named. find_symbolic_link's v2 branch
was dead (only v1 groups reach it) and is now v1-only.

Test: an h5py compact group with soft links dup_A (dangling, or to /d) and
dup_B (the other), dup_B renamed to dup_A in the header and re-checksummed.
Lookup, path and listing through all three readers match h5py for both
orders. With the old group_v2.rs the path lookup returned 42 where h5py
opens nothing.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
osobh
2026-09-26 14:11:47 -05:00
co-authored by Claude Opus 5.5
parent 5b3d32b37d
commit 04a7f6f6c7
3 changed files with 211 additions and 68 deletions
+10
View File
@@ -19,6 +19,16 @@
types): one attribute, found in dense storage through its name index
(record type 8) instead of reading every attribute
(`clawhdf5_format::attribute::find_attribute_in_file`).
- **Two links of one name: the first wins everywhere.** A group cannot
validly hold two links of one name, but a damaged or hand-made one can.
The listing, `resolve_child` (`Group::dataset`/`group`) and path
resolution now all use only the first link of a name (header message
order in a compact group, name index order in a dense one) and ignore
the rest, even if the first dangles — libhdf5's rule for compact groups
(h5py fails to open a dangling first link although a later one
resolves). Before, the listing skipped a dangling first link and listed
the name via a later one that lookup did not follow, and path resolution
followed the last.
- **`Group::entries()` and `File::group_at(address)`**: a listing's
`(name, address)` pairs, to open children without looking names up again.
- Test: `crates/clawhdf5/tests/indexed_lookup_interop.rs` — every child of