Conrad Meyer
2010-Jul-03 16:22 UTC
[Libguestfs] [PATCH] hivex: add hivex_set_value api call
I'm not entirely sure the generator/generator.ml changes are as correct as they could be. I'm not very familiar with Caml. The hivex_node_set_value call builds up a list of hive_set_values by walking the existing values at the node, adding or replacing the passed hive_set_value as necessary, then shoving the list at hivex_node_set_values. Not included: Perl or OCaml binding glue. I'm not on the list, please CC me to replies. Thanks! --- generator/generator.ml | 29 +++++++++++++-- lib/hivex.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/generator/generator.ml b/generator/generator.ml index 5a0ab6e..dbcbd2c 100755 --- a/generator/generator.ml +++ b/generator/generator.ml @@ -71,6 +71,7 @@ and argt = (* Note, cannot be NULL/0 unless it | AOpenFlags (* HIVEX_OPEN_* flags list. *) | AUnusedFlags (* Flags arg that is always 0 *) | ASetValues (* See hivex_node_set_values. *) + | ASetValue (* See hivex_node_set_value. *) (* Hive types, from: * https://secure.wikimedia.org/wikipedia/en/wiki/Windows_Registry#Keys_and_values @@ -304,8 +305,15 @@ subnodes become invalid. You cannot delete the root node."; "set (key, value) pairs at a node", "\ This call can be used to set all the (key, value) pairs -stored in C<node>. Note that this library does not offer -a way to modify just a single key at a node. +stored in C<node>. + +C<node> is the node to modify."; + + "node_set_value", (RErr, [AHive; ANode "node"; ASetValue; AUnusedFlags]), + "set a single (key, value) pair at a given node", + "\ +This call can be used to set a single (key, value) pair +stored in C<node>. C<node> is the node to modify."; ] @@ -459,6 +467,7 @@ let name_of_argt = function | ANode n | AValue n | AString n | AStringNullable n -> n | AOpenFlags | AUnusedFlags -> "flags" | ASetValues -> "values" + | ASetValue -> "val" (* Check function names etc. for consistency. *) let check_functions () @@ -806,6 +815,7 @@ and generate_c_prototype ?(extern = false) name style | AString n | AStringNullable n -> pr "const char *%s" n | AOpenFlags | AUnusedFlags -> pr "int flags" | ASetValues -> pr "size_t nr_values, const hive_set_value *values" + | ASetValue -> pr "const hive_set_value *val" ) (snd style); (match fst style with | RLenType | RLenTypeVal -> pr ", hive_type *t, size_t *len" @@ -937,6 +947,11 @@ Any existing values stored at the node are discarded, and their C<hive_value_h> handles become invalid. Thus you can remove all values stored at C<node> by passing C<nr_values = 0>.\n\n"; + if List.mem ASetValue (snd style) then + pr "C<value> is a single (key, value) pair. + +Existing C<hive_value_h> handles become invalid.\n\n"; + (match fst style with | RErr -> pr "\ @@ -1478,6 +1493,7 @@ and generate_ocaml_prototype ?(is_external = false) name style | AOpenFlags -> pr "open_flag list -> " | AUnusedFlags -> () | ASetValues -> pr "set_value array -> " + | ASetValue -> pr "set_value -> " ) (snd style); (match fst style with | RErr -> pr "unit" (* all errors are turned into exceptions *) @@ -1621,6 +1637,8 @@ static void raise_closed (const char *) Noreturn; | ASetValues -> pr " int nrvalues = Wosize_val (valuesv);\n"; pr " hive_set_value *values = HiveSetValues_val (valuesv);\n" + | ASetValue -> + pr " hive_set_value *val = HiveSetValue_val (valv);\n" ) (snd style); pr "\n"; @@ -1684,7 +1702,7 @@ static void raise_closed (const char *) Noreturn; List.iter ( function | AHive | ANode _ | AValue _ | AString _ | AStringNullable _ - | AOpenFlags | AUnusedFlags -> () + | AOpenFlags | AUnusedFlags | ASetValue -> () | ASetValues -> pr " free (values);\n"; pr "\n"; @@ -2113,6 +2131,7 @@ and generate_perl_prototype name style | AOpenFlags -> pr "[flags]" | AUnusedFlags -> assert false | ASetValues -> pr "\\@values" + | ASetValue -> pr "$val" ) args; pr ")" @@ -2319,6 +2338,8 @@ DESTROY (h) | AUnusedFlags -> () | ASetValues -> pr " pl_set_values values = unpack_pl_set_values (ST(%d));\n" i + | ASetValue -> + pr " pl_set_value val = unpack_pl_set_value (ST(%d));\n" i ) (snd style); let free_args () @@ -2327,7 +2348,7 @@ DESTROY (h) | ASetValues -> pr " free (values.values);\n" | AHive | ANode _ | AValue _ | AString _ | AStringNullable _ - | AOpenFlags | AUnusedFlags -> () + | AOpenFlags | AUnusedFlags | ASetValue -> () ) (snd style) in diff --git a/lib/hivex.c b/lib/hivex.c index 74a7f55..3879238 100644 --- a/lib/hivex.c +++ b/lib/hivex.c @@ -2606,3 +2606,93 @@ hivex_node_set_values (hive_h *h, hive_node_h node, return 0; } + + +int +hivex_node_set_value (hive_h *h, hive_node_h node, + const hive_set_value *val, int flags) +{ + if (!h->writable) { + errno = EROFS; + return -1; + } + + if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) { + errno = EINVAL; + return -1; + } + + hive_value_h *prev_values = hivex_node_values (h, node); + if (prev_values == NULL) + return -1; + + int retval = -1; + + size_t nr_values = 0; + for (hive_value_h *itr = prev_values; *itr != 0; ++itr) + ++nr_values; + + hive_set_value *values = malloc ((nr_values + 1) * (sizeof (hive_set_value))); + if (values == NULL) + goto leave_prev_values; + + int alloc_ct = 0; + int idx_of_val = -1; + for (hive_value_h *prev_val = prev_values; *prev_val != 0; ++prev_val) { + size_t len; + hive_type t; + + hive_set_value *value = &values[prev_val - prev_values]; + + char *valval = hivex_value_value (h, *prev_val, &t, &len); + if (valval == NULL) goto leave_partial; + + ++alloc_ct; + value->value = valval; + value->t = t; + value->len = len; + + char *valkey = hivex_value_key (h, *prev_val); + if (valkey == NULL) goto leave_partial; + + ++alloc_ct; + value->key = valkey; + + if (strcmp (valkey, val->key) == 0) + idx_of_val = prev_val - prev_values; + } + + if (idx_of_val > -1) { + free (values[idx_of_val].key); + free (values[idx_of_val].value); + } else { + idx_of_val = nr_values; + ++nr_values; + } + + hive_set_value *value = &values[idx_of_val]; + *value = (hive_set_value){ + .key = strdup (val->key), + .value = malloc (val->len), + .len = val->len, + .t = val->t + }; + + if (value->key == NULL || value->value == NULL) goto leave_partial; + memcpy (value->value, val->value, val->len); + + retval = hivex_node_set_values (h, node, nr_values, values, 0); + + leave_partial: + for (int i = 0; i < alloc_ct; i += 2) { + if (values[i / 2].value != NULL) + free (values[i / 2].value); + if (i + 1 < alloc_ct && values[i / 2].key != NULL) + free (values[i / 2].key); + } + free (values); + + leave_prev_values: + free (prev_values); + return retval; +} -- 1.7.1
Richard W.M. Jones
2010-Jul-03 17:42 UTC
[Libguestfs] [PATCH] hivex: add hivex_set_value api call
On Sat, Jul 03, 2010 at 09:22:20AM -0700, Conrad Meyer wrote:> I'm not entirely sure the generator/generator.ml changes are as correct > as they could be. I'm not very familiar with Caml.Well you can add OCaml to your CV now, because your code is fine ...> The hivex_node_set_value call builds up a list of hive_set_values by > walking the existing values at the node, adding or replacing the passed > hive_set_value as necessary, then shoving the list at > hivex_node_set_values. > > Not included: Perl or OCaml binding glue.Are you intending to go further with this? The most crucial missing part is the tests. We test via Perl code, so this implies a Perl binding (should be very easy to add). Have you loaded up files that you've modified this way on Windows? Subtle mistakes (more accurately: things which the hacked-together Windows code is not expecting) can cause registries to be silently corrupted. I had a quick look at the code and the only mistake I could spot is:> + if (strcmp (valkey, val->key) == 0)First of all use the STR* macros, secondly everything in registry files that is visible externally is matched case *in*sensitively. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://et.redhat.com/~rjones/libguestfs/ See what it can do: http://et.redhat.com/~rjones/libguestfs/recipes.html
Maybe Matching Threads
- [PATCH] hivex: add hivex_set_value api call and perl bindings, tests
- [PATCH] hivex: add hivex_set_value api call and ocaml/perl bindings, tests
- [PATCH 1/2] Add type checking, support integers as value
- [hivex] Segfault for an integer value to node_set_value
- [hivex] [PATCH 0/6] Python fixes for node_set_value