4.4 Operations

Eighteen operations. Every one that returns layer-qualified data MUST return all entries across all layers: a source MUST NOT pre-filter, resolve, or omit. The kernel decides what is effective.

Every response payload begins with a u32 status. Payload fields below are listed after it, in wire order, with no padding between them. "Status only" means the payload is the status and nothing else — 18 bytes in total.

OperationCodeResponse
RSI_LOOKUP0x00010x8001
RSI_CREATE_ENTRY0x00020x8002
RSI_HIDE_ENTRY0x00030x8003
RSI_DELETE_ENTRY0x00040x8004
RSI_ENUM_CHILDREN0x00050x8005
RSI_CREATE_KEY0x00100x8010
RSI_READ_KEY0x00110x8011
RSI_WRITE_KEY0x00120x8012
RSI_DROP_KEY0x00130x8013
RSI_QUERY_VALUES0x00200x8020
RSI_SET_VALUE0x00210x8021
RSI_DELETE_VALUE_ENTRY0x00220x8022
RSI_SET_BLANKET_TOMBSTONE0x00230x8023
RSI_BEGIN_TRANSACTION0x00300x8030
RSI_COMMIT_TRANSACTION0x00310x8031
RSI_ABORT_TRANSACTION0x00320x8032
RSI_FLUSH0x00400x8040
RSI_DELETE_LAYER0x00500x8050

Any other operation code is invalid.

4.4.1 Path operations #

4.4.1.1 RSI_LOOKUP #

Look up a child entry under a parent key. This is the path-walking primitive; the kernel issues one per path component.

Request: parent_guid (16), child_name (length-prefixed).

Response: entry_count (u32), then that many path entries:

SizeField
4+nlayer_name
1target_type: 0 = GUID, 1 = HIDDEN
16target_guid
8sequence

then metadata_count (u32), then that many key metadata entries:

SizeField
16guid
4+nsd, binary
1volatile
1symlink
8last_write_time

An empty response — entry_count zero — means the child does not exist in any layer. That is an ordinary answer, not an error.

The metadata block is deduplicated: exactly one entry per distinct GUID referenced by the path entries. A source MUST satisfy all of:

  • every GUID appearing as a target has exactly one metadata entry;
  • no metadata entry is duplicated;
  • no metadata entry is unreferenced;
  • no metadata GUID is all-zero;
  • a HIDDEN entry MUST carry an all-zero target_guid and MUST NOT contribute a metadata entry.

Violating any of these is malformed data.

The kernel resolves symlink targets itself, by issuing a separate RSI_QUERY_VALUES for the key's default value. A source MUST NOT interpret the symlink flag or follow anything.

4.4.1.2 RSI_CREATE_ENTRY #

Create a path entry (parent, child_name, layer) → guid.

Request: parent_guid (16), child_name, layer_name, child_guid (16), sequence (u64).

Response: status only.

Always paired with RSI_CREATE_KEY, which carries the same GUID. The kernel sends RSI_CREATE_ENTRY first, so that a losing race is detected before a key record is created: an RSI_ALREADY_EXISTS here means another writer got the name.

4.4.1.3 RSI_HIDE_ENTRY #

Create a HIDDEN path entry at (parent, child_name, layer).

Request: parent_guid (16), child_name, layer_name, sequence (u64).

Response: status only.

4.4.1.4 RSI_DELETE_ENTRY #

Remove the path entry at (parent, child_name, layer), whether it was a GUID entry or a HIDDEN one.

Request: parent_guid (16), child_name, layer_name.

Response: status only.

4.4.1.5 RSI_ENUM_CHILDREN #

Enumerate every child entry under a parent, across all layers.

Request: parent_guid (16).

Response: child_count (u32), then per child:

SizeField
4+nchild_name
4entry_count
that many path entries, in the RSI_LOOKUP entry format

followed by one metadata block, in the RSI_LOOKUP metadata format, covering the distinct GUIDs across all children. Emitting it once rather than per child is what makes this cheaper than a lookup per name.

The same deduplication and closure rules apply, evaluated across the whole response.

4.4.2 Key operations #

4.4.2.1 RSI_CREATE_KEY #

Create a key record. The GUID is assigned by the kernel.

Request: guid (16), name, parent_guid (16), sd (binary, length-prefixed), volatile (1), symlink (1).

Response: status only.

The path entry linking the key into the namespace is created separately by RSI_CREATE_ENTRY. For a symlink key, the target is written afterwards as a default REG_LINK value through RSI_SET_VALUE.

A source MUST persist the GUID exactly as given: no rewriting, no remapping, no reassignment. GUIDs are the kernel's identity for keys and the source's primary key for storage.

4.4.2.2 RSI_READ_KEY #

Request: guid (16).

Response: name, parent_guid (16), sd, volatile (1), symlink (1), last_write_time (i64).

4.4.2.3 RSI_WRITE_KEY #

Update a key's mutable fields.

Request: guid (16), field_mask (u32), then the named fields in bit order.

BitFieldEncoding
0sdlength-prefixed
1last_write_timei64

Only fields whose bit is set are present. Any other bit set in field_mask is invalid.

Response: status only.

There is no way to express a change to the GUID, the volatile flag or the symlink flag: those fields are simply absent from the request. A source MUST reject a request attempting to modify an immutable field with RSI_INVALID.

A field_mask of zero is a well-formed existence check that mutates nothing.

