From: "Richard W.M. Jones" <rjones(a)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