[Libguestfs] [PATCH 2/4] New APIs: hivex_*

Richard W.M. Jones rjones at redhat.com
Wed Aug 29 15:15:33 UTC 2012


From: "Richard W.M. Jones" <rjones at redhat.com>

Transscribe many hivex(3) APIs into the libguestfs API.

There is one hive handle per libguestfs handle, as with Augeas.

Note that hivex uses iconv_open for some APIs (eg. hivex_value_string).
But since we delete all the i18n files from the appliance, this
doesn't work -- iconv_open returns EINVAL.  Therefore hivex APIs which
require iconv cannot be bound in the daemon.
---
 appliance/packagelist.in                 |    3 +
 daemon/Makefile.am                       |    7 +-
 daemon/hivex.c                           |  509 ++++++++++++++++++++++++++++++
 generator/generator_actions.ml           |  187 +++++++++++
 generator/generator_structs.ml           |   14 +
 gobject/Makefile.inc                     |   10 +-
 java/Makefile.inc                        |    2 +
 java/com/redhat/et/libguestfs/.gitignore |    2 +
 po/POTFILES                              |    4 +
 src/MAX_PROC_NR                          |    2 +-
 src/guestfs.pod                          |   15 +-
 11 files changed, 745 insertions(+), 10 deletions(-)
 create mode 100644 daemon/hivex.c

diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index 4830962..6d412cb 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -30,6 +30,7 @@
   gfs2-utils
   grub
   hfsplus-tools
+  hivex
   iputils
   kernel
   MAKEDEV
@@ -57,6 +58,7 @@
   hfsplus
   iproute
   libaugeas0
+  libhivex0
   linux-image
   nilfs-tools
   ntfs-3g
@@ -76,6 +78,7 @@
   btrfs-progs-unstable
   cryptsetup
   augeas
+  hivex
   zfs-fuse
   e2fsprogs
   grub
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 9ea6ce3..ffd8b81 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -121,6 +121,7 @@ guestfsd_SOURCES = \
 	guestfsd.c \
 	headtail.c \
 	hexdump.c \
+	hivex.c \
 	htonl.c \
 	initrd.c \
 	inotify.c \
@@ -176,6 +177,7 @@ guestfsd_LDADD = \
 	libprotocol.a \
 	$(SELINUX_LIB) \
 	$(AUGEAS_LIBS) \
+	$(HIVEX_LIBS) \
 	$(top_builddir)/gnulib/lib/.libs/libgnu.a \
 	$(GETADDRINFO_LIB) \
 	$(HOSTENT_LIB) \
@@ -186,6 +188,9 @@ guestfsd_LDADD = \
 	$(SERVENT_LIB)
 
 guestfsd_CPPFLAGS = -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib
-guestfsd_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) $(AUGEAS_CFLAGS)
+guestfsd_CFLAGS = \
+	$(WARN_CFLAGS) $(WERROR_CFLAGS) \
+	$(AUGEAS_CFLAGS) \
+	$(HIVEX_CFLAGS)
 
 .PHONY: force
