hivexsh: Remove unused variable.
[libguestfs.git] / hivex / hivexsh.c
1 /* hivexsh - Hive shell.
2  * Copyright (C) 2009 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdint.h>
25 #include <inttypes.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <assert.h>
29 #include <errno.h>
30
31 #ifdef HAVE_LIBREADLINE
32 #include <readline/readline.h>
33 #include <readline/history.h>
34 #endif
35
36 #ifdef HAVE_GETTEXT
37 #include "gettext.h"
38 #define _(str) dgettext(PACKAGE, (str))
39 //#define N_(str) dgettext(PACKAGE, (str))
40 #else
41 #define _(str) str
42 //#define N_(str) str
43 #endif
44
45 #define STREQ(a,b) (strcmp((a),(b)) == 0)
46 #define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
47 #define STRNEQ(a,b) (strcmp((a),(b)) != 0)
48 //#define STRCASENEQ(a,b) (strcasecmp((a),(b)) != 0)
49 //#define STREQLEN(a,b,n) (strncmp((a),(b),(n)) == 0)
50 //#define STRCASEEQLEN(a,b,n) (strncasecmp((a),(b),(n)) == 0)
51 //#define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0)
52 //#define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0)
53 #define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0)
54
55 #include "c-ctype.h"
56 #include "xstrtol.h"
57
58 #include "hivex.h"
59 #include "byte_conversions.h"
60
61 static int quit = 0;
62 static int is_tty;
63 static hive_h *h = NULL;
64 static char *prompt_string = NULL; /* Normal prompt string. */
65 static char *loaded = NULL;     /* Basename of loaded file, if any. */
66 static hive_node_h cwd;         /* Current node. */
67 static int open_flags = 0;      /* Flags used when loading a hive file. */
68
69 static void usage (void) __attribute__((noreturn));
70 static void print_node_path (hive_node_h, FILE *);
71 static void set_prompt_string (void);
72 static void initialize_readline (void);
73 static void cleanup_readline (void);
74 static void add_history_line (const char *);
75 static char *rl_gets (const char *prompt_string);
76 static void sort_strings (char **strings, int len);
77 static int get_xdigit (char c);
78 static int dispatch (char *cmd, char *args);
79 static int cmd_add (char *name);
80 static int cmd_cd (char *path);
81 static int cmd_close (char *path);
82 static int cmd_commit (char *path);
83 static int cmd_del (char *args);
84 static int cmd_help (char *args);
85 static int cmd_load (char *hivefile);
86 static int cmd_ls (char *args);
87 static int cmd_lsval (char *args);
88 static int cmd_setval (char *args);
89
90 static void
91 usage (void)
92 {
93   fprintf (stderr, "hivexsh [-dfw] [hivefile]\n");
94   exit (EXIT_FAILURE);
95 }
96
97 int
98 main (int argc, char *argv[])
99 {
100   setlocale (LC_ALL, "");
101   bindtextdomain (PACKAGE, LOCALEBASEDIR);
102   textdomain (PACKAGE);
103
104   int c;
105   const char *filename = NULL;
106
107   set_prompt_string ();
108
109   while ((c = getopt (argc, argv, "dfw")) != EOF) {
110     switch (c) {
111     case 'd':
112       open_flags |= HIVEX_OPEN_DEBUG;
113       break;
114     case 'f':
115       filename = optarg;
116       break;
117     case 'w':
118       open_flags |= HIVEX_OPEN_WRITE;
119       break;
120     default:
121       usage ();
122     }
123   }
124
125   if (optind < argc) {
126     if (optind + 1 != argc)
127       usage ();
128     if (cmd_load (argv[optind]) == -1)
129       exit (EXIT_FAILURE);
130   }
131
132   /* -f filename parameter */
133   if (filename) {
134     close (0);
135     if (open (filename, O_RDONLY) == -1) {
136       perror (filename);
137       exit (EXIT_FAILURE);
138     }
139   }
140
141   /* Main loop. */
142   is_tty = isatty (0);
143   initialize_readline ();
144
145   if (is_tty)
146     printf (_(
147 "\n"
148 "Welcome to hivexsh, the hivex interactive shell for examining\n"
149 "Windows Registry binary hive files.\n"
150 "\n"
151 "Type: 'help' for help summary\n"
152 "      'quit' to quit the shell\n"
153 "\n"));
154
155   while (!quit) {
156     char *buf = rl_gets (prompt_string);
157     if (!buf) {
158       quit = 1;
159       if (is_tty)
160         printf ("\n");
161       break;
162     }
163
164     while (*buf && c_isspace (*buf))
165       buf++;
166
167     /* Ignore blank line. */
168     if (!*buf) continue;
169
170     /* If the next character is '#' then this is a comment. */
171     if (*buf == '#') continue;
172
173     /* Parsing is very simple - much simpler than guestfish.  This is
174      * because Registry keys often contain spaces, and we don't want
175      * to bother with quoting.  Therefore here we just split at the
176      * first whitespace into "cmd<whitespace>arg(s)".  We let the
177      * command decide how to deal with arg(s), if at all.
178      */
179     size_t len = strcspn (buf, " \t");
180
181     if (len == 0) continue;
182
183     char *cmd = buf;
184     char *args;
185     size_t i = 0;
186
187     if (buf[len] == '\0') {
188       /* This is mostly safe.  Although the cmd_* functions do sometimes
189        * modify args, then shouldn't do so when args is "".
190        */
191       args = (char *) "";
192       goto got_command;
193     }
194
195     buf[len] = '\0';
196     args = buf + len + 1 + strspn (&buf[len+1], " \t");
197
198     len = strlen (args);
199     while (len > 0 && c_isspace (args[len-1])) {
200       args[len-1] = '\0';
201       len--;
202     }
203
204   got_command:
205     /*printf ("command: '%s'  args: '%s'\n", cmd, args)*/;
206     int r = dispatch (cmd, args);
207     if (!is_tty && r == -1)
208       exit (EXIT_FAILURE);
209   }
210
211   cleanup_readline ();
212   free (prompt_string);
213   free (loaded);
214   if (h) hivex_close (h);
215   exit (0);
216 }
217
218 /* Set the prompt string.  This is called whenever it could change, eg.
219  * after loading a file or changing directory.
220  */
221 static void
222 set_prompt_string (void)
223 {
224   free (prompt_string);
225   prompt_string = NULL;
226
227   FILE *fp;
228   char *ptr;
229   size_t size;
230   fp = open_memstream (&ptr, &size);
231   if (fp == NULL) {
232     perror ("open_memstream");
233     exit (EXIT_FAILURE);
234   }
235
236   if (h) {
237     assert (loaded != NULL);
238     assert (cwd != 0);
239
240     fputs (loaded, fp);
241     print_node_path (cwd, fp);
242   }
243
244   fprintf (fp, "> ");
245   fclose (fp);
246   prompt_string = ptr;
247 }
248
249 /* Print the \full\path of a node. */
250 static void
251 print_node_path (hive_node_h node, FILE *fp)
252 {
253   hive_node_h root = hivex_root (h);
254
255   if (node == root) {
256     fputc ('\\', fp);
257     return;
258   }
259
260   hive_node_h parent = hivex_node_parent (h, node);
261   if (parent == 0) {
262     fprintf (stderr, _("hivexsh: error getting parent of node %zu\n"), node);
263     return;
264   }
265   print_node_path (parent, fp);
266
267   if (parent != root)
268     fputc ('\\', fp);
269
270   char *name = hivex_node_name (h, node);
271   if (name == NULL) {
272     fprintf (stderr, _("hivexsh: error getting node name of node %zx\n"), node);
273     return;
274   }
275
276   fputs (name, fp);
277   free (name);
278 }
279
280 static char *line_read = NULL;
281
282 static char *
283 rl_gets (const char *prompt_string)
284 {
285 #ifdef HAVE_LIBREADLINE
286
287   if (is_tty) {
288     if (line_read) {
289       free (line_read);
290       line_read = NULL;
291     }
292
293     line_read = readline (prompt_string);
294
295     if (line_read && *line_read)
296       add_history_line (line_read);
297
298     return line_read;
299   }
300
301 #endif /* HAVE_LIBREADLINE */
302
303   static char buf[8192];
304   int len;
305
306   if (is_tty)
307     printf ("%s", prompt_string);
308   line_read = fgets (buf, sizeof buf, stdin);
309
310   if (line_read) {
311     len = strlen (line_read);
312     if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0';
313   }
314
315   return line_read;
316 }
317
318 #ifdef HAVE_LIBREADLINE
319 static char histfile[1024];
320 static int nr_history_lines = 0;
321 #endif
322
323 static void
324 initialize_readline (void)
325 {
326 #ifdef HAVE_LIBREADLINE
327   const char *home;
328
329   home = getenv ("HOME");
330   if (home) {
331     snprintf (histfile, sizeof histfile, "%s/.hivexsh", home);
332     using_history ();
333     (void) read_history (histfile);
334   }
335
336   rl_readline_name = "hivexsh";
337 #endif
338 }
339
340 static void
341 cleanup_readline (void)
342 {
343 #ifdef HAVE_LIBREADLINE
344   int fd;
345
346   if (histfile[0] != '\0') {
347     fd = open (histfile, O_WRONLY|O_CREAT, 0644);
348     if (fd == -1) {
349       perror (histfile);
350       return;
351     }
352     close (fd);
353
354     (void) append_history (nr_history_lines, histfile);
355   }
356 #endif
357 }
358
359 static void
360 add_history_line (const char *line)
361 {
362 #ifdef HAVE_LIBREADLINE
363   add_history (line);
364   nr_history_lines++;
365 #endif
366 }
367
368 static int
369 compare (const void *vp1, const void *vp2)
370 {
371   char * const *p1 = (char * const *) vp1;
372   char * const *p2 = (char * const *) vp2;
373   return strcasecmp (*p1, *p2);
374 }
375
376 static void
377 sort_strings (char **strings, int len)
378 {
379   qsort (strings, len, sizeof (char *), compare);
380 }
381
382 static int
383 get_xdigit (char c)
384 {
385   switch (c) {
386   case '0'...'9': return c - '0';
387   case 'a'...'f': return c - 'a' + 10;
388   case 'A'...'F': return c - 'A' + 10;
389   default: return -1;
390   }
391 }
392
393 static int
394 dispatch (char *cmd, char *args)
395 {
396   if (STRCASEEQ (cmd, "help"))
397     return cmd_help (args);
398   else if (STRCASEEQ (cmd, "load"))
399     return cmd_load (args);
400   else if (STRCASEEQ (cmd, "exit") ||
401            STRCASEEQ (cmd, "q") ||
402            STRCASEEQ (cmd, "quit")) {
403     quit = 1;
404     return 0;
405   }
406
407   /* If no hive file is loaded (!h) then only the small selection of
408    * commands above will work.
409    */
410   if (!h) {
411     fprintf (stderr, _("hivexsh: you must load a hive file first using 'load hivefile'\n"));
412     return -1;
413   }
414
415   if (STRCASEEQ (cmd, "add"))
416     return cmd_add (args);
417   else if (STRCASEEQ (cmd, "cd"))
418     return cmd_cd (args);
419   else if (STRCASEEQ (cmd, "close") || STRCASEEQ (cmd, "unload"))
420     return cmd_close (args);
421   else if (STRCASEEQ (cmd, "commit"))
422     return cmd_commit (args);
423   else if (STRCASEEQ (cmd, "del"))
424     return cmd_del (args);
425   else if (STRCASEEQ (cmd, "ls"))
426     return cmd_ls (args);
427   else if (STRCASEEQ (cmd, "lsval"))
428     return cmd_lsval (args);
429   else if (STRCASEEQ (cmd, "setval"))
430     return cmd_setval (args);
431   else {
432     fprintf (stderr, _("hivexsh: unknown command '%s', use 'help' for help summary\n"),
433              cmd);
434     return -1;
435   }
436 }
437
438 static int
439 cmd_load (char *hivefile)
440 {
441   if (STREQ (hivefile, "")) {
442     fprintf (stderr, _("hivexsh: load: no hive file name given to load\n"));
443     return -1;
444   }
445
446   if (h) hivex_close (h);
447   h = NULL;
448
449   free (loaded);
450   loaded = NULL;
451
452   cwd = 0;
453
454   h = hivex_open (hivefile, open_flags);
455   if (h == NULL) {
456     fprintf (stderr,
457              _(
458 "hivexsh: failed to open hive file: %s: %m\n"
459 "\n"
460 "If you think this file is a valid Windows binary hive file (_not_\n"
461 "a regedit *.reg file) then please run this command again using the\n"
462 "hivexsh option '-d' and attach the complete output _and_ the hive file\n"
463 "which fails into a bug report at https://bugzilla.redhat.com/\n"
464 "\n"),
465              hivefile);
466     return -1;
467   }
468
469   /* Get the basename of the file for the prompt. */
470   char *p = strrchr (hivefile, '/');
471   if (p)
472     loaded = strdup (p+1);
473   else
474     loaded = strdup (hivefile);
475   if (!loaded) {
476     perror ("strdup");
477     exit (EXIT_FAILURE);
478   }
479
480   cwd = hivex_root (h);
481
482   set_prompt_string ();
483
484   return 0;
485 }
486
487 static int
488 cmd_close (char *args)
489 {
490   if (STRNEQ (args, "")) {
491     fprintf (stderr, _("hivexsh: '%s' command should not be given arguments\n"),
492              "close");
493     return -1;
494   }
495
496   if (h) hivex_close (h);
497   h = NULL;
498
499   free (loaded);
500   loaded = NULL;
501
502   cwd = 0;
503
504   set_prompt_string ();
505
506   return 0;
507 }
508
509 static int
510 cmd_commit (char *path)
511 {
512   if (STREQ (path, ""))
513     path = NULL;
514
515   if (hivex_commit (h, path, 0) == -1) {
516     perror ("hivexsh: commit");
517     return -1;
518   }
519
520   return 0;
521 }
522
523 static int
524 cmd_cd (char *path)
525 {
526   if (STREQ (path, "")) {
527     print_node_path (cwd, stdout);
528     fputc ('\n', stdout);
529     return 0;
530   }
531
532   if (path[0] == '\\' && path[1] == '\\') {
533     fprintf (stderr, _("%s: %s: \\ characters in path are doubled - are you escaping the path parameter correctly?\n"), "hivexsh", path);
534     return -1;
535   }
536
537   hive_node_h new_cwd = cwd;
538   hive_node_h root = hivex_root (h);
539
540   if (path[0] == '\\') {
541     new_cwd = root;
542     path++;
543   }
544
545   while (path[0]) {
546     size_t len = strcspn (path, "\\");
547     if (len == 0) {
548       path++;
549       continue;
550     }
551
552     char *elem = path;
553     path = path[len] == '\0' ? &path[len] : &path[len+1];
554     elem[len] = '\0';
555
556     if (len == 1 && STREQ (elem, "."))
557       continue;
558
559     if (len == 2 && STREQ (elem, "..")) {
560       if (new_cwd != root)
561         new_cwd = hivex_node_parent (h, new_cwd);
562       continue;
563     }
564
565     errno = 0;
566     new_cwd = hivex_node_get_child (h, new_cwd, elem);
567     if (new_cwd == 0) {
568       if (errno)
569         perror ("hivexsh: cd");
570       else
571         fprintf (stderr, _("hivexsh: cd: subkey '%s' not found\n"),
572                  elem);
573       return -1;
574     }
575   }
576
577   if (new_cwd != cwd) {
578     cwd = new_cwd;
579     set_prompt_string ();
580   }
581
582   return 0;
583 }
584
585 static int
586 cmd_help (char *args)
587 {
588   printf (_(
589 "Navigate through the hive's keys using the 'cd' command, as if it\n"
590 "contained a filesystem, and use 'ls' to list the subkeys of the\n"
591 "current key.  Full documentation is in the hivexsh(1) manual page.\n"));
592
593   return 0;
594 }
595
596 static int
597 cmd_ls (char *args)
598 {
599   if (STRNEQ (args, "")) {
600     fprintf (stderr, _("hivexsh: '%s' command should not be given arguments\n"),
601              "ls");
602     return -1;
603   }
604
605   /* Get the subkeys. */
606   hive_node_h *children = hivex_node_children (h, cwd);
607   if (children == NULL) {
608     perror ("ls");
609     return -1;
610   }
611
612   /* Get names for each subkey. */
613   size_t len;
614   for (len = 0; children[len] != 0; ++len)
615     ;
616
617   char **names = calloc (len, sizeof (char *));
618   if (names == NULL) {
619     perror ("malloc");
620     exit (EXIT_FAILURE);
621   }
622
623   int ret = -1;
624   size_t i;
625   for (i = 0; i < len; ++i) {
626     names[i] = hivex_node_name (h, children[i]);
627     if (names[i] == NULL) {
628       perror ("hivex_node_name");
629       goto error;
630     }
631   }
632
633   /* Sort the names. */
634   sort_strings (names, len);
635
636   for (i = 0; i < len; ++i)
637     printf ("%s\n", names[i]);
638
639   ret = 0;
640  error:
641   free (children);
642   for (i = 0; i < len; ++i)
643     free (names[i]);
644   free (names);
645   return ret;
646 }
647
648 static int
649 cmd_lsval (char *key)
650 {
651   if (STRNEQ (key, "")) {
652     hive_value_h value;
653
654     errno = 0;
655     if (STREQ (key, "@"))       /* default key written as "@" */
656       value = hivex_node_get_value (h, cwd, "");
657     else
658       value = hivex_node_get_value (h, cwd, key);
659
660     if (value == 0) {
661       if (errno)
662         goto error;
663       /* else key not found */
664       fprintf (stderr, _("%s: %s: key not found\n"), "hivexsh", key);
665       return -1;
666     }
667
668     /* Print the value. */
669     hive_type t;
670     size_t len;
671     if (hivex_value_type (h, value, &t, &len) == -1)
672       goto error;
673
674     switch (t) {
675     case hive_t_string:
676     case hive_t_expand_string:
677     case hive_t_link: {
678       char *str = hivex_value_string (h, value);
679       if (!str)
680         goto error;
681
682       puts (str); /* note: this adds a single \n character */
683       free (str);
684       break;
685     }
686
687     case hive_t_dword:
688     case hive_t_dword_be: {
689       int32_t j = hivex_value_dword (h, value);
690       printf ("%" PRIi32 "\n", j);
691       break;
692     }
693
694     case hive_t_qword: {
695       int64_t j = hivex_value_qword (h, value);
696       printf ("%" PRIi64 "\n", j);
697       break;
698     }
699
700     case hive_t_multiple_strings: {
701       char **strs = hivex_value_multiple_strings (h, value);
702       if (!strs)
703         goto error;
704       size_t j;
705       for (j = 0; strs[j] != NULL; ++j) {
706         puts (strs[j]);
707         free (strs[j]);
708       }
709       free (strs);
710       break;
711     }
712
713     case hive_t_none:
714     case hive_t_binary:
715     case hive_t_resource_list:
716     case hive_t_full_resource_description:
717     case hive_t_resource_requirements_list:
718     default: {
719       char *data = hivex_value_value (h, value, &t, &len);
720       if (!data)
721         goto error;
722
723       if (fwrite (data, 1, len, stdout) != len)
724         goto error;
725
726       free (data);
727       break;
728     }
729     } /* switch */
730   } else {
731     /* No key specified, so print all keys in this node.  We do this
732      * in a format which looks like the output of regedit, although
733      * this isn't a particularly useful format.
734      */
735     hive_value_h *values;
736
737     values = hivex_node_values (h, cwd);
738     if (values == NULL)
739       goto error;
740
741     size_t i;
742     for (i = 0; values[i] != 0; ++i) {
743       char *key = hivex_value_key (h, values[i]);
744       if (!key) goto error;
745
746       if (*key) {
747         putchar ('"');
748         size_t j;
749         for (j = 0; key[j] != 0; ++j) {
750           if (key[j] == '"' || key[j] == '\\')
751             putchar ('\\');
752           putchar (key[j]);
753         }
754         putchar ('"');
755       } else
756         printf ("\"@\"");       /* default key in regedit files */
757       putchar ('=');
758       free (key);
759
760       hive_type t;
761       size_t len;
762       if (hivex_value_type (h, values[i], &t, &len) == -1)
763         goto error;
764
765       switch (t) {
766       case hive_t_string:
767       case hive_t_expand_string:
768       case hive_t_link: {
769         char *str = hivex_value_string (h, values[i]);
770         if (!str)
771           goto error;
772
773         if (t != hive_t_string)
774           printf ("str(%d):", t);
775         putchar ('"');
776         size_t j;
777         for (j = 0; str[j] != 0; ++j) {
778           if (str[j] == '"' || str[j] == '\\')
779             putchar ('\\');
780           putchar (str[j]);
781         }
782         putchar ('"');
783         free (str);
784         break;
785       }
786
787       case hive_t_dword:
788       case hive_t_dword_be: {
789         int32_t j = hivex_value_dword (h, values[i]);
790         printf ("dword:%08" PRIx32, j);
791         break;
792       }
793
794       case hive_t_qword: /* sic */
795       case hive_t_none:
796       case hive_t_binary:
797       case hive_t_multiple_strings:
798       case hive_t_resource_list:
799       case hive_t_full_resource_description:
800       case hive_t_resource_requirements_list:
801       default: {
802         char *data = hivex_value_value (h, values[i], &t, &len);
803         if (!data)
804           goto error;
805
806         printf ("hex(%d):", t);
807         size_t j;
808         for (j = 0; j < len; ++j) {
809           if (j > 0)
810             putchar (',');
811           printf ("%02x", data[j]);
812         }
813         break;
814       }
815       } /* switch */
816
817       putchar ('\n');
818     } /* for */
819
820     free (values);
821   }
822
823   return 0;
824
825  error:
826   perror ("hivexsh: lsval");
827   return -1;
828 }
829
830 static int
831 cmd_setval (char *nrvals_str)
832 {
833   strtol_error xerr;
834
835   /* Parse number of values. */
836   long nrvals;
837   xerr = xstrtol (nrvals_str, NULL, 0, &nrvals, "");
838   if (xerr != LONGINT_OK) {
839     fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"),
840              "setval", "nrvals", "xstrtol", xerr);
841     return -1;
842   }
843   if (nrvals < 0 || nrvals > 1000) {
844     fprintf (stderr, _("%s: %s: integer out of range\n"),
845              "setval", "nrvals");
846     return -1;
847   }
848
849   struct hive_set_value *values =
850     calloc (nrvals, sizeof (struct hive_set_value));
851   if (values == NULL) {
852     perror ("calloc");
853     exit (EXIT_FAILURE);
854   }
855
856   int ret = -1;
857
858   /* Read nrvals * 2 lines of input, nrvals * (key, value) pairs, as
859    * explained in the man page.
860    */
861   int i, j;
862   for (i = 0; i < nrvals; ++i) {
863     /* Read key. */
864     char *buf = rl_gets ("  key> ");
865     if (!buf) {
866       fprintf (stderr, _("hivexsh: setval: unexpected end of input\n"));
867       quit = 1;
868       goto error;
869     }
870
871     /* Note that buf will be overwritten by the next call to rl_gets. */
872     if (STREQ (buf, "@"))
873       values[i].key = strdup ("");
874     else
875       values[i].key = strdup (buf);
876     if (values[i].key == NULL) {
877       perror ("strdup");
878       exit (EXIT_FAILURE);
879     }
880
881     /* Read value. */
882     buf = rl_gets ("value> ");
883     if (!buf) {
884       fprintf (stderr, _("hivexsh: setval: unexpected end of input\n"));
885       quit = 1;
886       goto error;
887     }
888
889     if (STREQ (buf, "none")) {
890       values[i].t = hive_t_none;
891       values[i].len = 0;
892     }
893     else if (STRPREFIX (buf, "string:")) {
894       buf += 7;
895       values[i].t = hive_t_string;
896       int nr_chars = strlen (buf);
897       values[i].len = 2 * (nr_chars + 1);
898       values[i].value = malloc (values[i].len);
899       if (!values[i].value) {
900         perror ("malloc");
901         exit (EXIT_FAILURE);
902       }
903       for (j = 0; j <= /* sic */ nr_chars; ++j) {
904         if (buf[j] & 0x80) {
905           fprintf (stderr, _("hivexsh: string(utf16le): only 7 bit ASCII strings are supported for input\n"));
906           goto error;
907         }
908         values[i].value[2*j] = buf[j];
909         values[i].value[2*j+1] = '\0';
910       }
911     }
912     else if (STRPREFIX (buf, "expandstring:")) {
913       buf += 13;
914       values[i].t = hive_t_string;
915       int nr_chars = strlen (buf);
916       values[i].len = 2 * (nr_chars + 1);
917       values[i].value = malloc (values[i].len);
918       if (!values[i].value) {
919         perror ("malloc");
920         exit (EXIT_FAILURE);
921       }
922       for (j = 0; j <= /* sic */ nr_chars; ++j) {
923         if (buf[j] & 0x80) {
924           fprintf (stderr, _("hivexsh: string(utf16le): only 7 bit ASCII strings are supported for input\n"));
925           goto error;
926         }
927         values[i].value[2*j] = buf[j];
928         values[i].value[2*j+1] = '\0';
929       }
930     }
931     else if (STRPREFIX (buf, "dword:")) {
932       buf += 6;
933       values[i].t = hive_t_dword;
934       values[i].len = 4;
935       values[i].value = malloc (4);
936       if (!values[i].value) {
937         perror ("malloc");
938         exit (EXIT_FAILURE);
939       }
940       long n;
941       xerr = xstrtol (buf, NULL, 0, &n, "");
942       if (xerr != LONGINT_OK) {
943         fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"),
944                  "setval", "dword", "xstrtol", xerr);
945         goto error;
946       }
947       if (n < 0 || n > UINT32_MAX) {
948         fprintf (stderr, _("%s: %s: integer out of range\n"),
949                  "setval", "dword");
950         goto error;
951       }
952       uint32_t u32 = htole32 (n);
953       memcpy (values[i].value, &u32, 4);
954     }
955     else if (STRPREFIX (buf, "qword:")) {
956       buf += 6;
957       values[i].t = hive_t_qword;
958       values[i].len = 8;
959       values[i].value = malloc (8);
960       if (!values[i].value) {
961         perror ("malloc");
962         exit (EXIT_FAILURE);
963       }
964       long long n;
965       xerr = xstrtoll (buf, NULL, 0, &n, "");
966       if (xerr != LONGINT_OK) {
967         fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"),
968                  "setval", "dword", "xstrtoll", xerr);
969         goto error;
970       }
971 #if 0
972       if (n < 0 || n > UINT64_MAX) {
973         fprintf (stderr, _("%s: %s: integer out of range\n"),
974                  "setval", "dword");
975         goto error;
976       }
977 #endif
978       uint64_t u64 = htole64 (n);
979       memcpy (values[i].value, &u64, 4);
980     }
981     else if (STRPREFIX (buf, "hex:")) {
982       /* Read the type. */
983       buf += 4;
984       size_t len = strcspn (buf, ":");
985       char *nextbuf;
986       if (buf[len] == '\0')     /* "hex:t" */
987         nextbuf = &buf[len];
988       else {                    /* "hex:t:..." */
989         buf[len] = '\0';
990         nextbuf = &buf[len+1];
991       }
992
993       long t;
994       xerr = xstrtol (buf, NULL, 0, &t, "");
995       if (xerr != LONGINT_OK) {
996         fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"),
997                  "setval", "hex", "xstrtol", xerr);
998         goto error;
999       }
1000       if (t < 0 || t > UINT32_MAX) {
1001         fprintf (stderr, _("%s: %s: integer out of range\n"),
1002                  "setval", "hex");
1003         goto error;
1004       }
1005       values[i].t = t;
1006
1007       /* Read the hex data. */
1008       buf = nextbuf;
1009
1010       /* The allocation length is an overestimate, but it doesn't matter. */
1011       values[i].value = malloc (1 + strlen (buf) / 2);
1012       if (!values[i].value) {
1013         perror ("malloc");
1014         exit (EXIT_FAILURE);
1015       }
1016       values[i].len = 0;
1017
1018       while (*buf) {
1019         int c = 0;
1020
1021         for (j = 0; *buf && j < 2; buf++) {
1022           if (c_isxdigit (*buf)) { /* NB: ignore non-hex digits. */
1023             c <<= 4;
1024             c |= get_xdigit (*buf);
1025             j++;
1026           }
1027         }
1028
1029         if (j == 2) values[i].value[values[i].len++] = c;
1030         else if (j == 1) {
1031           fprintf (stderr, _("hivexsh: setval: trailing garbage after hex string\n"));
1032           goto error;
1033         }
1034       }
1035     }
1036     else {
1037       fprintf (stderr,
1038                _("hivexsh: setval: cannot parse value string, please refer to the man page hivexsh(1) for help: %s\n"),
1039                buf);
1040       goto error;
1041     }
1042   }
1043
1044   ret = hivex_node_set_values (h, cwd, nrvals, values, 0);
1045
1046  error:
1047   /* Free values array. */
1048   for (i = 0; i < nrvals; ++i) {
1049     free (values[i].key);
1050     free (values[i].value);
1051   }
1052   free (values);
1053
1054   return ret;
1055 }
1056
1057 static int
1058 cmd_del (char *args)
1059 {
1060   if (STRNEQ (args, "")) {
1061     fprintf (stderr, _("hivexsh: '%s' command should not be given arguments\n"),
1062              "del");
1063     return -1;
1064   }
1065
1066   if (cwd == hivex_root (h)) {
1067     fprintf (stderr, _("hivexsh: del: the root node cannot be deleted\n"));
1068     return -1;
1069   }
1070
1071   hive_node_h new_cwd = hivex_node_parent (h, cwd);
1072
1073   if (hivex_node_delete_child (h, cwd) == -1) {
1074     perror ("hivexsh: del");
1075     return -1;
1076   }
1077
1078   cwd = new_cwd;
1079   set_prompt_string ();
1080   return 0;
1081 }
1082
1083 static int
1084 cmd_add (char *name)
1085 {
1086   hive_node_h node = hivex_node_add_child (h, cwd, name);
1087   if (node == 0) {
1088     perror ("hivexsh: add");
1089     return -1;
1090   }
1091   return 0;
1092 }