diff options
-rw-r--r-- | appliance/packagelist.in | 3 | ||||
-rw-r--r-- | daemon/Makefile.am | 7 | ||||
-rw-r--r-- | daemon/hivex.c | 509 | ||||
-rw-r--r-- | generator/generator_actions.ml | 187 | ||||
-rw-r--r-- | generator/generator_structs.ml | 14 | ||||
-rw-r--r-- | gobject/Makefile.inc | 10 | ||||
-rw-r--r-- | java/Makefile.inc | 2 | ||||
-rw-r--r-- | java/com/redhat/et/libguestfs/.gitignore | 2 | ||||
-rw-r--r-- | po/POTFILES | 4 | ||||
-rw-r--r-- | src/MAX_PROC_NR | 2 | ||||
-rw-r--r-- | src/guestfs.pod | 15 |
11 files changed, 745 insertions, 10 deletions
diff --git a/appliance/packagelist.in b/appliance/packagelist.in index 4830962d..6d412cbf 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 9ea6ce31..ffd8b81a 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 00000000..f13d3d7e --- /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 dbf5d000..6bcd0533 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 d4fc1ce5..2fa373f7 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 13dc3e3d..26d1c3c9 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 2b4b35e4..73b45cc7 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 80b245dc..72a1144c 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 65dea19c..13f20c17 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 aef2e272..47531021 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 cd4f5c5c..7361e0a5 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 |