diff --git a/daemon/hivex.c b/daemon/hivex.c
new file mode 100644
index 0000000..f13d3d7
--- /dev/null
+++ b/daemon/hivex.c
@@ -0,0 +1,509 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "guestfs_protocol.h"
+#include "daemon.h"
+#include "actions.h"
+#include "optgroups.h"
+
+#ifdef HAVE_HIVEX
+
+#include <hivex.h>
+
+int
+optgroup_hivex_available (void)
+{
+  return 1;
+}
+
+/* The hivex handle.  As with Augeas, there is one per guestfs handle /
+ * daemon.
+ */
+static hive_h *h = NULL;
+
+/* Clean up the hivex handle on daemon exit. */
+static void hivex_finalize (void) __attribute__((destructor));
+static void
+hivex_finalize (void)
+{
+  if (h) {
+    hivex_close (h);
+    h = NULL;
+  }
+}
+
+#define NEED_HANDLE(errcode)						\
+  do {									\
+    if (!h) {								\
+      reply_with_error ("%s: you must call 'hivex-open' first to initialize the hivex handle", __func__); \
+      return (errcode);							\
+    }									\
+  }									\
+  while (0)
+
+/* Takes optional arguments, consult optargs_bitmask. */
+int
+do_hivex_open (const char *filename, int verbose, int debug, int write)
+{
+  char *buf;
+  int flags = 0;
+
+  if (h) {
+    hivex_close (h);
+    h = NULL;
+  }
+
+  buf = sysroot_path (filename);
+  if (!buf) {
+    reply_with_perror ("malloc");
+    return -1;
+  }
+
+  if (optargs_bitmask & GUESTFS_HIVEX_OPEN_VERBOSE_BITMASK) {
+    if (verbose)
+      flags |= HIVEX_OPEN_VERBOSE;
+  }
+  if (optargs_bitmask & GUESTFS_HIVEX_OPEN_DEBUG_BITMASK) {
+    if (debug)
+      flags |= HIVEX_OPEN_DEBUG;
+  }
+  if (optargs_bitmask & GUESTFS_HIVEX_OPEN_WRITE_BITMASK) {
+    if (write)
+      flags |= HIVEX_OPEN_WRITE;
+  }
+
+  h = hivex_open (buf, flags);
+  if (!h) {
+    reply_with_perror ("hivex failed to open %s", filename);
+    free (buf);
+    return -1;
+  }
+
+  free (buf);
+  return 0;
+}
+
+int
+do_hivex_close (void)
+{
+  NEED_HANDLE (-1);
+
+  hivex_close (h);
+  h = NULL;
+
+  return 0;
+}
+
+int64_t
+do_hivex_root (void)
+{
+  int64_t r;
+
+  NEED_HANDLE (-1);
+
+  r = hivex_root (h);
+  if (r == 0) {
+    reply_with_perror ("failed");
+    return -1;
+  }
+
+  return r;
+}
+
+char *
+do_hivex_node_name (int64_t nodeh)
+{
+  char *r;
+
+  NEED_HANDLE (NULL);
+
+  r = hivex_node_name (h, nodeh);
+  if (r == NULL) {
+    reply_with_perror ("failed");
+    return NULL;
+  }
+
+  return r;
+}
+
+guestfs_int_hivex_node_list *
+do_hivex_node_children (int64_t nodeh)
+{
+  guestfs_int_hivex_node_list *ret;
+  hive_node_h *r;
+  size_t i, len;
+
+  NEED_HANDLE (NULL);
+
+  r = hivex_node_children (h, nodeh);
+  if (r == NULL) {
+    reply_with_perror ("failed");
+    return NULL;
+  }
+
+  len = 0;
+  for (i = 0; r[i] != 0; ++i)
+    len++;
+
+  ret = malloc (sizeof *ret);
+  if (!ret) {
+    reply_with_perror ("malloc");
+    free (r);
+    return NULL;
+  }
+
+  ret->guestfs_int_hivex_node_list_len = len;
+  ret->guestfs_int_hivex_node_list_val =
+    malloc (len * sizeof (guestfs_int_hivex_node));
+  if (ret->guestfs_int_hivex_node_list_val == NULL) {
+    reply_with_perror ("malloc");
+    free (ret);
+    free (r);
+    return NULL;
+  }
+
+  for (i = 0; i < len; ++i)
+    ret->guestfs_int_hivex_node_list_val[i].hivex_node_h = r[i];
+
+  free (r);
+
+  return ret;
+}
+
+int64_t
+do_hivex_node_get_child (int64_t nodeh, const char *name)
+{
+  int64_t r;
+
+  NEED_HANDLE (-1);
+
+  errno = 0;
+  r = hivex_node_get_child (h, nodeh, name);
+  if (r == 0 && errno != 0) {
+    reply_with_perror ("failed");
+    return -1;
+  }
+
+  return r;
+}
+
+int64_t
+do_hivex_node_parent (int64_t nodeh)
+{
+  int64_t r;
+
+  NEED_HANDLE (-1);
+
+  r = hivex_node_parent (h, nodeh);
+  if (r == 0) {
+    reply_with_perror ("failed");
+    return -1;
+  }
+
+  return r;
+}
+
+guestfs_int_hivex_value_list *
+do_hivex_node_values (int64_t nodeh)
+{
+  guestfs_int_hivex_value_list *ret;
+  hive_value_h *r;
+  size_t i, len;
+
+  NEED_HANDLE (NULL);
+
+  r = hivex_node_values (h, nodeh);
+  if (r == NULL) {
+    reply_with_perror ("failed");
+    return NULL;
+  }
+
+  len = 0;
+  for (i = 0; r[i] != 0; ++i)
+    len++;
+
+  ret = malloc (sizeof *ret);
+  if (!ret) {
+    reply_with_perror ("malloc");
+    free (r);
+    return NULL;
+  }
+
+  ret->guestfs_int_hivex_value_list_len = len;
+  ret->guestfs_int_hivex_value_list_val =
+    malloc (len * sizeof (guestfs_int_hivex_value));
+  if (ret->guestfs_int_hivex_value_list_val == NULL) {
+    reply_with_perror ("malloc");
+    free (ret);
+    free (r);
+    return NULL;
+  }
+
+  for (i = 0; i < len; ++i)
+    ret->guestfs_int_hivex_value_list_val[i].hivex_value_h = (int64_t) r[i];
+
+  free (r);
+
+  return ret;
+}
+
+int64_t
+do_hivex_node_get_value (int64_t nodeh, const char *key)
+{
+  int64_t r;
+
+  NEED_HANDLE (-1);
+
+  errno = 0;
+  r = hivex_node_get_value (h, nodeh, key);
+  if (r == 0 && errno != 0) {
+    reply_with_perror ("failed");
+    return -1;
+  }
+
+  return r;
+}
+
+char *
+do_hivex_value_key (int64_t valueh)
+{
+  char *r;
+
+  NEED_HANDLE (NULL);
+
+  r = hivex_value_key (h, valueh);
+  if (r == NULL) {
+    reply_with_perror ("failed");
+    return NULL;
+  }
+
+  return r;
+}
+
+int64_t
+do_hivex_value_type (int64_t valueh)
+{
+  hive_type r;
+
+  NEED_HANDLE (-1);
+
+  if (hivex_value_type (h, valueh, &r, NULL) == -1) {
+    reply_with_perror ("failed");
+    return -1;
+  }
+
+  return r;
+}
+
+char *
+do_hivex_value_value (int64_t valueh, size_t *size_r)
+{
+  char *r;
+  size_t size;
+
+  NEED_HANDLE (NULL);
+
+  r = hivex_value_value (h, valueh, NULL, &size);
+  if (r == NULL) {
+    reply_with_perror ("failed");
+    return NULL;
+  }
+
+  *size_r = size;
+  return r;
+}
+
+int
+do_hivex_commit (const char *filename)
+{
+  NEED_HANDLE (-1);
+
+  if (hivex_commit (h, filename, 0) == -1) {
+    reply_with_perror ("failed");
+    return -1;
+  }
+
+  return 0;
+}
+
+int64_t
+do_hivex_node_add_child (int64_t parent, const char *name)
+{
+  int64_t r;
+
+  NEED_HANDLE (-1);
+
+  r = hivex_node_add_child (h, parent, name);
+  if (r == 0) {
+    reply_with_perror ("failed");
+    return -1;
+  }
+
+  return r;
+}
+
+int
+do_hivex_node_delete_child (int64_t nodeh)
+{
+  NEED_HANDLE (-1);
+
+  if (hivex_node_delete_child (h, nodeh) == -1) {
+    reply_with_perror ("failed");
+    return -1;
+  }
+
+  return 0;
+}
+
+int
+do_hivex_node_set_value (int64_t nodeh,
+                         const char *key, int64_t t,
+                         const char *val, size_t val_size)
+{
+  const hive_set_value v =
+    { .key = (char *) key, .t = t, .len = val_size, .value = (char *) val };
+
+  NEED_HANDLE (-1);
+
+  if (hivex_node_set_value (h, nodeh, &v, 0) == -1) {
+    reply_with_perror ("failed");
+    return -1;
+  }
+
+  return 0;
+}
+
+#else /* !HAVE_HIVEX */
+
+/* Note that the wrapper code (daemon/stubs.c) ensures that the
+ * functions below are never called because optgroup_hivex_available
+ * returns false.
+ */
+int
+optgroup_hivex_available (void)
+{
+  return 0;
+}
+
+int __attribute__((noreturn))
+do_hivex_open (const char *filename, int verbose, int debug, int write)
+{
+  abort ();
+}
+
+int __attribute__((noreturn))
+do_hivex_close (void)
+{
+  abort ();
+}
+
+int64_t __attribute__((noreturn))
+do_hivex_root (void)
+{
+  abort ();
+}
+
+char * __attribute__((noreturn))
+do_hivex_node_name (int64_t nodeh)
+{
+  abort ();
+}
+
+guestfs_int_hivex_node_list * __attribute__((noreturn))
+do_hivex_node_children (int64_t nodeh)
+{
+  abort ();
+}
+
+int64_t __attribute__((noreturn))
+do_hivex_node_get_child (int64_t nodeh, const char *name)
+{
+  abort ();
+}
+
+int64_t __attribute__((noreturn))
+do_hivex_node_parent (int64_t nodeh)
+{
+  abort ();
+}
+
+guestfs_int_hivex_value_list * __attribute__((noreturn))
+do_hivex_node_values (int64_t nodeh)
+{
+  abort ();
+}
+
+int64_t __attribute__((noreturn))
+do_hivex_node_get_value (int64_t nodeh, const char *key)
+{
+  abort ();
+}
+
+char * __attribute__((noreturn))
+do_hivex_value_key (int64_t valueh)
+{
+  abort ();
+}
+
+int64_t __attribute__((noreturn))
+do_hivex_value_type (int64_t valueh)
+{
+  abort ();
+}
+
+char * __attribute__((noreturn))
+do_hivex_value_value (int64_t valueh, size_t *size_r)
+{
+  abort ();
+}
+
+int __attribute__((noreturn))
+do_hivex_commit (const char *filename)
+{
+  abort ();
+}
+
+int64_t __attribute__((noreturn))
+do_hivex_node_add_child (int64_t parent, const char *name)
+{
+  abort ();
+}
+
+int __attribute__((noreturn))
+do_hivex_node_delete_child (int64_t nodeh)
+{
+  abort ();
+}
+
+int __attribute__((noreturn))
+do_hivex_node_set_value (int64_t nodeh, const char *key, int64_t t, const char *val, size_t val_size)
+{
+  abort ();
+}
+
+#endif /* !HAVE_HIVEX */
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index dbf5d00..6bcd053 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -9477,6 +9477,193 @@ Some of the parameters of a mounted filesystem can be examined
 and modified using the C<guestfs_xfs_info> and
 C<guestfs_xfs_growfs> calls." };
 
