5.3.6 Resolution
Layer resolution turns several per-layer entries into one effective answer. It is the mechanism that makes the registry layered, and it is the same algorithm for path entries and for values — one resolves existence claims, the other resolves data.
5.3.6.1 The rule #
Every candidate is a tuple (precedence, sequence, entry). The winner
is the maximum, ordered by precedence first and sequence second.
Building the candidate list:
- For each entry the source returned, look up its layer in the current layer table. An entry naming a layer that is not in the table is skipped, not rejected.
- Discard entries from layers that are not active for this thread — a layer is active if it is globally enabled or its name is in the thread's private layer set (§5.3.5).
- For values, add every blanket tombstone on the key as a tombstone candidate for the requested name, at its own precedence and sequence (§5.2.7).
- If there are no candidates, the answer is not-found.
- Take the maximum. A winning HIDDEN path entry, a winning
REG_TOMBSTONEvalue entry, and a winning blanket all mean not-found.
That is the whole algorithm. Everything the layer system does — override, revert, mask, hide, hide-and-replace — is a consequence of it.
5.3.6.2 Unknown layers are latent, not wrong #
An entry tagged with a well-formed layer name that is not currently in the table is a valid latent entry. It is ignored while the layer is absent, and if a layer with the same folded identity is later created, that entry becomes eligible for resolution under the new metadata.
This is what makes restore, import and boot ordering work: source storage can legitimately hold entries before their metadata has been loaded. It also follows the core rule — sources persist entries, LCS decides their meaning.
Normal operations do not create such entries. A layer-targeting ioctl
naming a layer that is not in the table returns ENOENT. Latent
entries come from existing storage, from a restore or import, from a
previous boot, or from source behaviour. Since sources are trusted,
a well-formed latent entry is not malformed merely because its layer is
absent right now.
An entry whose layer name is malformed is a different matter, and is rejected as malformed source data.
5.3.6.3 Enumeration #
Enumerating values collects the unique names across all layers and resolves each one, returning only those whose answer is not not-found. Enumerating subkeys collects the unique child names and resolves each, returning those that map to a GUID rather than HIDDEN.
"Unique" means folded-unique. Two entries whose names differ only in case are one name, which is the only reading consistent with names being case-insensitive.
A caller sees effective state only. Tombstoned values, blanket-masked values and hidden keys are simply absent. Per-layer raw data is never visible through a normal operation.
5.3.6.4 Enumeration is index-based, and that has a cost #
REG_IOC_ENUM_VALUES and REG_IOC_ENUM_SUBKEYS return one entry at an
index. Each call re-resolves the full set and returns the entry at that
position, so walking 0..N-1 performs N full resolutions — O(n²) work
overall.
For a key with a handful of values that does not matter.
REG_IOC_QUERY_VALUES_BATCH exists for when it does: one call, the
whole effective value set, one resolution.
Enumeration order is not defined, and the index-to-entry mapping can change between calls if the effective set changes. Indices must not be cached across mutations. The batch call is also the way to get a consistent snapshot.
5.3.6.5 Neither party can lie about ordering #
Two rules stop a source manipulating the outcome.
A source-returned entry whose sequence number is greater than or equal to the next sequence LCS would allocate is malformed data. Sources store the numbers LCS assigns them; they cannot legitimately hold a future one. Without this, a compromised source could fabricate a sequence number and win every tie in its own hive. Every entry in a response is validated this way, whatever layer it names.
Duplicate sequence numbers at the same precedence, where they would actually have to be compared to pick a winner, are also malformed. LCS rejects the response rather than making an arbitrary choice. Duplicates that never get compared are not an error.
Both produce EIO and an LCS_SOURCE_VALIDATION_FAILURE audit event
(§5.4.4).