[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libguestfs] [PATCH 3/4] New API: guestfs_hivex_value_utf8



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

A convenience function that reads a value from the registry
and returns it as UTF-8.
---
 generator/generator_actions.ml |   20 +++++++++-
 src/inspect-fs-windows.c       |   85 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+), 1 deletion(-)

diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index 6bcd053..6290333 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -2224,6 +2224,22 @@ List the files in C<directory> (relative to the root directory,
 there is no cwd).  The '.' and '..' entries are not returned, but
 hidden files are shown." };
 
+  { defaults with
+    name = "hivex_value_utf8";
+    style = RString "databuf", [Int64 "valueh"], [];
+    optional = Some "hivex";
+    shortdesc = "return the data field from the (key, datatype, data) tuple";
+    longdesc = "\
+This calls C<guestfs_hivex_value_value> (which returns the
+data field from a hivex value tuple).  It then assumes that
+the field is a UTF-16LE string and converts the result to
+UTF-8 (or if this is not possible, it returns an error).
+
+This is useful for reading strings out of the Windows registry.
+However it is not foolproof because the registry is not
+strongly-typed and fields can contain arbitrary or unexpected
+data." };
+
 ]
 
 (* daemon_functions are any functions which cause some action
@@ -9612,7 +9628,9 @@ This is a wrapper around the L<hivex(3)> call of the same name." };
     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." };
+This is a wrapper around the L<hivex(3)> call of the same name.
+
+See also: C<guestfs_hivex_value_utf8>." };
 
   { defaults with
     name = "hivex_commit";
diff --git a/src/inspect-fs-windows.c b/src/inspect-fs-windows.c
index d04024b..cd2bd6c 100644
--- a/src/inspect-fs-windows.c
+++ b/src/inspect-fs-windows.c
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <iconv.h>
 
 #ifdef HAVE_ENDIAN_H
 #include <endian.h>
@@ -587,3 +588,87 @@ guestfs___case_sensitive_path_silently (guestfs_h *g, const char *path)
   g->error_cb = old_error_cb;
   return ret;
 }
+
+/* Read the data from 'valueh', assume it is UTF16LE and convert it to
+ * UTF8.  This is copied from hivex_value_string which doesn't work in
+ * the appliance because it uses iconv_open which doesn't work because
+ * we delete all the i18n databases.
+ */
+static char *utf16_to_utf8 (/* const */ char *input, size_t len);
+
+char *
+guestfs__hivex_value_utf8 (guestfs_h *g, int64_t valueh)
+{
+  char *buf, *ret;
+  size_t buflen;
+
+  buf = guestfs_hivex_value_value (g, valueh, &buflen);
+  if (buf == NULL)
+    return NULL;
+
+  ret = utf16_to_utf8 (buf, buflen);
+  if (ret == NULL) {
+    perrorf (g, "hivex: conversion of registry value to UTF8 failed");
+    free (buf);
+    return NULL;
+  }
+  free (buf);
+
+  return ret;
+}
+
+static char *
+utf16_to_utf8 (/* const */ char *input, size_t len)
+{
+  iconv_t ic = iconv_open ("UTF-8", "UTF-16");
+  if (ic == (iconv_t) -1)
+    return NULL;
+
+  /* iconv(3) has an insane interface ... */
+
+  /* Mostly UTF-8 will be smaller, so this is a good initial guess. */
+  size_t outalloc = len;
+
+ again:;
+  size_t inlen = len;
+  size_t outlen = outalloc;
+  char *out = malloc (outlen + 1);
+  if (out == NULL) {
+    int err = errno;
+    iconv_close (ic);
+    errno = err;
+    return NULL;
+  }
+  char *inp = input;
+  char *outp = out;
+
+  size_t r = iconv (ic, &inp, &inlen, &outp, &outlen);
+  if (r == (size_t) -1) {
+    if (errno == E2BIG) {
+      int err = errno;
+      size_t prev = outalloc;
+      /* Try again with a larger output buffer. */
+      free (out);
+      outalloc *= 2;
+      if (outalloc < prev) {
+        iconv_close (ic);
+        errno = err;
+        return NULL;
+      }
+      goto again;
+    }
+    else {
+      /* Else some conversion failure, eg. EILSEQ, EINVAL. */
+      int err = errno;
+      iconv_close (ic);
+      free (out);
+      errno = err;
+      return NULL;
+    }
+  }
+
+  *outp = '\0';
+  iconv_close (ic);
+
+  return out;
+}
-- 
1.7.10.4


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]