[PATCH 3/7] generator: Add new return types to ABI: RLenNode and RLenValue
by Alex Nelson
RLenNode and RLenValue are similar to RLenType, though with one less
argument. This required adding one processing function for OCaml and
Python.
Signed-off-by: Alex Nelson <ajnelson(a)cs.ucsc.edu>
---
generator/generator.ml | 114 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/generator/generator.ml b/generator/generator.ml
index 48b6e3a..15ebc44 100755
--- a/generator/generator.ml
+++ b/generator/generator.ml
@@ -49,8 +49,10 @@ and ret =
| RNode (* Returns hive_node_h or 0. *)
| RNodeNotFound (* See hivex_node_get_child. *)
| RNodeList (* Returns hive_node_h* or NULL. *)
+ | RLenNode (* See node_struct_length. *)
| RValue (* Returns hive_value_h or 0. *)
| RValueList (* Returns hive_value_h* or NULL. *)
+ | RLenValue (* See value_struct_length. *)
| RString (* Returns char* or NULL. *)
| RStringList (* Returns char** or NULL. *)
| RLenType (* See hivex_value_type. *)
@@ -878,6 +880,8 @@ and generate_c_prototype ?(extern = false) name style =
| RValueList -> pr "hive_value_h *"
| RString -> pr "char *"
| RStringList -> pr "char **"
+ | RLenNode -> pr "hive_node_h "
+ | RLenValue -> pr "hive_value_h "
| RLenType -> pr "int "
| RLenTypeVal -> pr "char *"
| RInt32 -> pr "int32_t "
@@ -899,6 +903,8 @@ and generate_c_prototype ?(extern = false) name style =
) (snd style);
(match fst style with
| RLenType | RLenTypeVal -> pr ", hive_type *t, size_t *len"
+ | RLenNode -> pr ", size_t *len"
+ | RLenValue -> pr ", size_t *len"
| _ -> ()
);
pr ");\n"
@@ -1101,6 +1107,14 @@ On error this returns NULL and sets errno.\n\n"
pr "\
Returns 0 on success.
On error this returns -1 and sets errno.\n\n"
+ | RLenNode ->
+ pr "\
+Returns a positive number on success.
+On error this returns 0 and sets errno.\n\n"
+ | RLenValue ->
+ pr "\
+Returns a positive number on success.
+On error this returns 0 and sets errno.\n\n"
| RLenTypeVal ->
pr "\
The value is returned as an array of bytes (of length C<len>).
@@ -1612,6 +1626,8 @@ and generate_ocaml_prototype ?(is_external = false) name style =
| RString -> pr "string"
| RStringList -> pr "string array"
| RLenType -> pr "hive_type * int"
+ | RLenNode -> pr "node"
+ | RLenValue -> pr "value"
| RLenTypeVal -> pr "hive_type * string"
| RInt32 -> pr "int32"
| RInt64 -> pr "int64"
@@ -1697,6 +1713,8 @@ static void raise_closed (const char *) Noreturn;
let c_params =
match fst style with
| RLenType | RLenTypeVal -> c_params @ [["&t"; "&len"]]
+ | RLenNode -> c_params @ [["&len"]]
+ | RLenValue -> c_params @ [["&len"]]
| _ -> c_params in
let c_params = List.concat c_params in
@@ -1769,6 +1787,14 @@ static void raise_closed (const char *) Noreturn;
pr " size_t len;\n";
pr " hive_type t;\n";
"-1"
+ | RLenNode ->
+ pr " int r;\n";
+ pr " size_t len;\n";
+ "0"
+ | RLenValue ->
+ pr " int r;\n";
+ pr " size_t len;\n";
+ "0"
| RLenTypeVal ->
pr " char *r;\n";
pr " size_t len;\n";
@@ -1849,6 +1875,8 @@ static void raise_closed (const char *) Noreturn;
pr " for (int i = 0; r[i] != NULL; ++i) free (r[i]);\n";
pr " free (r);\n"
| RLenType -> pr " rv = copy_type_len (len, t);\n"
+ | RLenNode -> pr " rv = copy_len (len);\n"
+ | RLenValue -> pr " rv = copy_len (len);\n"
| RLenTypeVal ->
pr " rv = copy_type_value (r, len, t);\n";
pr " free (r);\n"
@@ -1971,6 +1999,18 @@ copy_type_len (size_t len, hive_type t)
}
static value
+copy_type (size_t len, hive_type t)
+{
+ CAMLparam0 ();
+ CAMLlocal2 (v, rv);
+
+ rv = caml_alloc (1, 0);
+ v = Val_int (len);
+ Store_field (rv, 0, v);
+ CAMLreturn (rv);
+}
+
+static value
copy_type_value (const char *r, size_t len, hive_type t)
{
CAMLparam0 ();
@@ -2160,6 +2200,8 @@ sub open {
| RString
| RStringList
| RLenType
+ | RLenNode
+ | RLenValue
| RLenTypeVal
| RInt32
| RInt64 -> ()
@@ -2234,6 +2276,8 @@ and generate_perl_prototype name style =
| RString -> pr "$string = "
| RStringList -> pr "@strings = "
| RLenType -> pr "($type, $len) = "
+ | RLenNode -> pr "($len) = "
+ | RLenValue -> pr "($len) = "
| RLenTypeVal -> pr "($type, $data) = "
| RInt32 -> pr "$int32 = "
| RInt64 -> pr "$int64 = "
@@ -2457,6 +2501,8 @@ DESTROY (h)
| RValueList
| RStringList
| RLenType
+ | RLenNode
+ | RLenValue
| RLenTypeVal -> pr "void\n"
| RInt32 -> pr "SV *\n"
| RInt64 -> pr "SV *\n"
@@ -2629,6 +2675,34 @@ DESTROY (h)
pr " PUSHs (sv_2mortal (newSViv (type)));\n";
pr " PUSHs (sv_2mortal (newSViv (len)));\n";
+ | RLenNode ->
+ pr "PREINIT:\n";
+ pr " int r;\n";
+ pr " size_t len;\n";
+ pr " PPCODE:\n";
+ pr " r = hivex_%s (%s, &len);\n"
+ name (String.concat ", " c_params);
+ free_args ();
+ pr " if (r == 0)\n";
+ pr " croak (\"%%s: \", \"%s\", strerror (errno));\n"
+ name;
+ pr " EXTEND (SP, 2);\n";
+ pr " PUSHs (sv_2mortal (newSViv (len)));\n";
+
+ | RLenValue ->
+ pr "PREINIT:\n";
+ pr " int r;\n";
+ pr " size_t len;\n";
+ pr " PPCODE:\n";
+ pr " r = hivex_%s (%s, &len);\n"
+ name (String.concat ", " c_params);
+ free_args ();
+ pr " if (r == 0)\n";
+ pr " croak (\"%%s: \", \"%s\", strerror (errno));\n"
+ name;
+ pr " EXTEND (SP, 2);\n";
+ pr " PUSHs (sv_2mortal (newSViv (len)));\n";
+
| RLenTypeVal ->
pr "PREINIT:\n";
pr " char *r;\n";
@@ -2867,6 +2941,14 @@ put_len_type (size_t len, hive_type t)
}
static PyObject *
+put_len (size_t len)
+{
+ PyObject *r = PyTuple_New (1);
+ PyTuple_SetItem (r, 0, PyLong_FromLongLong ((long) len));
+ return r;
+}
+
+static PyObject *
put_val_type (char *val, size_t len, hive_type t)
{
PyObject *r = PyTuple_New (2);
@@ -2906,6 +2988,14 @@ put_val_type (char *val, size_t len, hive_type t)
pr " size_t len;\n";
pr " hive_type t;\n";
"-1"
+ | RLenNode ->
+ pr " int r;\n";
+ pr " size_t len;\n";
+ "0"
+ | RLenValue ->
+ pr " int r;\n";
+ pr " size_t len;\n";
+ "0"
| RLenTypeVal ->
pr " char *r;\n";
pr " size_t len;\n";
@@ -2930,6 +3020,7 @@ put_val_type (char *val, size_t len, hive_type t)
let c_params =
match fst style with
| RLenType | RLenTypeVal -> c_params @ ["&t"; "&len"]
+ | RLenNode | RLenValue -> c_params @ ["&len"]
| _ -> c_params in
List.iter (
@@ -3074,6 +3165,10 @@ put_val_type (char *val, size_t len, hive_type t)
pr " free_strings (r);\n"
| RLenType ->
pr " py_r = put_len_type (len, t);\n"
+ | RLenNode ->
+ pr " py_r = put_len (len);\n"
+ | RLenValue ->
+ pr " py_r = put_len (len);\n"
| RLenTypeVal ->
pr " py_r = put_val_type (r, len, t);\n";
pr " free (r);\n"
@@ -3284,6 +3379,8 @@ get_values (VALUE valuesv, size_t *nr_values)
| RString -> "string"
| RStringList -> "list"
| RLenType -> "hash"
+ | RLenNode -> "integer"
+ | RLenValue -> "integer"
| RLenTypeVal -> "hash"
| RInt32 -> "integer"
| RInt64 -> "integer" in
@@ -3382,6 +3479,14 @@ get_values (VALUE valuesv, size_t *nr_values)
pr " size_t len;\n";
pr " hive_type t;\n";
"-1"
+ | RLenNode ->
+ pr " int r;\n";
+ pr " size_t len;\n";
+ "0"
+ | RLenValue ->
+ pr " int r;\n";
+ pr " size_t len;\n";
+ "0"
| RLenTypeVal ->
pr " char *r;\n";
pr " size_t len;\n";
@@ -3406,6 +3511,7 @@ get_values (VALUE valuesv, size_t *nr_values)
let c_params =
match ret with
| RLenType | RLenTypeVal -> c_params @ [["&t"; "&len"]]
+ | RLenNode | RLenValue -> c_params @ [["&len"]]
| _ -> c_params in
let c_params = List.concat c_params in
@@ -3487,6 +3593,14 @@ get_values (VALUE valuesv, size_t *nr_values)
pr " rb_hash_aset (rv, ID2SYM (rb_intern (\"len\")), INT2NUM (len));\n";
pr " rb_hash_aset (rv, ID2SYM (rb_intern (\"type\")), INT2NUM (t));\n";
pr " return rv;\n"
+ | RLenNode ->
+ pr " VALUE rv = rb_hash_new ();\n";
+ pr " rb_hash_aset (rv, ID2SYM (rb_intern (\"len\")), INT2NUM (len));\n";
+ pr " return rv;\n"
+ | RLenValue ->
+ pr " VALUE rv = rb_hash_new ();\n";
+ pr " rb_hash_aset (rv, ID2SYM (rb_intern (\"len\")), INT2NUM (len));\n";
+ pr " return rv;\n"
| RLenTypeVal ->
pr " VALUE rv = rb_hash_new ();\n";
pr " rb_hash_aset (rv, ID2SYM (rb_intern (\"len\")), INT2NUM (len));\n";
--
1.7.6
12 years, 11 months
Man pages for virt-p2v-server?
by Greg Scott
I just installed virt-v2v 0.8.3.1 on a Fedora 14 VM and was getting
ready to set up a P2V migration. But the virt-p2v-server man pages only
tell me about the GPL and that's it. Is the documentation for that
.conf file someplace else now? Or don't I need it anymore?
Thanks
- Greg Scott
12 years, 11 months
Fwd: Re: VirtFS Query
by Harsh Bora
Richard, FYI.
On Wed, 28 Sep 2011 17:05:42 +0530, Harsh Bora
<harsh(a)linux.vnet.ibm.com> wrote:
> Hi Aneesh,
>
> Richard asked me if we have any plans to provide a solution for this use
> case:
>
> https://www.redhat.com/archives/libguestfs/2011-September/msg00089.html
>
> IIUC, VirtFS as a rootfs is targeted towards this requirement only,
> right? Any inputs ?
>
The right way to do this is to use a export path /guest and bind mount
needed directories within. VirtFS just export /guest and everything
works out easily. I already have autotest driving virtFS as root. So
that works easily
-aneesh
12 years, 11 months
Using febootstrap , please help
by Onkar N Mahajan
Hello,
I am new to febootstrap. I am struggling to install fedora 14 on
disk.img (formatted with ext4fs) mounted on
/mnt/temp . How to use febootstrap to do this ? Does it require any yum
configuration ? I searched the web for documentation on this , but
nothing is clearly mentioned. Please anyone tell me how to do this.
I am doing this on Fedora 14 host.
-- Onkar
12 years, 11 months
"make check" on ArchLinux: "This kernel requires an x86-64 CPU, but only detected an i686 CPU"
by Erik Nolte
I'm updating the ArchLinux libguestfs package to 1.12.7, but the "make check" tests fail in qemu with:
Booting from ROM...
This kernel requires an x86-64 CPU, but only detected an i686 CPU.
Unable to boot - please use a kernel appropriate for your CPU.
How does qemu detect the CPU type? I'm running a 64-bit ArchLinux (without KVM) on an Intel Xeon E5420 processor. I'm able to boot qemu's small test image (http://wiki.qemu.org/download/linux-0.2.img.bz2) and the libguestfs iso image test passes, but the make-{debian,fedora,ubuntu,windows}-img.sh scripts all fail with the CPU mismatch bios error.
I added "-v" to guestfish in images/guest-aux/make-debian-img.sh, ran "make check" and got the output listed below. I got the same results running as root and as non-root.
$ mcp:/enolte/libguestfs/src/libguestfs-1.12.7> make check
Making check in gnulib/lib
make[1]: Entering directory `/home/enolte/libguestfs/src/libguestfs-1.12.7/gnulib/lib'
GEN configmake.h
make check-recursive
make[2]: Entering directory `/home/enolte/libguestfs/src/libguestfs-1.12.7/gnulib/lib'
make[3]: Entering directory `/home/enolte/libguestfs/src/libguestfs-1.12.7/gnulib/lib'
GEN configmake.h
make[3]: Leaving directory `/home/enolte/libguestfs/src/libguestfs-1.12.7/gnulib/lib'
make[2]: Leaving directory `/home/enolte/libguestfs/src/libguestfs-1.12.7/gnulib/lib'
make[1]: Leaving directory `/home/enolte/libguestfs/src/libguestfs-1.12.7/gnulib/lib'
Making check in images
make[1]: Entering directory `/home/enolte/libguestfs/src/libguestfs-1.12.7/images'
ln -sf /10klines abssymlink
rm -f test.iso test.iso-t
mkdir -p directory
/usr/bin/genisoimage -J -r -graft-points \
-o test.iso-t \
./helloworld.tar ./helloworld.tar.gz ./helloworld.tar.xz ./empty ./known-1 ./known-2 ./known-3 ./known-4 ./known-5 ./bin-i586-dynamic ./bin-sparc-dynamic ./bin-win32.exe ./bin-win64.exe ./bin-x86_64-dynamic ./lib-i586.so ./lib-sparc.so ./lib-win32.dll ./lib-win64.dll ./lib-x86_64.so ./test-grep.txt ./100kallzeroes ./100kallnewlines ./100kallspaces ./100krandom ./10klines ./abssymlink ./hello.b64 ./initrd ./initrd-x86_64.img ./initrd-x86_64.img.gz ./test-grep.txt.gz /directory=directory
Total translation table size: 0
Total rockridge attributes bytes: 3010
Total directory bytes: 2048
Path table size(bytes): 26
Max brk space used 0
635 extents written (1 MB)
rmdir directory
mv test.iso-t test.iso
make debian.img fedora.img ubuntu.img windows.img
make[2]: Entering directory `/home/enolte/libguestfs/src/libguestfs-1.12.7/images'
TMPDIR=.. \
SRCDIR=. \
bash guest-aux/make-debian-img.sh
libguestfs: [00000ms] febootstrap-supermin-helper --verbose -f checksum '/home/enolte/libguestfs/src/libguestfs-1.12.7/appliance/supermin.d' x86_64
supermin helper [00000ms] whitelist = (not specified), host_cpu = x86_64, kernel = (null), initrd = (null), appliance = (null)
supermin helper [00000ms] inputs[0] = /home/enolte/libguestfs/src/libguestfs-1.12.7/appliance/supermin.d
supermin helper [00000ms] finished creating kernel
supermin helper [00000ms] visiting /home/enolte/libguestfs/src/libguestfs-1.12.7/appliance/supermin.d
supermin helper [00000ms] visiting /home/enolte/libguestfs/src/libguestfs-1.12.7/appliance/supermin.d/base.img
supermin helper [00000ms] visiting /home/enolte/libguestfs/src/libguestfs-1.12.7/appliance/supermin.d/daemon.img
supermin helper [00000ms] visiting /home/enolte/libguestfs/src/libguestfs-1.12.7/appliance/supermin.d/hostfiles
supermin helper [00020ms] visiting /home/enolte/libguestfs/src/libguestfs-1.12.7/appliance/supermin.d/init.img
supermin helper [00052ms] finished creating appliance
libguestfs: [00055ms] begin testing qemu features
libguestfs: [00068ms] finished testing qemu features
libguestfs: accept_from_daemon: 0x1625140 g->state = 1
[00069ms] /usr/bin/qemu \
-drive file=debian.img.tmp,cache=off,format=raw,if=virtio \
-nodefconfig \
-machine pc,accel=kvm:tcg \
-nodefaults \
-nographic \
-m 500 \
-no-reboot \
-no-hpet \
-device virtio-serial \
-serial stdio \
-chardev socket,path=/home/enolte/libguestfs/src/libguestfs-1.12.7/libguestfsCMM14k/guestfsd.sock,id=channel0 \
-device virtserialport,chardev=channel0,name=org.libguestfs.channel.0 \
-kernel /home/enolte/libguestfs/src/libguestfs-1.12.7/.guestfs-1004/kernel.26205 \
-initrd /home/enolte/libguestfs/src/libguestfs-1.12.7/.guestfs-1004/initrd.26205 \
-append 'panic=1 console=ttyS0 udevtimeout=300 noapic acpi=off printk.time=1 cgroup_disable=memory selinux=0 guestfs_verbose=1 TERM=xterm-256color ' \
-drive file=/home/enolte/libguestfs/src/libguestfs-1.12.7/.guestfs-1004/root.26205,snapshot=on,if=virtio,cache=unsafeCould not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
\x1b[1;256r\x1b[256;256H\x1b[6n
Google, Inc.
Serial Graphics Adapter 09/23/11
SGABIOS $Id: sgabios.S 8 2010-04-22 00:03:40Z nlaredo $ (root@saltdev) Fri Sep 23 18:55:38 UTC 2011
Term: 80x24
4 0
SeaBIOS (version pre-0.6.3-20110315_112143-titi)
Booting from ROM...
This kernel requires an x86-64 CPU, but only detected an i686 CPU.
Unable to boot - please use a kernel appropriate for your CPU.
^Cmake[2]: *** [debian.img] Interrupt
make[1]: *** [check-am] Interrupt
make: *** [check-recursive] Interrupt
12 years, 11 months
[PATCH] febootstrap: Use contents of installed Debian packages instead of downloading and unpacking them.
by Hilko Bengen
---
src/febootstrap_debian.ml | 65 +++++++++++++++++++++++++++++++++++++-------
1 files changed, 54 insertions(+), 11 deletions(-)
diff --git a/src/febootstrap_debian.ml b/src/febootstrap_debian.ml
index 23f3593..bb10f15 100644
--- a/src/febootstrap_debian.ml
+++ b/src/febootstrap_debian.ml
@@ -28,6 +28,9 @@ open Febootstrap_cmdline
(* Create a temporary directory for use by all the functions in this file. *)
let tmpdir = tmpdir ()
+let installed_pkgs =
+ run_command_get_lines "dpkg-query --show --showformat='${Package}\\n'"
+
let debian_detect () =
file_exists "/etc/debian_version" &&
Config.aptitude <> "no" && Config.apt_cache <> "no" && Config.dpkg <> "no"
@@ -51,18 +54,29 @@ let rec debian_resolve_dependencies_and_download names =
not (List.exists (fun re -> Str.string_match re name 0) excludes)
) pkgs in
+ let present_pkgs, download_pkgs = List.partition (
+ fun pkg -> List.exists ((=) pkg) installed_pkgs
+ ) pkgs in
+
+ debug "wanted packages (present / download): %s / %s\n"
+ (String.concat " " present_pkgs)
+ (String.concat " " download_pkgs);
+
(* Download the packages. *)
- let cmd =
- sprintf "umask 0000; cd %s && %s download %s"
- (Filename.quote tmpdir)
- Config.aptitude
- (String.concat " " (List.map Filename.quote pkgs)) in
- run_command cmd;
+ if (List.length download_pkgs > 0)
+ then (
+ let cmd =
+ sprintf "umask 0000; cd %s && %s download %s"
+ (Filename.quote tmpdir)
+ Config.aptitude
+ (String.concat " " (List.map Filename.quote download_pkgs)) in
+ run_command cmd
+ );
(* Find out what aptitude downloaded. *)
let files = Sys.readdir tmpdir in
- let pkgs = List.map (
+ let download_pkgs = List.map (
fun pkg ->
(* Look for 'pkg_*.deb' in the list of files. *)
let pre = pkg ^ "_" in
@@ -79,9 +93,9 @@ let rec debian_resolve_dependencies_and_download names =
exit 1
with
Exit -> !r
- ) pkgs in
+ ) download_pkgs in
- List.sort compare pkgs
+ List.sort compare (List.append present_pkgs download_pkgs)
(* On Ubuntu 10.04 LTS, apt-cache depends --recurse is broken. It
* doesn't return the full list of dependencies. Therefore recurse
@@ -106,7 +120,7 @@ and workaround_broken_apt_cache_depends_recurse names =
else
names
-let debian_list_files pkg =
+let debian_list_files_downloaded pkg =
debug "unpacking %s ..." pkg;
(* We actually need to extract the file in order to get the
@@ -147,9 +161,38 @@ let debian_list_files pkg =
files
+let debian_list_files_installed pkg =
+ debug "using installed package %s ..." pkg;
+ let cmd = sprintf "dpkg-query --listfiles %s" pkg in
+ let lines = run_command_get_lines cmd in
+ (* filter out lines not directly describing fs objects such as
+ "package diverts others to: /path/to/..." *)
+ let lines = List.filter (
+ fun l -> l.[0] = '/' && l.[1] != '.'
+ ) lines in
+ let files = List.map (
+ fun path ->
+ let statbuf = lstat path in
+ let is_dir = statbuf.st_kind = S_DIR in
+ let config = statbuf.st_kind = S_REG && string_prefix "/etc/" path in
+ let mode = statbuf.st_perm in
+ (path, { ft_dir = is_dir; ft_config = config; ft_mode = mode;
+ ft_ghost = false; ft_size = statbuf.st_size })
+ ) lines in
+ files
+
+let debian_list_files pkg =
+ if List.exists ((=) pkg) installed_pkgs then
+ debian_list_files_installed pkg
+ else
+ debian_list_files_downloaded pkg
+
(* Easy because we already unpacked the archive above. *)
let debian_get_file_from_package pkg file =
- tmpdir // pkg ^ ".d" // file
+ if List.exists (fun p -> p = pkg) installed_pkgs then
+ file
+ else
+ tmpdir // pkg ^ ".d" // file
let () =
let ph = {
--
1.7.5.4
12 years, 11 months
[PATCH] hivexml: Do not print null input times
by Alex Nelson
Dealing with "1601-01-01T00:00:00Z" is unnecessarily awkward, especially
since the value only represents a 0 found in the data.
Signed-off-by: Alex Nelson <ajnelson(a)cs.ucsc.edu>
---
xml/hivexml.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/xml/hivexml.c b/xml/hivexml.c
index cf11676..5030c24 100644
--- a/xml/hivexml.c
+++ b/xml/hivexml.c
@@ -169,6 +169,10 @@ main (int argc, char *argv[])
* fiwalk.cpp.
*
* The caller should free the returned buffer.
+ *
+ * This function returns NULL on a 0 input. In the context of
+ * hives, which only have mtimes, 0 will always be a complete
+ * absence of data.
*/
#define WINDOWS_TICK 10000000LL
@@ -182,6 +186,9 @@ filetime_to_8601 (int64_t windows_ticks)
time_t t;
struct tm *tm;
+ if (windows_ticks == 0LL)
+ return NULL;
+
t = windows_ticks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH;
tm = gmtime (&t);
if (tm == NULL)
--
1.7.6
12 years, 11 months
[PATCH 1/1] hivexml: Base64-encode non-printable data
by Alex Nelson
Some of the data in names and string values were being unsafely printed,
causing some types of XML processors to fail (e.g. Python's Expat).
This patch checks for printability of each character and outputs base64
with an encoding attribute for unsafe data.
---
xml/hivexml.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 64 insertions(+), 11 deletions(-)
diff --git a/xml/hivexml.c b/xml/hivexml.c
index cf11676..110c8fb 100644
--- a/xml/hivexml.c
+++ b/xml/hivexml.c
@@ -27,6 +27,7 @@
#include <errno.h>
#include <time.h>
#include <locale.h>
+#include <ctype.h>
#ifdef HAVE_LIBINTL_H
#include <libintl.h>
@@ -201,6 +202,52 @@ filetime_to_8601 (int64_t windows_ticks)
return ret;
}
+/* Caller need not free return value afterwards. */
+static char *
+encoding_recommendation (const char *data)
+{
+ /* Note that this function assumes data is null-terminated. */
+ //See if the data are printable
+ int is_printable = 0;
+ size_t i;
+ size_t data_len = strlen(data);
+
+ for (i=0; i < data_len; i++) {
+ is_printable = isprint (data[i]);
+ if (!is_printable) {
+ fprintf (stderr, "encoding_recommendation: Non-printable character found at data index %zu (c=%i)\n", i, data[i]);
+ break;
+ }
+ }
+
+ return is_printable ? "none" : "base64";
+}
+
+static int
+safe_print_string_attribute (hive_h *h, void *writer_v, const char *attr_name, const char *attr_encoding, const char *attr_data)
+{
+ int ret = 0;
+ char *encoding_to_use = NULL;
+ if (attr_name && attr_data && attr_encoding) {
+ xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
+ encoding_to_use = encoding_recommendation (attr_data);
+
+ if (strcmp (encoding_to_use, "none") == 0)
+ XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST attr_name, BAD_CAST attr_data));
+ else if (strcmp (encoding_to_use, "base64") == 0) {
+ XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST attr_encoding, BAD_CAST "base64"));
+ XML_CHECK (xmlTextWriterStartAttribute, (writer, BAD_CAST attr_name));
+ XML_CHECK (xmlTextWriterWriteBase64, (writer, BAD_CAST attr_data, 0, strlen(attr_data)));
+ XML_CHECK (xmlTextWriterEndAttribute, (writer));
+ } else {
+ fprintf (stderr, "safe_print_string_attribute: Unexpected encoding to use (won't print here).\n");
+ ret = -1;
+ }
+ } else
+ ret = -1;
+ return ret;
+}
+
static int
node_start (hive_h *h, void *writer_v, hive_node_h node, const char *name)
{
@@ -210,7 +257,10 @@ node_start (hive_h *h, void *writer_v, hive_node_h node, const char *name)
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "node"));
- XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "name", BAD_CAST name));
+
+ ret = safe_print_string_attribute (h, writer_v, "name", "name_encoding", name);
+ if (ret)
+ fprintf (stderr, "Warning: node_start: safe_print_string_attribute failed, but we're continuing.\n");
if (node == hivex_root (h)) {
XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "root", BAD_CAST "1"));
@@ -227,7 +277,7 @@ node_start (hive_h *h, void *writer_v, hive_node_h node, const char *name)
}
}
- return 0;
+ return ret;
}
static int
@@ -242,13 +292,16 @@ static void
start_value (xmlTextWriterPtr writer,
const char *key, const char *type, const char *encoding)
{
+ int ret = 0;
XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "value"));
XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "type", BAD_CAST type));
if (encoding)
XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "encoding", BAD_CAST encoding));
- if (*key)
- XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "key", BAD_CAST key));
- else /* default key */
+ if (*key) {
+ ret = safe_print_string_attribute (NULL, writer, "key", "key_encoding", key);
+ if (ret)
+ fprintf (stderr, "Warning: start_value: safe_print_string_attribute failed, but we're continuing.\n");
+ } else /* default key */
XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "default", BAD_CAST "1"));
}
@@ -264,6 +317,7 @@ value_string (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
{
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
const char *type;
+ int ret = 0;
switch (t) {
case hive_t_string: type = "string"; break;
@@ -286,11 +340,9 @@ value_string (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
}
start_value (writer, key, type, NULL);
- XML_CHECK (xmlTextWriterStartAttribute, (writer, BAD_CAST "value"));
- XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST str));
- XML_CHECK (xmlTextWriterEndAttribute, (writer));
+ ret = safe_print_string_attribute (h, writer_v, "value", "value_encoding", str);
end_value (writer);
- return 0;
+ return ret;
}
static int
@@ -299,17 +351,18 @@ value_multiple_strings (hive_h *h, void *writer_v, hive_node_h node,
const char *key, char **argv)
{
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
+ int ret = 0;
start_value (writer, key, "string-list", NULL);
size_t i;
for (i = 0; argv[i] != NULL; ++i) {
XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "string"));
- XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST argv[i]));
+ ret = safe_print_string_attribute (h, writer_v, "value", "value_encoding", argv[i]);
XML_CHECK (xmlTextWriterEndElement, (writer));
}
end_value (writer);
- return 0;
+ return ret;
}
static int
--
1.7.4.4
12 years, 11 months
[PATCH 0/1] Base64-encode non-printable data
by Alex Nelson
I expect this patch to require a second version. I mainly wanted to
spur discussion:
* I firmly believe hivexml needs more encoding checks before printing.
Base64 encoding made the most sense as hivexml already uses it
elsewhere. Is this the right direction to go, to escape non-printable
data?
* Should there be an enumeration for encoding decisions? I'm returning
strings because it felt a little like over-engineering for something I
could just see as having two values.
* There need to be at most two encoding descriptors for a values and
one for nodes. Keys and values might need to encode their names.
Values might also need to encode their data. We already know I'm
pushing for value data to go into attributes in another patch series.
Could we change the "encoding" value attribute to "value_encoding"?
* I'd like to change values' "key" attribute to "name" attributes.
Rich, what are your feelings, or what are the policies to which you're
adhering, on changing the name of an element that hivexml has already
been producing? You've been quite accepting of new functionality coming
in, but what about renaming what's present?
--Alex
Alex Nelson (1):
hivexml: Base64-encode non-printable data
xml/hivexml.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 64 insertions(+), 11 deletions(-)
--
1.7.4.4
12 years, 11 months