branch update for HEAD-2003021201
[reactos.git] / ntoskrnl / cm / import.c
1 /* $Id$
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 #ifdef WIN32_REGDBG
11 #include "cm_win32.h"
12 #else
13 #include <ctype.h>
14
15 #include <ddk/ntddk.h>
16 #include <roscfg.h>
17 #include <internal/ob.h>
18 #include <limits.h>
19 #include <string.h>
20 #include <internal/pool.h>
21 #include <internal/registry.h>
22
23 #define NDEBUG
24 #include <internal/debug.h>
25
26 #include "cm.h"
27 #endif
28
29 static PCHAR 
30 checkAndSkipMagic (PCHAR  regChunk)
31 {
32   if (strncmp (regChunk, 
33                REGISTRY_FILE_MAGIC, 
34                strlen (REGISTRY_FILE_MAGIC)) != 0)
35   {
36     CPRINT ("incorrect magic number in registry chunk. expected: %s got:%.*s\n",
37             REGISTRY_FILE_MAGIC,
38             strlen (REGISTRY_FILE_MAGIC),
39             regChunk);
40     return  0;
41   }
42   regChunk += strlen (REGISTRY_FILE_MAGIC);
43   DPRINT ("Found regsitry chunk magic value\n");
44
45   return  regChunk;
46 }
47
48 static PCHAR
49 skipWhitespaceInChunk (PCHAR regChunk)
50 {
51   while (*regChunk && isspace (*regChunk))
52     regChunk++;
53
54   return *regChunk ? regChunk : 0;
55 }
56
57 static int
58 computeKeyNameSize (PCHAR  regChunk)
59 {
60   int  copyCount = 0;
61
62   while (*regChunk != 0 && *regChunk != ']')
63   {
64     copyCount++;
65     regChunk++;
66   }
67
68   return  copyCount;
69 }
70
71 static BOOLEAN
72 allocateKeyName (PUNICODE_STRING  newKeyName, int  newKeySize)
73 {
74   if (newKeyName->MaximumLength < (newKeySize + 1) * sizeof (WCHAR))
75   {
76     if (newKeyName->Buffer != 0)
77       ExFreePool (newKeyName->Buffer);
78     newKeyName->Length = 0;
79     newKeyName->MaximumLength = (newKeySize + 1) * sizeof (WCHAR);
80     newKeyName->Buffer = ExAllocatePool (NonPagedPool, newKeyName->MaximumLength);
81     if (newKeyName->Buffer == 0)
82     {
83       CPRINT ("Could not allocate space for key name\n");
84       return  FALSE;
85     }
86     newKeyName->Buffer [0] = 0;
87   }
88   else
89   {
90     newKeyName->Length = 0;
91     newKeyName->Buffer [0] = 0;
92   }
93
94   return  TRUE;
95 }
96
97 static PCHAR
98 skipToNextKeyInChunk (PCHAR  regChunk)
99 {
100   while (*regChunk != 0 && *regChunk != '[')
101   {
102     while (*regChunk != 0 && *regChunk != '\n')
103     {
104       regChunk++;
105     }
106     regChunk++;
107   }
108
109   return  *regChunk ? regChunk : 0;
110 }
111
112 static PCHAR
113 getKeyNameFromChunk (PCHAR  regChunk, PUNICODE_STRING  newKeyName)
114 {
115   int index = 0;
116
117   while (*regChunk != 0 && *regChunk != ']')
118   {
119     newKeyName->Buffer [index++] = *regChunk++;
120   }
121   newKeyName->Buffer [index] = '\0';
122   newKeyName->Length = index * sizeof (WCHAR);
123
124   return  *regChunk ? regChunk : 0;
125 }
126
127 static HANDLE
128 createNewKey (PUNICODE_STRING  newKeyName)
129 {
130   NTSTATUS  status;
131   OBJECT_ATTRIBUTES  attributes;
132   HANDLE  handleToReturn;
133
134   DPRINT ("Creating key (%wZ)\n", newKeyName);
135   InitializeObjectAttributes (&attributes,
136                               newKeyName,
137                               0,
138                               0,
139                               NULL);
140   status = NtCreateKey (&handleToReturn,
141                         KEY_ALL_ACCESS,
142                         &attributes,
143                         0,
144                         NULL,
145                         REG_OPTION_VOLATILE,
146                         NULL);
147   if (!NT_SUCCESS(status))
148   {
149     CPRINT ("Could not crete key (%wZ)\n", newKeyName);
150     return  INVALID_HANDLE_VALUE;
151   }
152
153   return  handleToReturn;
154 }
155
156 static PCHAR
157 skipToNextKeyValueInChunk (PCHAR  regChunk)
158 {
159   while (*regChunk != 0 && *regChunk != '\n')
160     regChunk++;
161   regChunk = skipWhitespaceInChunk (regChunk);
162   
163   return  regChunk;
164 }
165
166 static int
167 computeKeyValueNameSize (PCHAR  regChunk)
168 {
169   int size = 0;
170
171   if (*regChunk != '\"')
172     return  0;
173   regChunk++;
174   while (*regChunk != 0 && *regChunk != '\"')
175   {
176     size++;
177     regChunk++;
178   }
179
180   return  regChunk ? size : 0;
181 }
182
183 static PCHAR
184 getKeyValueNameFromChunk (PCHAR  regChunk, PUNICODE_STRING  newKeyName)
185 {
186   int  index = 0;
187
188   regChunk++;
189   while (*regChunk != 0 && *regChunk != '\"')
190   {
191     newKeyName->Buffer [index++] = *regChunk++;
192   }
193   newKeyName->Buffer [index] = '\0';
194   newKeyName->Length = index * sizeof (WCHAR);
195   regChunk++;
196
197   return  *regChunk ? regChunk : 0;
198 }
199
200 static PCHAR 
201 getKeyValueTypeFromChunk (PCHAR  regChunk, PCHAR  dataFormat, int *keyValueType)
202 {
203   if (*regChunk == '\"')
204   {
205     strcpy (dataFormat, "string");
206     *keyValueType = REG_SZ;
207   }
208   else if (strncmp (regChunk, "hex", 3) == 0)
209   {
210     strcpy (dataFormat, "hex");
211     regChunk += 3;
212     if (*regChunk == '(')
213     {
214       regChunk++;
215       *keyValueType = atoi (regChunk);
216       while (*regChunk != 0 && *regChunk != ')')
217         regChunk++;
218       regChunk++;
219     }
220     else
221       *keyValueType = REG_BINARY;
222     if (*regChunk == ':')
223       regChunk++;
224   }
225   else if (strncmp (regChunk, "dword", 5) == 0)
226   {
227     strcpy (dataFormat, "dword");
228     *keyValueType = REG_DWORD;
229     regChunk += 5;
230     if (*regChunk == ':')
231       regChunk++;
232   }
233   else if (strncmp (regChunk, "multi", 5) == 0)
234   {
235     strcpy (dataFormat, "multi");
236     *keyValueType = REG_MULTI_SZ;
237     regChunk += 5;
238     if (*regChunk == ':')
239       regChunk++;
240   }
241   else if (strncmp (regChunk, "expand", 6) == 0)
242   {
243     strcpy (dataFormat, "expand");
244     *keyValueType = REG_EXPAND_SZ;
245     regChunk += 6;
246     if (*regChunk == ':')
247       regChunk++;
248   }
249   else
250   {
251     UNIMPLEMENTED;
252   }
253
254   return  *regChunk ? regChunk : 0;
255 }
256
257 static int 
258 computeKeyValueDataSize (PCHAR  regChunk, PCHAR  dataFormat)
259 {
260   int  dataSize = 0;
261
262   if (strcmp (dataFormat, "string") == 0)
263   {
264     regChunk++;
265     while (*regChunk != 0 && *regChunk != '\"')
266     {
267       dataSize++;
268       dataSize++;
269       regChunk++;
270     }
271     dataSize++;
272     dataSize++;
273   }
274   else if (strcmp (dataFormat, "hex") == 0)
275   {
276     while (*regChunk != 0 && isxdigit(*regChunk))
277     {
278       regChunk++;
279       regChunk++;
280       dataSize++;
281       if (*regChunk == ',')
282       {
283         regChunk++;
284         if (*regChunk == '\\')
285         {
286           regChunk++;
287           regChunk = skipWhitespaceInChunk (regChunk);
288         }
289       }
290     }
291   }
292   else if (strcmp (dataFormat, "dword") == 0)
293   {
294     dataSize = sizeof(DWORD);
295     while (*regChunk != 0 && isxdigit(*regChunk))
296     {
297       regChunk++;
298     }
299   }
300   else if (strcmp (dataFormat, "multi") == 0)
301   {
302     while (*regChunk == '\"')
303     {
304       regChunk++;
305       while (*regChunk != 0 && *regChunk != '\"')
306       {
307         dataSize++;
308         dataSize++;
309         regChunk++;
310       }
311       regChunk++;
312       dataSize++;
313       dataSize++;
314       if (*regChunk == ',')
315       {
316         regChunk++;
317         regChunk = skipWhitespaceInChunk (regChunk);
318         if (*regChunk == '\\')
319         {
320           regChunk++;
321           regChunk = skipWhitespaceInChunk (regChunk);
322         }
323       }
324       else
325         break;
326     }
327     dataSize++;
328     dataSize++;
329   }
330   else if (strcmp (dataFormat, "expand") == 0)
331   {
332     regChunk++;
333     while (*regChunk != 0 && *regChunk != '\"')
334     {
335       dataSize++;
336       dataSize++;
337       regChunk++;
338     }
339     dataSize++;
340     dataSize++;
341   }
342   else
343   {
344     UNIMPLEMENTED;
345   }
346
347   return  dataSize;
348 }
349
350 static BOOLEAN
351 allocateDataBuffer (PVOID * data, int * dataBufferSize, int dataSize)
352 {
353   if (*dataBufferSize < dataSize)
354   {
355     if (*dataBufferSize > 0)
356       ExFreePool (*data);
357     *data = ExAllocatePool (NonPagedPool, dataSize);
358     *dataBufferSize = dataSize;
359   }
360
361   return  TRUE;
362 }
363
364 static PCHAR
365 getKeyValueDataFromChunk (PCHAR  regChunk, PCHAR  dataFormat, PCHAR data)
366 {
367   char  dataValue;
368   ULONG ulValue;
369   PWCHAR ptr;
370   
371   if (strcmp (dataFormat, "string") == 0)
372   {
373     /* convert quoted string to zero-terminated Unicode string */
374     ptr = (PWCHAR)data;
375     regChunk++;
376     while (*regChunk != 0 && *regChunk != '\"')
377     {
378       *ptr++ = (WCHAR)*regChunk++;
379     }
380     *ptr = 0;
381     regChunk++;
382   }
383   else if (strcmp (dataFormat, "hex") == 0)
384   {
385     while (*regChunk != 0 && isxdigit (*regChunk))
386     {
387       dataValue = (isdigit (*regChunk) ? *regChunk - '0' : 
388         tolower(*regChunk) - 'a' + 10) << 4;
389       regChunk++;
390       dataValue += (isdigit (*regChunk) ? *regChunk - '0' : 
391         tolower(*regChunk) - 'a' + 10);
392       regChunk++;
393       *data++ = dataValue;
394       if (*regChunk == ',')
395       {
396         regChunk++;
397         if (*regChunk == '\\')
398         {
399           regChunk++;
400           regChunk = skipWhitespaceInChunk (regChunk);
401         }
402       }
403     }
404   }
405   else if (strcmp (dataFormat, "dword") == 0)
406   {
407     ulValue = 0;
408     while (*regChunk != 0 && isxdigit(*regChunk))
409     {
410       dataValue = (isdigit (*regChunk) ? *regChunk - '0' : 
411         tolower(*regChunk) - 'a' + 10);
412       ulValue = (ulValue << 4) + dataValue;
413       regChunk++;
414     }
415     memcpy(data, &ulValue, sizeof(ULONG));
416   }
417   else if (strcmp (dataFormat, "multi") == 0)
418   {
419     ptr = (PWCHAR)data;
420     while (*regChunk == '\"')
421     {
422       regChunk++;
423       while (*regChunk != 0 && *regChunk != '\"')
424       {
425         *ptr++ = (WCHAR)*regChunk++;
426       }
427       regChunk++;
428       *ptr++ = 0;
429       if (*regChunk == ',')
430       {
431         regChunk++;
432         regChunk = skipWhitespaceInChunk (regChunk);
433         if (*regChunk == '\\')
434         {
435           regChunk++;
436           regChunk = skipWhitespaceInChunk (regChunk);
437         }
438       }
439       else
440         break;
441     }
442     *ptr = 0;
443   }
444   else if (strcmp (dataFormat, "expand") == 0)
445   {
446     /* convert quoted string to zero-terminated Unicode string */
447     ptr = (PWCHAR)data;
448     regChunk++;
449     while (*regChunk != 0 && *regChunk != '\"')
450     {
451       *ptr++ = (WCHAR)*regChunk++;
452     }
453     *ptr = 0;
454     regChunk++;
455   }
456   else
457   {
458     UNIMPLEMENTED;
459   }
460
461   return  *regChunk ? regChunk : 0;
462 }
463
464 static BOOLEAN
465 setKeyValue (HANDLE  currentKey,
466              PUNICODE_STRING  newValueName,
467              ULONG  keyValueType,
468              PVOID  data,
469              ULONG  dataSize)
470 {
471   NTSTATUS  status;
472
473   DPRINT ("Adding value (%wZ) to current key, with data type %d size %d\n",
474           newValueName,
475           keyValueType,
476           dataSize);
477   status = NtSetValueKey (currentKey,
478                           newValueName,
479                           0,
480                           keyValueType,
481                           data,
482                           dataSize);
483   if (!NT_SUCCESS(status))
484   {
485     CPRINT ("could not set key value, rc:%08x\n", status);
486     return  FALSE;
487   }
488
489   return  TRUE;
490 }
491
492 VOID
493 CmImportHive(PCHAR  ChunkBase,
494              ULONG  ChunkSize)
495 {
496   HANDLE  currentKey = INVALID_HANDLE_VALUE;
497   int  newKeySize;
498   UNICODE_STRING  newKeyName = {0, 0, 0};
499   char  dataFormat [10];
500   int  keyValueType;
501   int  dataSize = 0;
502   int  dataBufferSize = 0;
503   PVOID  data = 0;
504   PCHAR regChunk;
505
506   DPRINT("ChunkBase %p  ChunkSize %lx\n", ChunkBase, ChunkSize);
507
508   regChunk = checkAndSkipMagic (ChunkBase);
509   if (regChunk == 0)
510     return;
511
512   while (regChunk != 0 && *regChunk != 0 && (((ULONG)regChunk-(ULONG)ChunkBase) < ChunkSize))
513   {
514     regChunk = skipWhitespaceInChunk (regChunk);
515     if (regChunk == 0)
516       continue;
517
518     if (*regChunk == '[')
519     {
520       if (currentKey != INVALID_HANDLE_VALUE)
521       {
522         DPRINT("Closing current key: 0x%lx\n", currentKey);
523         NtClose (currentKey);
524         currentKey = INVALID_HANDLE_VALUE;
525       }
526
527       regChunk++;
528
529       newKeySize = computeKeyNameSize (regChunk);
530       if (!allocateKeyName (&newKeyName, newKeySize))
531       {
532         regChunk = 0;
533         continue;
534       }
535
536       regChunk = getKeyNameFromChunk (regChunk, &newKeyName);
537       if (regChunk == 0)
538         continue;
539
540       currentKey = createNewKey (&newKeyName);
541       if (currentKey == INVALID_HANDLE_VALUE)
542       {
543         regChunk = skipToNextKeyInChunk (regChunk);
544         continue;
545       }
546
547       regChunk++;
548     }
549     else
550     {
551       if (currentKey == INVALID_HANDLE_VALUE)
552       {
553         regChunk = skipToNextKeyInChunk (regChunk);
554         continue;
555       }
556
557       newKeySize = computeKeyValueNameSize (regChunk);
558       if (!allocateKeyName (&newKeyName, newKeySize))
559       {
560         regChunk = 0;
561         continue;
562       }
563
564       regChunk = getKeyValueNameFromChunk (regChunk, &newKeyName);
565       if (regChunk == 0)
566         continue;
567
568       if (*regChunk != '=')
569       {
570         regChunk = skipToNextKeyValueInChunk (regChunk);
571         continue;
572       }
573       regChunk++;
574
575       regChunk = getKeyValueTypeFromChunk (regChunk, dataFormat, &keyValueType);
576       if (regChunk == 0)
577         continue;
578
579       dataSize = computeKeyValueDataSize (regChunk, dataFormat);
580       if (!allocateDataBuffer (&data, &dataBufferSize, dataSize))
581       {
582         regChunk = 0;
583         continue;
584       }
585       
586       regChunk = getKeyValueDataFromChunk (regChunk, dataFormat, data);
587       if (regChunk == 0)
588         continue;
589
590       if (!setKeyValue (currentKey, &newKeyName, keyValueType, data, dataSize))
591       {
592         regChunk = 0;
593         continue;
594       }
595     }
596   }
597
598   if (currentKey != INVALID_HANDLE_VALUE)
599   {
600     NtClose (currentKey);
601   }
602   if (newKeyName.Buffer != 0)
603   {
604     ExFreePool (newKeyName.Buffer);
605   }
606   if (data != 0)
607   {
608     ExFreePool (data);
609   }
610
611   return;
612 }
613
614