4.4.2.4 RSI_DROP_KEY #

Purge everything associated with a GUID: the key record, all value entries across all layers, all path entries, and all blanket tombstones.

Request: guid (16).

Response: status only.

RSI_DROP_KEY MUST be idempotent. If the GUID does not exist — already purged by startup cleanup, say — the source MUST return RSI_OK.

The kernel issues this when the last descriptor to an unnamed key closes, and it issues it without a waiting caller. A source MUST answer it like any other request.

4.4.3 Value operations #

4.4.3.1 RSI_QUERY_VALUES #

Retrieve every layer entry for one value, or for all values on a key.

Request: guid (16), value_name, query_all (1). When query_all is set the value name is empty and every value on the key is returned.

Response: entry_count (u32), then per entry:

SizeField
4+nvalue_name
4+nlayer_name
4type
4+ndata, binary
8sequence

then blanket_count (u32), then per blanket tombstone:

SizeField
4+nlayer_name
8sequence

The blanket list is part of every response, including one for a single named value: the kernel needs it to resolve that name.

A tombstone entry carries type REG_TOMBSTONE (0xFFFF) and zero-length data. A source MUST NOT return a tombstone with data, an undefined value type, or data exceeding the configured maximum value size.

4.4.3.2 RSI_SET_VALUE #

Store a value entry at (guid, value_name, layer), replacing any existing entry for that triple.

Request: guid (16), value_name, layer_name, type (u32), data, sequence (u64), expected_sequence (u64).

Response: status only.

Conditional writes. A source MUST support expected_sequence. Zero means unconditional. Non-zero means the source MUST atomically verify that the current entry at (guid, value_name, layer) carries that sequence number before writing, and MUST return RSI_CAS_FAILED without writing if it does not match or if no entry exists.

The condition is against the layer's own entry, not against any resolved value. A source does not know what is effective and MUST NOT try to work it out.

4.4.3.3 RSI_DELETE_VALUE_ENTRY #

Remove the entry at (guid, value_name, layer), whether it was a value or a tombstone.

Request: guid (16), value_name, layer_name.

Response: status only.

This operation MUST be idempotent: a source MUST return RSI_OK when there was no entry to remove. The kernel does not mask RSI_NOT_FOUND here, so a source returning it makes the caller's delete fail.

4.4.3.4 RSI_SET_BLANKET_TOMBSTONE #

Set or remove a blanket tombstone on (guid, layer).

Request: guid (16), layer_name, set (1), sequence (u64).

Response: status only.

4.4.4 Transaction operations #

4.4.4.1 RSI_BEGIN_TRANSACTION #

Request: txn_id (u64), mode (u32).

The transaction id appears in the payload. The request header's own txn_id is zero for this operation, since the transaction does not yet exist. RSI_COMMIT_TRANSACTION and RSI_ABORT_TRANSACTION carry it in both places.

ModeValueMeaning
RSI_TXN_READ_WRITE0An ordinary transaction.
RSI_TXN_READ_ONLY1A point-in-time read snapshot.

Response: status only.

For RSI_TXN_READ_WRITE, reads tagged with the id MUST observe the transaction's own uncommitted writes, and writes tagged with it MUST be committed atomically by RSI_COMMIT_TRANSACTION.

For RSI_TXN_READ_ONLY, reads tagged with the id MUST observe a stable point-in-time snapshot. The kernel MUST NOT send a mutating operation with a read-only transaction id, and a source that receives one MUST reject it with RSI_INVALID and MUST NOT mutate anything. A read-only transaction is released with RSI_ABORT_TRANSACTION; the kernel MUST NOT send RSI_COMMIT_TRANSACTION for one.

A source whose store cannot support a mode MAY answer RSI_TXN_NOT_SUPPORTED for that mode. The two are independent: a source MAY support read-only snapshots without supporting read-write transactions.

4.4.4.2 RSI_COMMIT_TRANSACTION #

Request: txn_id (u64).

Response: status only.

On success every change in the transaction MUST be durable. On failure every change MUST be rolled back.

4.4.4.3 RSI_ABORT_TRANSACTION #

Request: txn_id (u64).

Response: status only.

Sent when a transaction is closed without committing, on timeout, and to release a read-only snapshot. The kernel MAY send it without a waiting caller.

4.4.5 Layer operations #

4.4.5.1 RSI_DELETE_LAYER #

Remove everything tagged with a layer name.

Request: layer_name.

Response: orphaned_guid_count (u32), then that many GUIDs (16 each).

The source MUST atomically remove all path entries, all value entries and all blanket tombstones whose layer is layer_name, and MUST NOT remove any key record. Orphan cleanup is the kernel's, through RSI_DROP_KEY.

orphaned_guids MUST list exactly the GUIDs that lost their last path entry as a result, with no nil GUID and no duplicates. The kernel tracks them for deferred deletion.

An unknown layer name is not an error. A source with no entries for it MUST return RSI_OK with an empty orphan list — a layer may have entries in one source and none in another.

4.4.6 Maintenance #

4.4.6.1 RSI_FLUSH #

Persist pending writes for one hive to durable storage.

Request: hive_name.

Response: status only, returned when persistence is confirmed.

This is the only operation that identifies its target by hive name rather than by GUID, because flushing is a hive-level act — a WAL checkpoint, say — not a key-level one.

Edit this page