hivex: Add HIVEX_OPEN_WRITE flag to allow hive to be opened for writing.
[libguestfs.git] / hivex / hivexml.c
1 /* hivexml - Convert Windows Registry "hive" to XML file.
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 <unistd.h>
27 #include <errno.h>
28
29 #include <libxml/xmlwriter.h>
30
31 #include "hivex.h"
32
33 #ifdef HAVE_GETTEXT
34 #include "gettext.h"
35 #define _(str) dgettext(PACKAGE, (str))
36 //#define N_(str) dgettext(PACKAGE, (str))
37 #else
38 #define _(str) str
39 //#define N_(str) str
40 #endif
41
42 /* Callback functions. */
43 static int node_start (hive_h *, void *, hive_node_h, const char *name);
44 static int node_end (hive_h *, void *, hive_node_h, const char *name);
45 static int value_string (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *str);
46 static int value_multiple_strings (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, char **argv);
47 static int value_string_invalid_utf16 (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *str);
48 static int value_dword (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int32_t);
49 static int value_qword (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int64_t);
50 static int value_binary (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
51 static int value_none (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
52 static int value_other (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
53
54 static struct hivex_visitor visitor = {
55   .node_start = node_start,
56   .node_end = node_end,
57   .value_string = value_string,
58   .value_multiple_strings = value_multiple_strings,
59   .value_string_invalid_utf16 = value_string_invalid_utf16,
60   .value_dword = value_dword,
61   .value_qword = value_qword,
62   .value_binary = value_binary,
63   .value_none = value_none,
64   .value_other = value_other
65 };
66
67 #define XML_CHECK(proc, args)                                           \
68   do {                                                                  \
69     if ((proc args) == -1) {                                            \
70       fprintf (stderr, _("%s: failed to write XML document\n"), #proc); \
71       exit (EXIT_FAILURE);                                              \
72     }                                                                   \
73   } while (0)
74
75 int
76 main (int argc, char *argv[])
77 {
78   setlocale (LC_ALL, "");
79   bindtextdomain (PACKAGE, LOCALEBASEDIR);
80   textdomain (PACKAGE);
81
82   int c;
83   int open_flags = 0;
84   int visit_flags = 0;
85
86   while ((c = getopt (argc, argv, "dk")) != EOF) {
87     switch (c) {
88     case 'd':
89       open_flags |= HIVEX_OPEN_DEBUG;
90       break;
91     case 'k':
92       visit_flags |= HIVEX_VISIT_SKIP_BAD;
93       break;
94     default:
95       fprintf (stderr, "hivexml [-dk] regfile > output.xml\n");
96       exit (EXIT_FAILURE);
97     }
98   }
99
100   if (optind + 1 != argc) {
101     fprintf (stderr, _("hivexml: missing name of input file\n"));
102     exit (EXIT_FAILURE);
103   }
104
105   hive_h *h = hivex_open (argv[optind], open_flags);
106   if (h == NULL) {
107     perror (argv[optind]);
108     exit (EXIT_FAILURE);
109   }
110
111   /* Note both this macro, and xmlTextWriterStartDocument leak memory.  There
112    * doesn't seem to be any way to recover that memory, but it's not a
113    * large amount.
114    */
115   LIBXML_TEST_VERSION;
116
117   xmlTextWriterPtr writer;
118   writer = xmlNewTextWriterFilename ("/dev/stdout", 0);
119   if (writer == NULL) {
120     fprintf (stderr, _("xmlNewTextWriterFilename: failed to create XML writer\n"));
121     exit (EXIT_FAILURE);
122   }
123
124   XML_CHECK (xmlTextWriterStartDocument, (writer, NULL, "utf-8", NULL));
125   XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "hive"));
126
127   if (hivex_visit (h, &visitor, sizeof visitor, writer, visit_flags) == -1) {
128     perror (argv[optind]);
129     exit (EXIT_FAILURE);
130   }
131
132   if (hivex_close (h) == -1) {
133     perror (argv[optind]);
134     exit (EXIT_FAILURE);
135   }
136
137   XML_CHECK (xmlTextWriterEndElement, (writer));
138   XML_CHECK (xmlTextWriterEndDocument, (writer));
139   xmlFreeTextWriter (writer);
140
141   exit (EXIT_SUCCESS);
142 }
143
144 static int
145 node_start (hive_h *h, void *writer_v, hive_node_h node, const char *name)
146 {
147   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
148   XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "node"));
149   XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "name", BAD_CAST name));
150   return 0;
151 }
152
153 static int
154 node_end (hive_h *h, void *writer_v, hive_node_h node, const char *name)
155 {
156   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
157   XML_CHECK (xmlTextWriterEndElement, (writer));
158   return 0;
159 }
160
161 static void
162 start_value (xmlTextWriterPtr writer,
163              const char *key, const char *type, const char *encoding)
164 {
165   XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "value"));
166   XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "type", BAD_CAST type));
167   if (encoding)
168     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "encoding", BAD_CAST encoding));
169   if (*key)
170     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "key", BAD_CAST key));
171   else                          /* default key */
172     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "default", BAD_CAST "1"));
173 }
174
175 static void
176 end_value (xmlTextWriterPtr writer)
177 {
178   XML_CHECK (xmlTextWriterEndElement, (writer));
179 }
180
181 static int
182 value_string (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
183               hive_type t, size_t len, const char *key, const char *str)
184 {
185   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
186   const char *type;
187
188   switch (t) {
189   case hive_t_string: type = "string"; break;
190   case hive_t_expand_string: type = "expand"; break;
191   case hive_t_link: type = "link"; break;
192
193   case hive_t_none:
194   case hive_t_binary:
195   case hive_t_dword:
196   case hive_t_dword_be:
197   case hive_t_multiple_strings:
198   case hive_t_resource_list:
199   case hive_t_full_resource_description:
200   case hive_t_resource_requirements_list:
201   case hive_t_qword:
202     abort ();                   /* internal error - should not happen */
203
204   default:
205     type = "unknown";
206   }
207
208   start_value (writer, key, type, NULL);
209   XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST str));
210   end_value (writer);
211   return 0;
212 }
213
214 static int
215 value_multiple_strings (hive_h *h, void *writer_v, hive_node_h node,
216                         hive_value_h value, hive_type t, size_t len,
217                         const char *key, char **argv)
218 {
219   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
220   start_value (writer, key, "string-list", NULL);
221
222   size_t i;
223   for (i = 0; argv[i] != NULL; ++i) {
224     XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "string"));
225     XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST argv[i]));
226     XML_CHECK (xmlTextWriterEndElement, (writer));
227   }
228
229   end_value (writer);
230   return 0;
231 }
232
233 static int
234 value_string_invalid_utf16 (hive_h *h, void *writer_v, hive_node_h node,
235                             hive_value_h value, hive_type t, size_t len,
236                             const char *key,
237                             const char *str /* original data */)
238 {
239   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
240   const char *type;
241
242   switch (t) {
243   case hive_t_string: type = "bad-string"; break;
244   case hive_t_expand_string: type = "bad-expand"; break;
245   case hive_t_link: type = "bad-link"; break;
246   case hive_t_multiple_strings: type = "bad-string-list"; break;
247
248   case hive_t_none:
249   case hive_t_binary:
250   case hive_t_dword:
251   case hive_t_dword_be:
252   case hive_t_resource_list:
253   case hive_t_full_resource_description:
254   case hive_t_resource_requirements_list:
255   case hive_t_qword:
256     abort ();                   /* internal error - should not happen */
257
258   default:
259     type = "unknown";
260   }
261
262   start_value (writer, key, type, "base64");
263   XML_CHECK (xmlTextWriterWriteBase64, (writer, str, 0, len));
264   end_value (writer);
265
266   return 0;
267 }
268
269 static int
270 value_dword (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
271              hive_type t, size_t len, const char *key, int32_t v)
272 {
273   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
274   start_value (writer, key, "int32", NULL);
275   XML_CHECK (xmlTextWriterWriteFormatString, (writer, "%" PRIi32, v));
276   end_value (writer);
277   return 0;
278 }
279
280 static int
281 value_qword (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
282              hive_type t, size_t len, const char *key, int64_t v)
283 {
284   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
285   start_value (writer, key, "int64", NULL);
286   XML_CHECK (xmlTextWriterWriteFormatString, (writer, "%" PRIi64, v));
287   end_value (writer);
288   return 0;
289 }
290
291 static int
292 value_binary (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
293               hive_type t, size_t len, const char *key, const char *v)
294 {
295   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
296   start_value (writer, key, "binary", "base64");
297   XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
298   end_value (writer);
299   return 0;
300 }
301
302 static int
303 value_none (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
304             hive_type t, size_t len, const char *key, const char *v)
305 {
306   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
307   start_value (writer, key, "none", "base64");
308   if (len > 0) XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
309   end_value (writer);
310   return 0;
311 }
312
313 static int
314 value_other (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
315              hive_type t, size_t len, const char *key, const char *v)
316 {
317   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
318   const char *type;
319
320   switch (t) {
321   case hive_t_none:
322   case hive_t_binary:
323   case hive_t_dword:
324   case hive_t_dword_be:
325   case hive_t_qword:
326   case hive_t_string:
327   case hive_t_expand_string:
328   case hive_t_link:
329   case hive_t_multiple_strings:
330     abort ();                   /* internal error - should not happen */
331
332   case hive_t_resource_list: type = "resource-list"; break;
333   case hive_t_full_resource_description: type = "resource-description"; break;
334   case hive_t_resource_requirements_list: type = "resource-requirements"; break;
335
336   default:
337     type = "unknown";
338   }
339
340   start_value (writer, key, type, "base64");
341   if (len > 0) XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
342   end_value (writer);
343
344   return 0;
345 }