+  { defaults with
+    name = "hivex_open";
+    style = RErr, [Pathname "filename"], [OBool "verbose"; OBool "debug"; OBool "write"];
+    proc_nr = Some 350;
+    optional = Some "hivex";
+    shortdesc = "open a Windows Registry hive file";
+    longdesc = "\
+Open the Windows Registry hive file named C<filename>.
+If there was any previous hivex handle associated with this
+guestfs session, then it is closed.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_close";
+    style = RErr, [], [];
+    proc_nr = Some 351;
+    optional = Some "hivex";
+    shortdesc = "close the current hivex handle";
+    longdesc = "\
+Close the current hivex handle.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_root";
+    style = RInt64 "nodeh", [], [];
+    proc_nr = Some 352;
+    optional = Some "hivex";
+    shortdesc = "return the root node of the hive";
+    longdesc = "\
+Return the root node of the hive.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_node_name";
+    style = RString "name", [Int64 "nodeh"], [];
+    proc_nr = Some 353;
+    optional = Some "hivex";
+    shortdesc = "return the name of the node";
+    longdesc = "\
+Return the name of C<nodeh>.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_node_children";
+    style = RStructList ("nodehs", "hivex_node"), [Int64 "nodeh"], [];
+    proc_nr = Some 354;
+    optional = Some "hivex";
+    shortdesc = "return list of nodes which are subkeys of node";
+    longdesc = "\
+Return the list of nodes which are subkeys of C<nodeh>.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_node_get_child";
+    style = RInt64 "child", [Int64 "nodeh"; String "name"], [];
+    proc_nr = Some 355;
+    optional = Some "hivex";
+    shortdesc = "return the named child of node";
+    longdesc = "\
+Return the child of C<nodeh> with the name C<name>, if it exists.
+This can return C<0> meaning the name was not found.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_node_parent";
+    style = RInt64 "parent", [Int64 "nodeh"], [];
+    proc_nr = Some 356;
+    optional = Some "hivex";
+    shortdesc = "return the parent of node";
+    longdesc = "\
+Return the parent node of C<nodeh>.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_node_values";
+    style = RStructList ("valuehs", "hivex_value"), [Int64 "nodeh"], [];
+    proc_nr = Some 357;
+    optional = Some "hivex";
+    shortdesc = "return list of values attached to node";
+    longdesc = "\
+Return the array of (key, datatype, data) tuples attached to C<nodeh>.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_node_get_value";
+    style = RInt64 "valueh", [Int64 "nodeh"; String "key"], [];
+    proc_nr = Some 358;
+    optional = Some "hivex";
+    shortdesc = "return the named value";
+    longdesc = "\
+Return the value attached to C<nodeh> which has the
+name C<key>, if it exists.  This can return C<0> meaning
+the key was not found.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_value_key";
+    style = RString "key", [Int64 "valueh"], [];
+    proc_nr = Some 359;
+    optional = Some "hivex";
+    shortdesc = "return the key field from the (key, datatype, data) tuple";
+    longdesc = "\
+Return the key (name) field of a (key, datatype, data) tuple.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_value_type";
+    style = RInt64 "datatype", [Int64 "valueh"], [];
+    proc_nr = Some 360;
+    optional = Some "hivex";
+    shortdesc = "return the data type from the (key, datatype, data) tuple";
+    longdesc = "\
+Return the data type field from a (key, datatype, data) tuple.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_value_value";
+    style = RBufferOut "databuf", [Int64 "valueh"], [];
+    proc_nr = Some 361;
+    optional = Some "hivex";
+    shortdesc = "return the data field from the (key, datatype, data) tuple";
+    longdesc = "\
+Return the data field of a (key, datatype, data) tuple.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_commit";
+    style = RErr, [OptString "filename"], [];
+    proc_nr = Some 362;
+    optional = Some "hivex";
+    shortdesc = "commit (write) changes back to the hive";
+    longdesc = "\
+Commit (write) changes to the hive.
+
+If the optional C<filename> parameter is null, then the changes
+are written back to the same hive that was opened.  If this is
+not null then they are written to the alternate filename given
+and the original hive is left untouched.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_node_add_child";
+    style = RInt64 "nodeh", [Int64 "parent"; String "name"], [];
+    proc_nr = Some 363;
+    optional = Some "hivex";
+    shortdesc = "add a child node";
+    longdesc = "\
+Add a child node to C<parent> named C<name>.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_node_delete_child";
+    style = RErr, [Int64 "nodeh"], [];
+    proc_nr = Some 364;
+    optional = Some "hivex";
+    shortdesc = "delete a node (recursively)";
+    longdesc = "\
+Delete C<nodeh>, recursively if necessary.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
+  { defaults with
+    name = "hivex_node_set_value";
+    style = RErr, [Int64 "nodeh"; String "key"; Int64 "t"; BufferIn "val"], [];
+    proc_nr = Some 365;
+    optional = Some "hivex";
+    shortdesc = "set or replace a single value in a node";
+    longdesc = "\
+Set or replace a single value under the node C<nodeh>.  The
+C<key> is the name, C<t> is the type, and C<val> is the data.
+
+This is a wrapper around the L<hivex(3)> call of the same name." };
+
 ]
 
 (* Non-API meta-commands available only in guestfish.
diff --git a/generator/generator_structs.ml b/generator/generator_structs.ml
index d4fc1ce..2fa373f 100644
--- a/generator/generator_structs.ml
+++ b/generator/generator_structs.ml
@@ -263,6 +263,18 @@ let structs = [
     "uts_version", FString;
     "uts_machine", FString;
   ];
+
+  (* Used by hivex_* APIs to return a list of int64 handles (node
+   * handles and value handles).  Note that we can't add a putative
+   * 'RInt64List' type to the generator because we need to return
+   * length and size, and RStructList does this already.
+   *)
+  "hivex_node", [
+    "hivex_node_h", FInt64;
+  ];
+  "hivex_value", [
+    "hivex_value_h", FInt64;
+  ];
 ] (* end of structs *)
 
 (* For bindings which want camel case *)
@@ -284,6 +296,8 @@ let camel_structs = [
   "mdstat", "MDStat";
   "btrfssubvolume", "BTRFSSubvolume";
   "utsname", "UTSName";
+  "hivex_node", "HivexNode";
+  "hivex_value", "HivexValue";
 ]
 let camel_structs = List.sort (fun (_,a) (_,b) -> compare a b) camel_structs
 
diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc
index 13dc3e3..26d1c3c 100644
--- a/gobject/Makefile.inc
+++ b/gobject/Makefile.inc
@@ -40,6 +40,8 @@ guestfs_gobject_headers= \
   include/guestfs-gobject/struct-btrfssubvolume.h \
   include/guestfs-gobject/struct-xfsinfo.h \
   include/guestfs-gobject/struct-utsname.h \
+  include/guestfs-gobject/struct-hivex_node.h \
+  include/guestfs-gobject/struct-hivex_value.h \
   include/guestfs-gobject/optargs-internal_test.h \
   include/guestfs-gobject/optargs-add_drive.h \
   include/guestfs-gobject/optargs-add_domain.h \
@@ -74,7 +76,8 @@ guestfs_gobject_headers= \
   include/guestfs-gobject/optargs-rsync.h \
   include/guestfs-gobject/optargs-rsync_in.h \
   include/guestfs-gobject/optargs-rsync_out.h \
-  include/guestfs-gobject/optargs-xfs_admin.h
+  include/guestfs-gobject/optargs-xfs_admin.h \
+  include/guestfs-gobject/optargs-hivex_open.h
 
 guestfs_gobject_sources= \
   src/session.c \
@@ -96,6 +99,8 @@ guestfs_gobject_sources= \
   src/struct-btrfssubvolume.c \
   src/struct-xfsinfo.c \
   src/struct-utsname.c \
+  src/struct-hivex_node.c \
+  src/struct-hivex_value.c \
   src/optargs-internal_test.c \
   src/optargs-add_drive.c \
   src/optargs-add_domain.c \
@@ -130,4 +135,5 @@ guestfs_gobject_sources= \
   src/optargs-rsync.c \
   src/optargs-rsync_in.c \
   src/optargs-rsync_out.c \
-  src/optargs-xfs_admin.c
+  src/optargs-xfs_admin.c \
+  src/optargs-hivex_open.c
diff --git a/java/Makefile.inc b/java/Makefile.inc
index 2b4b35e..73b45cc 100644
--- a/java/Makefile.inc
+++ b/java/Makefile.inc
@@ -23,6 +23,8 @@ java_built_sources = \
 	com/redhat/et/libguestfs/Application.java \
 	com/redhat/et/libguestfs/BTRFSSubvolume.java \
 	com/redhat/et/libguestfs/Dirent.java \
+	com/redhat/et/libguestfs/HivexNode.java \
+	com/redhat/et/libguestfs/HivexValue.java \
 	com/redhat/et/libguestfs/INotifyEvent.java \
 	com/redhat/et/libguestfs/ISOInfo.java \
 	com/redhat/et/libguestfs/IntBool.java \
diff --git a/java/com/redhat/et/libguestfs/.gitignore b/java/com/redhat/et/libguestfs/.gitignore
index 80b245d..72a1144 100644
--- a/java/com/redhat/et/libguestfs/.gitignore
+++ b/java/com/redhat/et/libguestfs/.gitignore
@@ -1,6 +1,8 @@
 Application.java
 BTRFSSubvolume.java
 Dirent.java
+HivexNode.java
+HivexValue.java
 INotifyEvent.java
 ISOInfo.java
 IntBool.java
diff --git a/po/POTFILES b/po/POTFILES
index 65dea19..13f20c1 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -41,6 +41,7 @@ daemon/grub.c
 daemon/guestfsd.c
 daemon/headtail.c
 daemon/hexdump.c
+daemon/hivex.c
 daemon/htonl.c
 daemon/initrd.c
 daemon/inotify.c
@@ -148,6 +149,7 @@ gobject/src/optargs-copy_file_to_file.c
 gobject/src/optargs-e2fsck.c
 gobject/src/optargs-fstrim.c
 gobject/src/optargs-grep.c
+gobject/src/optargs-hivex_open.c
 gobject/src/optargs-inspect_get_icon.c
 gobject/src/optargs-internal_test.c
 gobject/src/optargs-md_create.c
@@ -174,6 +176,8 @@ gobject/src/session.c
 gobject/src/struct-application.c
 gobject/src/struct-btrfssubvolume.c
 gobject/src/struct-dirent.c
+gobject/src/struct-hivex_node.c
+gobject/src/struct-hivex_value.c
 gobject/src/struct-inotify_event.c
 gobject/src/struct-int_bool.c
 gobject/src/struct-isoinfo.c
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index aef2e27..4753102 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-349
+365
diff --git a/src/guestfs.pod b/src/guestfs.pod
index cd4f5c5..7361e0a 100644
--- a/src/guestfs.pod
+++ b/src/guestfs.pod
@@ -723,12 +723,15 @@ length filenames, keep the files in a tarball.
 =head3 ACCESSING THE WINDOWS REGISTRY
 
 Libguestfs also provides some help for decoding Windows Registry
-"hive" files, through the library C<hivex> which is part of the
-libguestfs project although ships as a separate tarball.  You have to
-locate and download the hive file(s) yourself, and then pass them to
-C<hivex> functions.  See also the programs L<hivexml(1)>,
-L<hivexsh(1)>, L<hivexregedit(1)> and L<virt-win-reg(1)> for more help
-on this issue.
+"hive" files, through a separate C library called L<hivex(3)>.
+
+Before libguestfs 1.19.35 you had to download the hive file, operate
+on it locally using hivex, and upload it again.  Since this version,
+we have included the major hivex APIs directly in the libguestfs API
+(see L</guestfs_hivex_open>).  This means that if you have opened a
+Windows guest, you can read and write the registry directly.
+
+See also L<virt-win-reg(1)>.
 
 =head3 SYMLINKS ON NTFS-3G FILESYSTEMS
 
-- 
1.7.10.4




More information about the Libguestfs mailing list