summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-08-29 13:01:53 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-08-29 17:08:01 +0100
commit288cc74d77fd80e40a442344d9d0ce00162c1fb4 (patch)
treec43ecaeed97566746915990fd4899cc7a71f8725
parent8a723ca62eb4f93f19c5c66beffaf70997afb64c (diff)
downloadlibguestfs-288cc74d77fd80e40a442344d9d0ce00162c1fb4.tar.gz
libguestfs-288cc74d77fd80e40a442344d9d0ce00162c1fb4.tar.xz
libguestfs-288cc74d77fd80e40a442344d9d0ce00162c1fb4.zip
New API: guestfs_hivex_value_utf8
A convenience function that reads a value from the registry and returns it as UTF-8.
-rw-r--r--generator/generator_actions.ml20
-rw-r--r--src/inspect-fs-windows.c85
2 files changed, 104 insertions, 1 deletions
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index 6bcd0533..62903338 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 d04024bc..cd2bd6ca 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;
+}