[Libguestfs] [PATCH 2/13] hivex: Add HIVEX_OPEN_WRITE flag to allow hive to be

Richard W.M. Jones rjones at redhat.com
Thu Jan 28 10:16:45 UTC 2010


-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine.  Supports Linux and Windows.
http://et.redhat.com/~rjones/virt-df/
-------------- next part --------------
>From 699d7fa711968a8fd3904587d2bf4188ac32681c Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones at redhat.com>
Date: Mon, 18 Jan 2010 11:08:56 +0000
Subject: [PATCH 02/13] hivex: Add HIVEX_OPEN_WRITE flag to allow hive to be opened for writing.

If this flag is omitted (as in the case for all existing callers)
then the hive is still opened read-only.

We add a 'writable' flag to the hive handle, and we change the way
that the hive file (data) is stored.  The data is still mmapped if
the file is opened read-only, since that is more efficient and allows
us to handle larger hives.  However if we need to write to the file
then we have to read it all into memory, since if we had to extend the
file we need to realloc that data.

Note the manpage section L</WRITING TO HIVE FILES> comes in a later
commit.
---
 bootstrap         |    1 +
 hivex/Makefile.am |   10 +++++-----
 hivex/README      |    3 ---
 hivex/hivex.c     |   44 ++++++++++++++++++++++++++++++++++----------
 hivex/hivex.h     |    4 +++-
 hivex/hivex.pod   |   15 +++++++++++----
 6 files changed, 54 insertions(+), 23 deletions(-)

diff --git a/bootstrap b/bootstrap
index 7010eca..e743a4b 100755
--- a/bootstrap
+++ b/bootstrap
@@ -60,6 +60,7 @@ modules='
 arpa_inet
 c-ctype
 closeout
+full-read
 full-write
 gitlog-to-changelog
 gnu-make
diff --git a/hivex/Makefile.am b/hivex/Makefile.am
index b73aa2f..a2be7e3 100644
--- a/hivex/Makefile.am
+++ b/hivex/Makefile.am
@@ -23,16 +23,16 @@ libhivex_la_SOURCES = \
   hivex.c \
   hivex.h
 
-libhivex_la_LDFLAGS = -version-info 0:0:0
-libhivex_la_CFLAGS = \
-  $(WARN_CFLAGS) $(WERROR_CFLAGS)
+libhivex_la_LDFLAGS = -version-info 0:0:0 $(LTLIBINTL) $(LTLIBTHREAD)
+libhivex_la_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS)
+libhivex_la_CPPFLAGS = -I$(top_srcdir)/gnulib/lib
 
 bin_PROGRAMS = hivexml hivexget
 
 hivexml_SOURCES = \
   hivexml.c
 
-hivexml_LDADD = libhivex.la $(LIBXML2_LIBS)
+hivexml_LDADD = libhivex.la $(LIBXML2_LIBS) ../gnulib/lib/libgnu.la
 hivexml_CFLAGS = \
   $(LIBXML2_CFLAGS) \
   $(WARN_CFLAGS) $(WERROR_CFLAGS)
@@ -40,7 +40,7 @@ hivexml_CFLAGS = \
 hivexget_SOURCES = \
   hivexget.c
 
-hivexget_LDADD = libhivex.la
+hivexget_LDADD = libhivex.la ../gnulib/lib/libgnu.la
 hivexget_CFLAGS = \
   $(WARN_CFLAGS) $(WERROR_CFLAGS)
 
diff --git a/hivex/README b/hivex/README
index 5e7d21f..583d351 100644
--- a/hivex/README
+++ b/hivex/README
@@ -5,9 +5,6 @@ Copyright (C) 2009-2010 Red Hat Inc.
 This is a self-contained library for reading Windows Registry "hive"
 binary files.
 
-It is totally dedicated to reading the files and doesn't deal with
-writing or modifying them in any way.
-
 Unlike many other tools in this area, it doesn't use the textual .REG
 format for output, because parsing that is as much trouble as parsing
 the original binary format.  Instead it makes the file available
diff --git a/hivex/hivex.c b/hivex/hivex.c
index a760300..849049c 100644
--- a/hivex/hivex.c
+++ b/hivex/hivex.c
@@ -40,6 +40,12 @@
 #include <byteswap.h>
 #endif
 
+#include "full-read.h"
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
 #define STREQ(a,b) (strcmp((a),(b)) == 0)
 #define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
 //#define STRNEQ(a,b) (strcmp((a),(b)) != 0)
