:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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 #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 BOOLEAN
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 if (strncmp (regChunk, "dword", 5) == 0)
222   {
223     strcpy (dataFormat, "dword");
224     *keyValueType = REG_DWORD;
225     regChunk += 5;
226     if (*regChunk == ':')
227       regChunk++;
228   }
229   else if (strncmp (regChunk, "multi", 5) == 0)
230   {
231     strcpy (dataFormat, "multi");
232     *keyValueType = REG_MULTI_SZ;
233     regChunk += 5;
234     if (*regChunk == ':')
235       regChunk++;
236   }
237   else if (strncmp (regChunk, "expand", 6) == 0)
238   {
239     strcpy (dataFormat, "expand");
240     *keyValueType = REG_EXPAND_SZ;
241     regChunk += 6;
242     if (*regChunk == ':')
243       regChunk++;
244   }
245   else
246   {
247     UNIMPLEMENTED;
248   }
249
250   return  *regChunk ? regChunk : 0;
251 }
252
253 static int 
254 computeKeyValueDataSize (PCHAR  regChunk, PCHAR  dataFormat)
255 {
256   int  dataSize = 0;
257
258   if (strcmp (dataFormat, "string") == 0)
259   {
260     regChunk++;
261     while (*regChunk != 0 && *regChunk != '\"')
262     {
263       dataSize++;
264       dataSize++;
265       regChunk++;
266     }
267     dataSize++;
268     dataSize++;
269   }
270   else if (strcmp (dataFormat, "hex") == 0)
271   {
272     while (*regChunk != 0 && isxdigit(*regChunk))
273     {
274       regChunk++;
275       regChunk++;
276       dataSize++;
277       if (*regChunk == ',')
278       {
279         regChunk++;
280         if (*regChunk == '\\')
281         {
282           regChunk++;
283           regChunk = skipWhitespaceInChunk (regChunk);
284         }
285       }
286     }
287   }
288   else if (strcmp (dataFormat, "dword") == 0)
289   {
290     dataSize = sizeof(DWORD);
291     while (*regChunk != 0 && isxdigit(*regChunk))
292     {
293       regChunk++;
294     }
295   }
296   else if (strcmp (dataFormat, "multi") == 0)
297   {
298     while (*regChunk == '\"')
299     {
300       regChunk++;
301       while (*regChunk != 0 && *regChunk != '\"')
302       {
303         dataSize++;
304         dataSize++;
305         regChunk++;
306       }
307       regChunk++;
308       dataSize++;
309       dataSize++;
310       if (*regChunk == ',')
311       {
312         regChunk++;
313         regChunk = skipWhitespaceInChunk (regChunk);
314         if (*regChunk == '\\')
315         {
316           regChunk++;
317           regChunk = skipWhitespaceInChunk (regChunk);
318         }
319       }
320       else
321         break;
322     }
323     dataSize++;
324     dataSize++;
325   }
326   else if (strcmp (dataFormat, "expand") == 0)
327   {
328     regChunk++;
329     while (*regChunk != 0 && *regChunk != '\"')
330     {
331       dataSize++;
332       dataSize++;
333       regChunk++;
334     }
335     dataSize++;
336     dataSize++;
337   }
338   else
339   {
340     UNIMPLEMENTED;
341   }
342
343   return  dataSize;
344 }
345
346 static BOOLEAN
347 allocateDataBuffer (PVOID * data, int * dataBufferSize, int dataSize)
348 {
349   if (*dataBufferSize < dataSize)
350   {
351     if (*dataBufferSize > 0)
352       ExFreePool (*data);
353     *data = ExAllocatePool (NonPagedPool, dataSize);
354     *dataBufferSize = dataSize;
355   }
356
357   return  TRUE;
358 }
359
360 static PCHAR
361 getKeyValueDataFromChunk (PCHAR  regChunk, PCHAR  dataFormat, PCHAR data)
362 {
363   char  dataValue;
364   ULONG ulValue;
365   PWCHAR ptr;
366   
367   if (strcmp (dataFormat, "string") == 0)
368   {
369     /* convert quoted string to zero-terminated Unicode string */
370     ptr = (PWCHAR)data;
371     regChunk++;
372     while (*regChunk != 0 && *regChunk != '\"')
373     {
374       *ptr++ = (WCHAR)*regChunk++;
375     }
376     *ptr = 0;
377     regChunk++;
378   }
379   else if (strcmp (dataFormat, "hex") == 0)
380   {
381     while (*regChunk != 0 && isxdigit (*regChunk))
382     {
383       dataValue = (isdigit (*regChunk) ? *regChunk - '0' : 
384         tolower(*regChunk) - 'a' + 10) << 4;
385       regChunk++;
386       dataValue += (isdigit (*regChunk) ? *regChunk - '0' : 
387         tolower(*regChunk) - 'a' + 10);
388       regChunk++;
389       *data++ = dataValue;
390       if (*regChunk == ',')
391       {
392         regChunk++;
393         if (*regChunk == '\\')
394         {
395           regChunk++;
396           regChunk = skipWhitespaceInChunk (regChunk);
397         }
398       }
399     }
400   }
401   else if (strcmp (dataFormat, "dword") == 0)
402   {
403     ulValue = 0;
404     while (*regChunk != 0 && isxdigit(*regChunk))
405     {
406       dataValue = (isdigit (*regChunk) ? *regChunk - '0' : 
407         tolower(*regChunk) - 'a' + 10);
408       ulValue = (ulValue << 4) + dataValue;
409       regChunk++;
410     }
411     memcpy(data, &ulValue, sizeof(ULONG));
412   }
413   else if (strcmp (dataFormat, "multi") == 0)
414   {
415     ptr = (PWCHAR)data;
416     while (*regChunk == '\"')
417     {
418       regChunk++;
419       while (*regChunk != 0 && *regChunk != '\"')
420       {
421         *ptr++ = (WCHAR)*regChunk++;
422       }
423       regChunk++;
424       *ptr++ = 0;
425       if (*regChunk == ',')
426       {
427         regChunk++;
428         regChunk = skipWhitespaceInChunk (regChunk);
429         if (*regChunk == '\\')
430         {
431           regChunk++;
432           regChunk = skipWhitespaceInChunk (regChunk);
433         }
434       }
435       else
436         break;
437     }
438     *ptr = 0;
439   }
440   else if (strcmp (dataFormat, "expand") == 0)
441   {
442     /* convert quoted string to zero-terminated Unicode string */
443     ptr = (PWCHAR)data;
444     regChunk++;
445     while (*regChunk != 0 && *regChunk != '\"')
446     {
447       *ptr++ = (WCHAR)*regChunk++;
448     }
449     *ptr = 0;
450     regChunk++;
451   }
452   else
453   {
454     UNIMPLEMENTED;
455   }
456
457   return  *regChunk ? regChunk : 0;
458 }
459
460 static BOOLEAN
461 setKeyValue (HANDLE  currentKey,
462              PUNICODE_STRING  newValueName,
463              ULONG  keyValueType,
464              PVOID  data,
465              ULONG  dataSize)
466 {
467   NTSTATUS  status;
468
469   DPRINT ("Adding value (%wZ) to current key, with data type %d size %d\n",
470           newValueName,
471           keyValueType,
472           dataSize);
473   status = NtSetValueKey (currentKey,
474                           newValueName,
475                           0,
476                           keyValueType,
477                           data,
478                           dataSize);
479   if (!NT_SUCCESS(status))
480   {
481     CPRINT ("could not set key value, rc:%08x\n", status);
482     return  FALSE;
483   }
484
485   return  TRUE;
486 }
487
488 VOID
489 CmImportHive(PCHAR  ChunkBase,
490              ULONG  ChunkSize)
491 {
492   HANDLE  currentKey = INVALID_HANDLE_VALUE;
493   int  newKeySize;
494   UNICODE_STRING  newKeyName = {0, 0, 0};
495   char  dataFormat [10];
496   int  keyValueType;
497   int  dataSize = 0;
498   int  dataBufferSize = 0;
499   PVOID  data = 0;
500   PCHAR regChunk;
501
502   DPRINT("ChunkBase %p  ChunkSize %lx\n", ChunkBase, ChunkSize);
503
504   regChunk = checkAndSkipMagic (ChunkBase);
505   if (regChunk == 0)
506     return;
507
508   while (regChunk != 0 && *regChunk != 0 && (((ULONG)regChunk-(ULONG)ChunkBase) < ChunkSize))
509   {
510     regChunk = skipWhitespaceInChunk (regChunk);
511     if (regChunk == 0)
512       continue;
513
514     if (*regChunk == '[')
515     {
516       if (currentKey != INVALID_HANDLE_VALUE)
517       {
518         DPRINT("Closing current key: 0x%lx\n", currentKey);
519         NtClose (currentKey);
520         currentKey = INVALID_HANDLE_VALUE;
521       }
522
523       regChunk++;
524
525       newKeySize = computeKeyNameSize (regChunk);
526       if (!allocateKeyName (&newKeyName, newKeySize))
527       {
528         regChunk = 0;
529         continue;
530       }
531
532       regChunk = getKeyNameFromChunk (regChunk, &newKeyName);
533       if (regChunk == 0)
534         continue;
535
536       currentKey = createNewKey (&newKeyName);
537       if (currentKey == INVALID_HANDLE_VALUE)
538       {
539         regChunk = skipToNextKeyInChunk (regChunk);
540         continue;
541       }
542
543       regChunk++;
544     }
545     else
546     {
547       if (currentKey == INVALID_HANDLE_VALUE)
548       {
549         regChunk = skipToNextKeyInChunk (regChunk);
550         continue;
551       }
552
553       newKeySize = computeKeyValueNameSize (regChunk);
554       if (!allocateKeyName (&newKeyName, newKeySize))
555       {
556         regChunk = 0;
557         continue;
558       }
559
560       regChunk = getKeyValueNameFromChunk (regChunk, &newKeyName);
561       if (regChunk == 0)
562         continue;
563
564       if (*regChunk != '=')
565       {
566         regChunk = skipToNextKeyValueInChunk (regChunk);
567         continue;
568       }
569       regChunk++;
570
571       regChunk = getKeyValueTypeFromChunk (regChunk, dataFormat, &keyValueType);
572       if (regChunk == 0)
573         continue;
574
575       dataSize = computeKeyValueDataSize (regChunk, dataFormat);
576       if (!allocateDataBuffer (&data, &dataBufferSize, dataSize))
577       {
578         regChunk = 0;
579         continue;
580       }
581       
582       regChunk = getKeyValueDataFromChunk (regChunk, dataFormat, data);
583       if (regChunk == 0)
584         continue;
585
586       if (!setKeyValue (currentKey, &newKeyName, keyValueType, data, dataSize))
587       {
588         regChunk = 0;
589         continue;
590       }
591     }
592   }
593
594   if (currentKey != INVALID_HANDLE_VALUE)
595   {
596     NtClose (currentKey);
597   }
598   if (newKeyName.Buffer != 0)
599   {
600     ExFreePool (newKeyName.Buffer);
601   }
602   if (data != 0)
603   {
604     ExFreePool (data);
605   }
606
607   return;
608 }
609
610