[Libguestfs] [PATCH 10/12] hivexsh: Add 'setval' and 'commit' commands.

Matthew Booth mbooth at redhat.com
Thu Feb 4 17:34:36 UTC 2010


On 03/02/10 18:35, Richard W.M. Jones wrote:
>>From c6fa2b912e47df21bc6a64b2f1b0bcf17cbd0a0f Mon Sep 17 00:00:00 2001
> From: Richard Jones <rjones at redhat.com>
> Date: Wed, 3 Feb 2010 18:04:31 +0000
> Subject: [PATCH 10/12] hivexsh: Add 'setval' and 'commit' commands.
> 
> This adds the 'setval' and 'commit' commands to the hivex shell.
> 
> Also adds some example scripts showing use of these.
> ---
>  hivex/Makefile.am |    5 +-
>  hivex/example1    |   40 ++++++++
>  hivex/example2    |   47 +++++++++
>  hivex/example3    |   53 +++++++++++
>  hivex/hivexsh.c   |  271 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  hivex/hivexsh.pod |   79 ++++++++++++++++
>  6 files changed, 491 insertions(+), 4 deletions(-)
>  create mode 100755 hivex/example1
>  create mode 100755 hivex/example2
>  create mode 100755 hivex/example3
> 

A few nits inline.

Matt

> diff --git a/hivex/hivexsh.c b/hivex/hivexsh.c
> index 01a5ddc..6f33f41 100644
> --- a/hivex/hivexsh.c
> +++ b/hivex/hivexsh.c
> @@ -779,3 +816,231 @@ cmd_lsval (char *key)
>    perror ("hivexsh: lsval");
>    return -1;
>  }
> +
> +static int
> +cmd_setval (char *nrvals_str)
> +{
> +  strtol_error xerr;
> +
> +  /* Parse number of values. */
> +  long nrvals;
> +  xerr = xstrtol (nrvals_str, NULL, 0, &nrvals, "");
> +  if (xerr != LONGINT_OK) {
> +    fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"),
> +             "setval", "nrvals", "xstrtol", xerr);
> +    return -1;
> +  }
> +  if (nrvals < 0 || nrvals > 1000) {

IIRC, this 1000 was an arbitrary constant in the previous patch. Could
you replace both with a #define?

> +    fprintf (stderr, _("%s: %s: integer out of range\n"),
> +             "setval", "nrvals");
> +    return -1;
> +  }
> +
> +  struct hive_set_value *values =
> +    calloc (nrvals, sizeof (struct hive_set_value));
> +  if (values == NULL) {
> +    perror ("calloc");
> +    exit (EXIT_FAILURE);
> +  }
> +
> +  int ret = -1;
> +
> +  /* Read nrvals * 2 lines of input, nrvals * (key, value) pairs, as
> +   * explained in the man page.
> +   */
> +  int prompt = isatty (0) ? 2 : 0;

You've already got this in a global. In fact, I can't see it used
anywhere. Doesn't this generate a warning?