@@ -93,8 +99,9 @@ struct hive_h {
   int fd;
   size_t size;
   int msglvl;
+  int writable;
 
-  /* Memory-mapped (readonly) registry file. */
+  /* Registry file, memory mapped if read-only, or malloc'd if writing. */
   union {
     char *addr;
     struct ntreg_header *hdr;
@@ -282,11 +289,12 @@ hivex_open (const char *filename, int flags)
   if (h->msglvl >= 2)
     fprintf (stderr, "hivex_open: created handle %p\n", h);
 
+  h->writable = !!(flags & HIVEX_OPEN_WRITE);
   h->filename = strdup (filename);
   if (h->filename == NULL)
     goto error;
 
-  h->fd = open (filename, O_RDONLY);
+  h->fd = open (filename, O_RDONLY | O_CLOEXEC);
   if (h->fd == -1)
     goto error;
 
@@ -296,12 +304,21 @@ hivex_open (const char *filename, int flags)
 
   h->size = statbuf.st_size;
 
-  h->addr = mmap (NULL, h->size, PROT_READ, MAP_SHARED, h->fd, 0);
-  if (h->addr == MAP_FAILED)
-    goto error;
+  if (!h->writable) {
+    h->addr = mmap (NULL, h->size, PROT_READ, MAP_SHARED, h->fd, 0);
+    if (h->addr == MAP_FAILED)
+      goto error;
 
-  if (h->msglvl >= 2)
-    fprintf (stderr, "hivex_open: mapped file at %p\n", h->addr);
+    if (h->msglvl >= 2)
+      fprintf (stderr, "hivex_open: mapped file at %p\n", h->addr);
+  } else {
+    h->addr = malloc (h->size);
+    if (h->addr == NULL)
+      goto error;
+
+    if (full_read (h->fd, h->addr, h->size) < h->size)
+      goto error;
+  }
 
   /* Check header. */
   if (h->hdr->magic[0] != 'r' ||
@@ -483,8 +500,12 @@ hivex_open (const char *filename, int flags)
   int err = errno;
   if (h) {
     free (h->bitmap);
-    if (h->addr && h->size && h->addr != MAP_FAILED)
-      munmap (h->addr, h->size);
+    if (h->addr && h->size && h->addr != MAP_FAILED) {
+      if (!h->writable)
+        munmap (h->addr, h->size);
+      else
+        free (h->addr);
+    }
     if (h->fd >= 0)
       close (h->fd);
     free (h->filename);
@@ -500,7 +521,10 @@ hivex_close (hive_h *h)
   int r;
 
   free (h->bitmap);
-  munmap (h->addr, h->size);
+  if (!h->writable)
+    munmap (h->addr, h->size);
+  else
+    free (h->addr);
   r = close (h->fd);
   free (h->filename);
   free (h);
diff --git a/hivex/hivex.h b/hivex/hivex.h
index 14bdcc5..b0c1c3b 100644
--- a/hivex/hivex.h
+++ b/hivex/hivex.h
@@ -69,9 +69,11 @@ enum hive_type {
 
 typedef enum hive_type hive_type;
 
+/* Bitmask of flags passed to hivex_open. */
 #define HIVEX_OPEN_VERBOSE      1
 #define HIVEX_OPEN_DEBUG        2
-#define HIVEX_OPEN_MSGLVL_MASK  3
+#define HIVEX_OPEN_MSGLVL_MASK  (HIVEX_OPEN_VERBOSE|HIVEX_OPEN_DEBUG)
+#define HIVEX_OPEN_WRITE        4
 
 extern hive_h *hivex_open (const char *filename, int flags);
 extern int hivex_close (hive_h *h);
diff --git a/hivex/hivex.pod b/hivex/hivex.pod
index 0cc91af..0de4d54 100644
--- a/hivex/hivex.pod
+++ b/hivex/hivex.pod
@@ -13,8 +13,7 @@ hivex - Windows Registry "hive" extraction library
 
 libhivex is a library for extracting the contents of Windows Registry
 "hive" files.  It is designed to be secure against buggy or malicious
-registry files, and to have limited functionality (writing or
-modifying these files is not in the scope of this library).
+registry files.
 
 Unlike many other tools in this area, it doesn't use the textual .REG
 format for output, because parsing that is as much trouble as parsing
@@ -32,8 +31,7 @@ L<hivexget(1)>).
 Opens the hive named C<filename> for reading.
 
 Flags is an ORed list of the open flags (or C<0> if you don't
-want to pass any flags).  Currently the only
-flags defined are:
+want to pass any flags).  These flags are defined:
 
 =over 4
 
@@ -49,6 +47,12 @@ itself.
 This is also selected if the C<HIVEX_DEBUG> environment variable
 is set to 1.
 
+=item HIVEX_OPEN_WRITE
+
+Open the hive for writing.  If omitted, the hive is read-only.
+
+See L</WRITING TO HIVE FILES>.
+
 =back
 
 C<hivex_open> returns a hive handle.  On error this returns NULL and
@@ -58,6 +62,9 @@ sets C<errno> to indicate the error.
 
 Close a hive handle and free all associated resources.
 
+Note that any uncommitted writes are I<not> committed by this call,
+but instead are lost.  See L</WRITING TO HIVE FILES>.
+
 Returns 0 on success.  On error this returns -1 and sets errno.
 
 =back
-- 
1.6.5.2



More information about the Libguestfs mailing list