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