Fixed hive import bug.
[reactos.git] / reactos / ntoskrnl / cm / import.c
1 /* $Id: import.c,v 1.3 2001/09/04 21:05:26 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/import.c
6 * PURPOSE: Registry functions
7 * PROGRAMMERS: Rex Jolliff
8 */
9
10 #include <ctype.h>
11
12 #include <ddk/ntddk.h>
13 #include <roscfg.h>
14 #include <internal/ob.h>
15 #include <limits.h>
16 #include <string.h>
17 #include <internal/pool.h>
18 #include <internal/registry.h>
19
20 #define NDEBUG
21 #include <internal/debug.h>
22
23 #include "cm.h"
24
25 static PCHAR
26 checkAndSkipMagic (PCHAR regChunk)
27 {
28 if (strncmp (regChunk,
29 REGISTRY_FILE_MAGIC,
30 strlen (REGISTRY_FILE_MAGIC)) != 0)
31 {
32 CPRINT ("incorrect magic number in registry chunk. expected: %s got:%.*s\n",
33 REGISTRY_FILE_MAGIC,
34 strlen (REGISTRY_FILE_MAGIC),
35 regChunk);
36 return 0;
37 }
38 regChunk += strlen (REGISTRY_FILE_MAGIC);
39 DPRINT ("Found regsitry chunk magic value\n");
40
41 return regChunk;
42 }
43
44 static PCHAR
45 skipWhitespaceInChunk (PCHAR regChunk)
46 {
47 while (*regChunk && isspace (*regChunk))
48 regChunk++;
49
50 return *regChunk ? regChunk : 0;
51 }
52
53 static int
54 computeKeyNameSize (PCHAR regChunk)
55 {
56 int copyCount = 0;
57
58 while (*regChunk != 0 && *regChunk != ']')
59 {
60 copyCount++;
61 regChunk++;
62 }
63
64 return copyCount;
65 }
66
67 static BOOL
68 allocateKeyName (PUNICODE_STRING newKeyName, int newKeySize)
69 {
70 if (newKeyName->MaximumLength < (newKeySize + 1) * sizeof (WCHAR))
71 {
72 if (newKeyName->Buffer != 0)
73 ExFreePool (newKeyName->Buffer);
74 newKeyName->Length = 0;
75 newKeyName->MaximumLength = (newKeySize + 1) * sizeof (WCHAR);
76 newKeyName->Buffer = ExAllocatePool (NonPagedPool, newKeyName->MaximumLength);
77 if (newKeyName->Buffer == 0)
78 {
79 CPRINT ("Could not allocate space for key name\n");
80 return FALSE;
81 }
82 newKeyName->Buffer [0] = 0;
83 }
84 else
85 {
86 newKeyName->Length = 0;
87 newKeyName->Buffer [0] = 0;
88 }
89
90 return TRUE;
91 }
92
93 static PCHAR
94 skipToNextKeyInChunk (PCHAR regChunk)
95 {
96 while (*regChunk != 0 && *regChunk != '[')
97 {
98 while (*regChunk != 0 && *regChunk != '\n')
99 {
100 regChunk++;
101 }
102 regChunk++;
103 }
104
105 return *regChunk ? regChunk : 0;
106 }
107
108 static PCHAR
109 getKeyNameFromChunk (PCHAR regChunk, PUNICODE_STRING newKeyName)
110 {
111 int index = 0;
112
113 while (*regChunk != 0 && *regChunk != ']')
114 {
115 newKeyName->Buffer [index++] = *regChunk++;
116 }
117 newKeyName->Buffer [index] = '\0';
118 newKeyName->Length = index * sizeof (WCHAR);
119
120 return *regChunk ? regChunk : 0;
121 }
122
123 static HANDLE
124 createNewKey (PUNICODE_STRING newKeyName)
125 {
126 NTSTATUS status;
127 OBJECT_ATTRIBUTES attributes;
128 HANDLE handleToReturn;
129
130 DPRINT ("Creating key (%wZ)\n", newKeyName);
131 InitializeObjectAttributes (&attributes,
132 newKeyName,
133 0,
134 0,
135 NULL);
136 status = NtCreateKey (&handleToReturn,
137 KEY_ALL_ACCESS,
138 &attributes,
139 0,
140 NULL,
141 REG_OPTION_VOLATILE,
142 NULL);
143 if (!NT_SUCCESS(status))
144 {
145 CPRINT ("Could not crete key (%wZ)\n", newKeyName);
146 return INVALID_HANDLE_VALUE;
147 }
148
149 return handleToReturn;
150 }
151
152 static PCHAR
153 skipToNextKeyValueInChunk (PCHAR regChunk)
154 {
155 while (*regChunk != 0 && *regChunk != '\n')
156 regChunk++;
157 regChunk = skipWhitespaceInChunk (regChunk);
158
159 return regChunk;
160 }
161
162 static int
163 computeKeyValueNameSize (PCHAR regChunk)
164 {
165 int size = 0;
166
167 if (*regChunk != '\"')
168 return 0;
169 regChunk++;
170 while (*regChunk != 0 && *regChunk != '\"')
171 {
172 size++;
173 regChunk++;
174 }
175
176 return regChunk ? size : 0;
177 }
178
179 static PCHAR
180 getKeyValueNameFromChunk (PCHAR regChunk, PUNICODE_STRING newKeyName)
181 {
182 int index = 0;
183
184 regChunk++;
185 while (*regChunk != 0 && *regChunk != '\"')
186 {
187 newKeyName->Buffer [index++] = *regChunk++;
188 }
189 newKeyName->Buffer [index] = '\0';
190 newKeyName->Length = index * sizeof (WCHAR);
191 regChunk++;
192
193 return *regChunk ? regChunk : 0;
194 }
195
196 static PCHAR
197 getKeyValueTypeFromChunk (PCHAR regChunk, PCHAR dataFormat, int *keyValueType)
198 {
199 if (*regChunk == '\"')
200 {
201 strcpy (dataFormat, "string");
202 *keyValueType = REG_SZ;
203 }
204 else if (strncmp (regChunk, "hex", 3) == 0)
205 {
206 strcpy (dataFormat, "hex");
207 regChunk += 3;
208 if (*regChunk == '(')
209 {
210 regChunk++;
211 *keyValueType = atoi (regChunk);
212 while (*regChunk != 0 && *regChunk != ')')
213 regChunk++;
214 regChunk++;
215 }
216 else
217 *keyValueType = REG_BINARY;
218 if (*regChunk == ':')
219 regChunk++;
220 }
221 else
222 {
223 UNIMPLEMENTED;
224 }
225
226 return *regChunk ? regChunk : 0;
227 }
228
229 static int
230 computeKeyValueDataSize (PCHAR regChunk, PCHAR dataFormat)
231 {
232 int dataSize = 0;
233
234 if (strcmp (dataFormat, "string") == 0)
235 {
236 regChunk++;
237 while (*regChunk != 0 && *regChunk != '\"')
238 {
239 dataSize++;
240 dataSize++;
241 regChunk++;
242 }
243 dataSize++;
244 dataSize++;
245 }
246 else if (strcmp (dataFormat, "hex") == 0)
247 {
248 while (*regChunk != 0 && isxdigit(*regChunk))
249 {
250 regChunk++;
251 regChunk++;
252 dataSize++;
253 if (*regChunk == ',')
254 {
255 regChunk++;
256 if (*regChunk == '\\')
257 {
258 regChunk++;
259 regChunk = skipWhitespaceInChunk (regChunk);
260 }
261 }
262 }
263 }
264 else
265 {
266 UNIMPLEMENTED;
267 }
268
269 return dataSize;
270 }
271
272 static BOOL
273 allocateDataBuffer (PVOID * data, int * dataBufferSize, int dataSize)
274 {
275 if (*dataBufferSize < dataSize)
276 {
277 if (*dataBufferSize > 0)
278 ExFreePool (*data);
279 *data = ExAllocatePool (NonPagedPool, dataSize);
280 *dataBufferSize = dataSize;
281 }
282
283 return TRUE;
284 }
285
286 static PCHAR
287 getKeyValueDataFromChunk (PCHAR regChunk, PCHAR dataFormat, PCHAR data)
288 {
289 char dataValue;
290 PWCHAR ptr;
291
292 if (strcmp (dataFormat, "string") == 0)
293 {
294 /* convert quoted string to zero-terminated Unicode string */
295 ptr = (PWCHAR)data;
296 regChunk++;
297 while (*regChunk != 0 && *regChunk != '\"')
298 {
299 *ptr++ = (WCHAR)*regChunk++;
300 }
301 *ptr = 0;
302 regChunk++;
303 }
304 else if (strcmp (dataFormat, "hex") == 0)
305 {
306 while (*regChunk != 0 && isxdigit (*regChunk))
307 {
308 dataValue = (isdigit (*regChunk) ? *regChunk - '0' :
309 tolower(*regChunk) - 'a') << 4;
310 regChunk++;
311 dataValue += (isdigit (*regChunk) ? *regChunk - '0' :
312 tolower(*regChunk) - 'a');
313 regChunk++;
314 *data++ = dataValue;
315 if (*regChunk == ',')
316 {
317 regChunk++;
318 if (*regChunk == '\\')
319 {
320 regChunk++;
321 regChunk = skipWhitespaceInChunk (regChunk);
322 }
323 }
324 }
325 }
326 else
327 {
328 UNIMPLEMENTED;
329 }
330
331 return *regChunk ? regChunk : 0;
332 }
333
334 static BOOL
335 setKeyValue (HANDLE currentKey,
336 PUNICODE_STRING newValueName,
337 ULONG keyValueType,
338 PVOID data,
339 ULONG dataSize)
340 {
341 NTSTATUS status;
342
343 DPRINT ("Adding value (%wZ) to current key, with data type %d size %d\n",
344 newValueName,
345 keyValueType,
346 dataSize);
347 status = NtSetValueKey (currentKey,
348 newValueName,
349 0,
350 keyValueType,
351 data,
352 dataSize);
353 if (!NT_SUCCESS(status))
354 {
355 CPRINT ("could not set key value, rc:%08x\n", status);
356 return FALSE;
357 }
358
359 return TRUE;
360 }
361
362 VOID
363 CmImportHive(PCHAR ChunkBase,
364 ULONG ChunkSize)
365 {
366 HANDLE currentKey = INVALID_HANDLE_VALUE;
367 int newKeySize;
368 UNICODE_STRING newKeyName = {0, 0, 0};
369 char dataFormat [10];
370 int keyValueType;
371 int dataSize = 0;
372 int dataBufferSize = 0;
373 PVOID data = 0;
374 PCHAR regChunk;
375
376 DPRINT("ChunkBase %p ChunkSize %lx\n", ChunkBase, ChunkSize);
377
378 regChunk = checkAndSkipMagic (ChunkBase);
379 if (regChunk == 0)
380 return;
381
382 while (regChunk != 0 && *regChunk != 0 && (((ULONG)regChunk-(ULONG)ChunkBase) < ChunkSize))
383 {
384 regChunk = skipWhitespaceInChunk (regChunk);
385 if (regChunk == 0)
386 continue;
387
388 if (*regChunk == '[')
389 {
390 if (currentKey != INVALID_HANDLE_VALUE)
391 {
392 DPRINT("Closing current key: 0x%lx\n", currentKey);
393 NtClose (currentKey);
394 currentKey = INVALID_HANDLE_VALUE;
395 }
396
397 regChunk++;
398
399 newKeySize = computeKeyNameSize (regChunk);
400 if (!allocateKeyName (&newKeyName, newKeySize))
401 {
402 regChunk = 0;
403 continue;
404 }
405
406 regChunk = getKeyNameFromChunk (regChunk, &newKeyName);
407 if (regChunk == 0)
408 continue;
409
410 currentKey = createNewKey (&newKeyName);
411 if (currentKey == INVALID_HANDLE_VALUE)
412 {
413 regChunk = skipToNextKeyInChunk (regChunk);
414 continue;
415 }
416
417 regChunk++;
418 }
419 else
420 {
421 if (currentKey == INVALID_HANDLE_VALUE)
422 {
423 regChunk = skipToNextKeyInChunk (regChunk);
424 continue;
425 }
426
427 newKeySize = computeKeyValueNameSize (regChunk);
428 if (!allocateKeyName (&newKeyName, newKeySize))
429 {
430 regChunk = 0;
431 continue;
432 }
433
434 regChunk = getKeyValueNameFromChunk (regChunk, &newKeyName);
435 if (regChunk == 0)
436 continue;
437
438 if (*regChunk != '=')
439 {
440 regChunk = skipToNextKeyValueInChunk (regChunk);
441 continue;
442 }
443 regChunk++;
444
445 regChunk = getKeyValueTypeFromChunk (regChunk, dataFormat, &keyValueType);
446 if (regChunk == 0)
447 continue;
448
449 dataSize = computeKeyValueDataSize (regChunk, dataFormat);
450 if (!allocateDataBuffer (&data, &dataBufferSize, dataSize))
451 {
452 regChunk = 0;
453 continue;
454 }
455
456 regChunk = getKeyValueDataFromChunk (regChunk, dataFormat, data);
457 if (regChunk == 0)
458 continue;
459
460 if (!setKeyValue (currentKey, &newKeyName, keyValueType, data, dataSize))
461 {
462 regChunk = 0;
463 continue;
464 }
465 }
466 }
467
468 if (currentKey != INVALID_HANDLE_VALUE)
469 {
470 NtClose (currentKey);
471 }
472 if (newKeyName.Buffer != 0)
473 {
474 ExFreePool (newKeyName.Buffer);
475 }
476 if (data != 0)
477 {
478 ExFreePool (data);
479 }
480
481 return;
482 }
483
484