>From 520c38b211a35cb77d8bec98aa4d77dfb8042aad Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Wed, 3 Feb 2010 18:10:38 +0000 Subject: [PATCH 12/12] hivex: Implement adding and deleting child nodes. --- hivex/hivex.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hivex/hivex.h | 4 ++ hivex/hivex.pod | 18 +++++++ 3 files changed, 167 insertions(+), 0 deletions(-) diff --git a/hivex/hivex.c b/hivex/hivex.c index af36868..f197cd3 100644 --- a/hivex/hivex.c +++ b/hivex/hivex.c @@ -1952,6 +1952,151 @@ hivex_commit (hive_h *h, const char *filename, int flags) return 0; } +#if 0 +hive_node_h +hivex_node_add_child (hive_h *h, hive_node_h parent, const char *name) +{ + if (!h->writable) { + errno = EROFS; + return 0; + } + + if (!IS_VALID_BLOCK (h, parent) || !BLOCK_ID_EQ (h, parent, "nk")) { + errno = EINVAL; + return -1; + } + + if (name == NULL) { + errno = EINVAL; + return -1; + } + + + + + + +} +#endif + +#if 0 +/* Callback from hivex_node_delete_child which is called to delete a + * node AFTER its subnodes have been visited. The subnodes have been + * deleted but we still have to delete any lf/lh/li/ri records and the + * value list block and values, followed by deleting the node itself. + */ +static int +delete_node (hive_h *h, void *opaque, hive_node_h node, const char *name) +{ + hive_node_h *unused; + size_t *blocks; + if (get_children (h, node, &unused, &blocks) == -1) + return -1; + free (unused); + + /* We don't care what's in these intermediate blocks, so we can just + * delete them unconditionally. + */ + size_t i; + for (i = 0; blocks[i] != 0; ++i) + mark_block_unused (h, blocks[i]); + + free (blocks); + + /* Delete the values in the node. */ + if (delete_values (h, node) == -1) + return -1; + + /* XXX We should decrement the refcount. Deleting the SK is tricky + * because we don't yet know about the sk_prev and sk_next fields. + + mark_block_unused (node->sk); + */ + + /* XXX Should do this: + if (node->classname != -1) + mark_block_unused (node->classname); + */ + + /* Delete the node itself. */ + mark_block_unused (h, node); + + return 0; +} + +int +hivex_node_delete_child (hive_h *h, hive_node_h node) +{ + if (!h->writable) { + errno = EROFS; + return -1; + } + + if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) { + errno = EINVAL; + return -1; + } + + if (node == hivex_root (h)) { + if (h->msglvl >= 2) + fprintf (stderr, "hivex_node_delete_child: cannot delete root node\n"); + errno = EINVAL; + return -1; + } + + hive_node_h parent = hivex_node_parent (h, node); + if (parent == 0) + return -1; + + /* Delete node and all its children and values recursively. */ + static const struct hivex_visitor visitor = { .node_end = delete_node }; + if (hivex_visit_node (h, node, &visitor, sizeof visitor, NULL, 0) == -1) + return -1; + + /* Delete the link from parent to child. We need to find the lf/lh + * record which contains the offset and remove the offset from that + * record, then decrement the element count in that record, and + * decrement the overall number of subkeys stored in the parent + * node. + */ + hive_node_h *unused; + size_t *blocks; + if (get_children (h, parent, &unused, &blocks) == -1) + return -1; + + size_t i, j; + for (i = 0; blocks[i] != 0; ++i) { + struct ntreg_hbin_block *block = + (struct ntreg_hbin_block *) (h->addr + blocks[i]); + + if (block->id[0] == 'l' && (block->id[1] == 'f' || block->id[1] == 'h')) { + struct ntreg_lf_record *lf = (struct ntreg_lf_record *) block; + + size_t nr_subkeys_in_lf = le16toh (lf->nr_keys); + + for (j = 0; j < nr_subkeys_in_lf; ++j) + if (le32toh (lf->keys[j].offset) + 0x1000 == node) { + for (; j < nr_subkeys_in_lf - 1; ++j) + memcpy (&lf->keys[j], &lf->keys[j+1], sizeof (lf->keys[j])); + lf->nr_keys = htole16 (nr_subkeys_in_lf - 1); + goto found; + } + } + } + if (h->msglvl >= 2) + fprintf (stderr, "hivex_node_delete_child: could not find parent to child link\n"); + errno = ENOTSUP; + return -1; + + found:; + struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node); + size_t nr_subkeys_in_nk = le32toh (nk->nr_subkeys); + nk->nr_subkeys = htole32 (nr_subkeys_in_nk - 1); + + return 0; +} +#endif + int hivex_node_set_values (hive_h *h, hive_node_h node, size_t nr_values, const hive_set_value *values, diff --git a/hivex/hivex.h b/hivex/hivex.h index 6a3cb3a..296a1a5 100644 --- a/hivex/hivex.h +++ b/hivex/hivex.h @@ -111,6 +111,10 @@ extern int hivex_visit (hive_h *h, const struct hivex_visitor *visitor, size_t l extern int hivex_visit_node (hive_h *h, hive_node_h node, const struct hivex_visitor *visitor, size_t len, void *opaque, int flags); extern int hivex_commit (hive_h *h, const char *filename, int flags); +#if 0 +extern hive_node_h hivex_node_add_child (hive_h *h, hive_node_h parent, const char *name); +extern int hivex_node_delete_child (hive_h *h, hive_node_h node); +#endif struct hive_set_value { char *key; diff --git a/hivex/hivex.pod b/hivex/hivex.pod index 5df75aa..34ff253 100644 --- a/hivex/hivex.pod +++ b/hivex/hivex.pod @@ -379,6 +379,24 @@ operations on the hive after committing, including making more modifications. If you no longer wish to use the hive, call C after this. +=item hive_node_h hivex_node_add_child (hive_h *h, hive_node_h parent, const char *name); + +Add a new child node named C to the existing node C. +The new child initially has no subnodes and contains no keys or +values. The parent must not have an existing child called C, so +if you want to overwrite an existing child, call +C first. + +Returns the node handle. On error this returns 0 and sets errno. + +=item int hivex_node_delete_child (hive_h *h, hive_node_h node); + +Delete the node C. All values at the node and all subnodes are +deleted (recursively). The C handle and the handles of all +subnodes become invalid. You cannot delete the root node. + +Returns 0 on success. On error this returns -1 and sets errno. + =item hive_set_value The typedef C is used in conjunction with the -- 1.6.5.2