> +  int i, j;
> +  for (i = 0; i < nrvals; ++i) {
> +    /* Read key. */
> +    char *buf = rl_gets ("  key> ");
> +    if (!buf) {
> +      fprintf (stderr, _("hivexsh: setval: unexpected end of input\n"));
> +      quit = 1;
> +      goto error;
> +    }
> +
> +    /* Note that buf will be overwritten by the next call to rl_gets. */
> +    if (STREQ (buf, "@"))
> +      values[i].key = strdup ("");
> +    else
> +      values[i].key = strdup (buf);
> +    if (values[i].key == NULL) {
> +      perror ("strdup");
> +      exit (EXIT_FAILURE);
> +    }
> +
> +    /* Read value. */
> +    buf = rl_gets ("value> ");

Why no indentation on this prompt, as for key?

> +    if (!buf) {
> +      fprintf (stderr, _("hivexsh: setval: unexpected end of input\n"));
> +      quit = 1;
> +      goto error;
> +    }
> +
> +    if (STREQ (buf, "none")) {
> +      values[i].t = hive_t_none;
> +      values[i].len = 0;
> +    }
> +    else if (STRPREFIX (buf, "string:")) {
> +      buf += 7;
> +      values[i].t = hive_t_string;
> +      int nr_chars = strlen (buf);
> +      values[i].len = 2 * (nr_chars + 1);
> +      values[i].value = malloc (values[i].len);
> +      if (!values[i].value) {
> +        perror ("malloc");
> +        exit (EXIT_FAILURE);
> +      }
> +      for (j = 0; j <= /* sic */ nr_chars; ++j) {
> +        if (buf[j] & 0x80) {
> +          fprintf (stderr, _("hivexsh: string(utf16le): only 7 bit ASCII strings are supported for input\n"));
> +          goto error;
> +        }
> +        values[i].value[2*j] = buf[j];
> +        values[i].value[2*j+1] = '\0';

There must be a library function to do the above. Where does the 7 bit
ASCII restriction come from?

> +      }
> +    }

This doesn't look like regedit's expandstring format. What's the purpose
of it?

> +    else if (STRPREFIX (buf, "expandstring:")) {
> +      buf += 13;
> +      values[i].t = hive_t_string;
> +      int nr_chars = strlen (buf);
> +      values[i].len = 2 * (nr_chars + 1);
> +      values[i].value = malloc (values[i].len);
> +      if (!values[i].value) {
> +        perror ("malloc");
> +        exit (EXIT_FAILURE);
> +      }
> +      for (j = 0; j <= /* sic */ nr_chars; ++j) {
> +        if (buf[j] & 0x80) {
> +          fprintf (stderr, _("hivexsh: string(utf16le): only 7 bit ASCII strings are supported for input\n"));
> +          goto error;
> +        }
> +        values[i].value[2*j] = buf[j];
> +        values[i].value[2*j+1] = '\0';
> +      }
> +    }
> +    else if (STRPREFIX (buf, "dword:")) {
> +      buf += 6;
> +      values[i].t = hive_t_dword;
> +      values[i].len = 4;
> +      values[i].value = malloc (4);
> +      if (!values[i].value) {
> +        perror ("malloc");
> +        exit (EXIT_FAILURE);
> +      }
> +      long n;
> +      xerr = xstrtol (buf, NULL, 0, &n, "");

Does xstrtol support 0x notation?

> +      if (xerr != LONGINT_OK) {
> +        fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"),
> +                 "setval", "dword", "xstrtol", xerr);
> +        goto error;
> +      }
> +      if (n < 0 || n > UINT32_MAX) {
> +        fprintf (stderr, _("%s: %s: integer out of range\n"),
> +                 "setval", "dword");
> +        goto error;
> +      }
> +      uint32_t u32 = htole32 (n);
> +      memcpy (values[i].value, &u32, 4);
> +    }
> +    else if (STRPREFIX (buf, "qword:")) {
> +      buf += 6;
> +      values[i].t = hive_t_qword;
> +      values[i].len = 8;
> +      values[i].value = malloc (8);
> +      if (!values[i].value) {
> +        perror ("malloc");
> +        exit (EXIT_FAILURE);
> +      }
> +      long long n;
> +      xerr = xstrtoll (buf, NULL, 0, &n, "");
> +      if (xerr != LONGINT_OK) {
> +        fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"),
> +                 "setval", "dword", "xstrtoll", xerr);
> +        goto error;
> +      }
> +#if 0
> +      if (n < 0 || n > UINT64_MAX) {
> +        fprintf (stderr, _("%s: %s: integer out of range\n"),
> +                 "setval", "dword");
> +        goto error;
> +      }
> +#endif

Why have you commented this out?

> +      uint64_t u64 = htole64 (n);
> +      memcpy (values[i].value, &u64, 4);
> +    }
> +    else if (STRPREFIX (buf, "hex:")) {
> +      /* Read the type. */
> +      buf += 4;
> +      size_t len = strcspn (buf, ":");
> +      char *nextbuf;
> +      if (buf[len] == '\0')     /* "hex:t" */
> +        nextbuf = &buf[len];
> +      else {                    /* "hex:t:..." */
> +        buf[len] = '\0';
> +        nextbuf = &buf[len+1];
> +      }
> +
> +      long t;
> +      xerr = xstrtol (buf, NULL, 0, &t, "");
> +      if (xerr != LONGINT_OK) {
> +        fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"),
> +                 "setval", "hex", "xstrtol", xerr);
> +        goto error;
> +      }
> +      if (t < 0 || t > UINT32_MAX) {
> +        fprintf (stderr, _("%s: %s: integer out of range\n"),
> +                 "setval", "hex");
> +        goto error;
> +      }
> +      values[i].t = t;
> +
> +      /* Read the hex data. */
> +      buf = nextbuf;
> +
> +      /* The allocation length is an overestimate, but it doesn't matter. */
> +      values[i].value = malloc (1 + strlen (buf) / 2);
> +      if (!values[i].value) {
> +        perror ("malloc");
> +        exit (EXIT_FAILURE);
> +      }
> +      values[i].len = 0;
> +
> +      while (*buf) {
> +        int c = 0;
> +
> +        for (j = 0; *buf && j < 2; buf++) {
> +          if (c_isxdigit (*buf)) { /* NB: ignore non-hex digits. */

The documentation defines the limiter to be a comma. I'd stick to this
strictly, making it more likely to catch typos.

> +            c <<= 4;
> +            c |= get_xdigit (*buf);
> +            j++;
> +          }
> +        }
> +
> +        if (j == 2) values[i].value[values[i].len++] = c;
> +        else if (j == 1) {
> +          fprintf (stderr, _("hivexsh: setval: trailing garbage after hex string\n"));
> +          goto error;
> +        }
> +      }
> +    }
> +    else {
> +      fprintf (stderr,
> +               _("hivexsh: setval: cannot parse value string, please refer to the man page hivexsh(1) for help: %s\n"),
> +               buf);
> +      goto error;
> +    }
> +  }
> +
> +  ret = hivex_node_set_values (h, cwd, nrvals, values, 0);
> +
> + error:
> +  /* Free values array. */
> +  for (i = 0; i < nrvals; ++i) {
> +    free (values[i].key);
> +    free (values[i].value);
> +  }
> +  free (values);
> +
> +  return ret;
> +}

-- 
Matthew Booth, RHCA, RHCSS
Red Hat Engineering, Virtualisation Team

M:       +44 (0)7977 267231
GPG ID:  D33C3490
GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490




More information about the Libguestfs mailing list