3.2 Persistent Tables

Each hive is one SQLite database, and every hive database has the same four data tables. loregd creates them on first boot (§2.2, step 4).

The tables hold what the kernel gives loregd and nothing derived from it. Security descriptors are stored as opaque blobs, GUIDs and sequence numbers are assigned by the kernel, and no table records a resolved or filtered view of anything.

3.2.1 keys #

CREATE TABLE keys (
    guid           BLOB NOT NULL PRIMARY KEY,
    name           TEXT NOT NULL,
    name_folded    TEXT NOT NULL,
    parent_guid    BLOB,
    sd             BLOB NOT NULL,
    volatile       INTEGER NOT NULL DEFAULT 0,
    symlink        INTEGER NOT NULL DEFAULT 0,
    last_write_time INTEGER NOT NULL
);
ColumnMeaning
guidThe 16-byte key GUID assigned by the kernel. Primary key.
nameThe key's own name component, with case preserved as written.
name_foldedThe folded form of name (§3.4), used for case-insensitive lookup.
parent_guidThe parent key's GUID; null for the hive root, which is how the root is identified.
sdThe security descriptor, in binary self-relative form. Opaque to loregd.
volatile1 for a volatile key, 0 for a persistent one. In this table it is always 0 — volatile keys live in the volatile database (§3.3).
symlink1 if the key is a symbolic link.
last_write_timeUnix nanoseconds.

3.2.2 path_entries #

CREATE TABLE path_entries (
    parent_guid       BLOB NOT NULL,
    child_name        TEXT NOT NULL,
    child_name_folded TEXT NOT NULL,
    layer             TEXT NOT NULL,
    target_type       INTEGER NOT NULL,
    target_guid       BLOB,
    sequence          INTEGER NOT NULL,
    PRIMARY KEY (parent_guid, child_name_folded, layer)
);

CREATE INDEX idx_path_entries_target
    ON path_entries (target_guid)
    WHERE target_type = 0;

A path entry is one layer's opinion about one child name under one parent. Several layers may hold entries for the same name; resolving between them is the kernel's job, not loregd's.

ColumnMeaning
parent_guidThe parent key's GUID.
child_nameThe child name with case preserved.
child_name_foldedThe folded form, which is what the primary key uses — so a name collides case-insensitively within a layer.
layerThe layer name. Compared as binary, so layer names are case-sensitive, unlike key names.
target_type0 for a GUID entry (the key exists in this layer), 1 for HIDDEN (a tombstone masking lower layers).
target_guidThe target key's GUID when target_type is 0; null for HIDDEN.
sequenceThe kernel-assigned sequence number.

The partial index on target_guid covers only non-HIDDEN rows. It is what makes the reverse lookup — which path entries point at this key — cheap, and that reverse lookup is what orphan detection (§2.2, step 6) and RSI_DROP_KEY need.

3.2.3 values #

CREATE TABLE [values] (
    key_guid       BLOB NOT NULL,
    name           TEXT NOT NULL,
    name_folded    TEXT NOT NULL,
    layer          TEXT NOT NULL,
    type           INTEGER NOT NULL,
    data           BLOB,
    sequence       INTEGER NOT NULL,
    PRIMARY KEY (key_guid, name_folded, layer)
);
ColumnMeaning
key_guidThe key this value belongs to.
nameThe value name, case preserved. The empty string is the key's default value.
name_foldedThe folded form; also the empty string for the default value.
layerThe layer this value entry belongs to.
typeThe registry value type — REG_SZ is 1, REG_DWORD is 4, and so on. REG_TOMBSTONE (0xFFFF) marks a per-value tombstone.
dataThe value payload; null for a tombstone.
sequenceThe kernel-assigned sequence number.

values is a reserved word in SQL, so every reference to this table is quoted — [values], or main.[values] and volatile.[values] when the schema is named explicitly. Unquoted, it is a syntax error.

3.2.4 blanket_tombstones #

CREATE TABLE blanket_tombstones (
    key_guid       BLOB NOT NULL,
    layer          TEXT NOT NULL,
    sequence       INTEGER NOT NULL,
    PRIMARY KEY (key_guid, layer)
);

A blanket tombstone hides every value a key holds in the layers beneath it, rather than naming one value the way a REG_TOMBSTONE entry does. One row per key per layer.

Edit this page