[Libguestfs] [PATCH 12/12 (NOT FOR REVIEW)] hivex: Implement adding and deleting child nodes.

Richard W.M. Jones rjones at redhat.com
Wed Feb 3 18:38:38 UTC 2010


WIP ...

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-top is 'top' for virtual machines.  Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://et.redhat.com/~rjones/virt-top
-------------- next part --------------
>From 520c38b211a35cb77d8bec98aa4d77dfb8042aad Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones at redhat.com>
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<hivex_close> 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<name> to the existing node C<parent>.
+The new child initially has no subnodes and contains no keys or
+values.  The parent must not have an existing child called C<name>, so
+if you want to overwrite an existing child, call
+C<hivex_node_delete_child> 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<node>.  All values at the node and all subnodes are
+deleted (recursively).  The C<node> 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<hive_set_value> is used in conjunction with the
-- 
1.6.5.2



More information about the Libguestfs mailing list