summaryrefslogtreecommitdiffstats
path: root/src/inspect-fs-windows.c
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 /src/inspect-fs-windows.c
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.
Diffstat (limited to 'src/inspect-fs-windows.c')
-rw-r--r--src/inspect-fs-windows.c85
1 files changed, 85 insertions, 0 deletions
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;
+}