:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / ntoskrnl / cm / registry.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/cm/registry.c
6  * PURPOSE:         Registry functions
7  * PROGRAMMERS:     Rex Jolliff
8  *                  Matt Pyne
9  *                  Jean Michault
10  * UPDATE HISTORY:
11  *                  Created 22/05/98
12  */
13
14 #include <ddk/ntddk.h>
15 #include <roscfg.h>
16 #include <limits.h>
17 #include <string.h>
18 #include <internal/pool.h>
19 #include <internal/registry.h>
20
21 #define NDEBUG
22 #include <internal/debug.h>
23
24 #include "cm.h"
25
26 /*  -------------------------------------------------  File Statics  */
27
28 POBJECT_TYPE  CmiKeyType = NULL;
29 PREGISTRY_HIVE  CmiVolatileHive = NULL;
30 KSPIN_LOCK  CmiKeyListLock;
31
32 static PKEY_OBJECT  CmiRootKey = NULL;
33 static PKEY_OBJECT  CmiMachineKey = NULL;
34 static PKEY_OBJECT  CmiUserKey = NULL;
35 static PKEY_OBJECT  CmiHardwareKey = NULL;
36
37 static GENERIC_MAPPING CmiKeyMapping =
38         {KEY_READ, KEY_WRITE, KEY_EXECUTE, KEY_ALL_ACCESS};
39
40
41 VOID
42 CmiCheckKey(BOOLEAN Verbose,
43   HANDLE Key);
44
45 static NTSTATUS
46 CmiCreateCurrentControlSetLink(VOID);
47
48 /* FUNCTIONS ****************************************************************/
49
50 VOID
51 CmiCheckSubKeys(BOOLEAN Verbose,
52   HANDLE Key)
53 {
54   OBJECT_ATTRIBUTES ObjectAttributes;
55   PKEY_NODE_INFORMATION KeyInfo;
56   WCHAR KeyBuffer[MAX_PATH];
57   UNICODE_STRING KeyPath;
58   WCHAR Name[MAX_PATH];
59   ULONG BufferSize;
60   ULONG ResultSize;
61   NTSTATUS Status;
62   HANDLE SubKey;
63   ULONG Index;
64
65   Index = 0;
66   while (TRUE)
67     {
68           BufferSize = sizeof(KEY_NODE_INFORMATION) + 4096;
69             KeyInfo = ExAllocatePool(PagedPool, BufferSize);
70
71             Status = NtEnumerateKey(Key,
72                           Index,
73                                 KeyNodeInformation,
74                                 KeyInfo,
75                                 BufferSize,
76                                 &ResultSize);
77       if (!NT_SUCCESS(Status))
78                     {
79           ExFreePool(KeyInfo);
80                       if (Status == STATUS_NO_MORE_ENTRIES)
81                               Status = STATUS_SUCCESS;
82                       break;
83                     }
84
85       wcsncpy(Name,
86         KeyInfo->Name,
87         KeyInfo->NameLength / sizeof(WCHAR));
88
89       if (Verbose)
90                                 {
91           DbgPrint("Key: %S\n", Name);
92                                 }
93
94       /* FIXME: Check info. */
95
96       ExFreePool(KeyInfo);
97
98         wcscpy(KeyBuffer, L"\\Registry\\");
99         wcscat(KeyBuffer, Name);
100
101         RtlInitUnicodeString(&KeyPath, KeyBuffer);
102
103                   InitializeObjectAttributes(&ObjectAttributes,
104                                 &KeyPath,
105                                 OBJ_CASE_INSENSITIVE,
106                                 NULL,
107                                 NULL);
108
109                   Status = NtOpenKey(&SubKey,
110                                 KEY_ALL_ACCESS,
111                                 &ObjectAttributes);
112
113                   assert(NT_SUCCESS(Status));
114                 
115                   CmiCheckKey(Verbose, SubKey);
116                 
117                   NtClose(SubKey);
118
119                   Index++;
120     }
121
122   assert(NT_SUCCESS(Status));
123 }
124
125
126 VOID
127 CmiCheckValues(BOOLEAN Verbose,
128   HANDLE Key)
129 {
130   PKEY_NODE_INFORMATION ValueInfo;
131   WCHAR Name[MAX_PATH];
132   ULONG BufferSize;
133   ULONG ResultSize;
134   NTSTATUS Status;
135   ULONG Index;
136
137   Index = 0;
138   while (TRUE)
139     {
140           BufferSize = sizeof(KEY_NODE_INFORMATION) + 4096;
141             ValueInfo = ExAllocatePool(PagedPool, BufferSize);
142
143             Status = NtEnumerateValueKey(Key,
144                           Index,
145                                 KeyNodeInformation,
146                                 ValueInfo,
147                                 BufferSize,
148                                 &ResultSize);
149       if (!NT_SUCCESS(Status))
150                     {
151           ExFreePool(ValueInfo);
152                       if (Status == STATUS_NO_MORE_ENTRIES)
153                               Status = STATUS_SUCCESS;
154                       break;
155                     }
156
157       wcsncpy(Name,
158         ValueInfo->Name,
159         ValueInfo->NameLength / sizeof(WCHAR));
160
161       if (Verbose)
162                                 {
163           DbgPrint("Value: %S\n", Name);
164                                 }
165
166       /* FIXME: Check info. */
167
168       ExFreePool(ValueInfo);
169
170                   Index++;
171     }
172
173   assert(NT_SUCCESS(Status));
174 }
175
176
177 VOID
178 CmiCheckKey(BOOLEAN Verbose,
179   HANDLE Key)
180 {
181   CmiCheckValues(Verbose, Key);
182   CmiCheckSubKeys(Verbose, Key);
183 }
184
185
186 VOID
187 CmiCheckByName(BOOLEAN Verbose,
188   PWSTR KeyName)
189 {
190   OBJECT_ATTRIBUTES ObjectAttributes;
191   WCHAR KeyPathBuffer[MAX_PATH];
192   UNICODE_STRING KeyPath;
193   NTSTATUS Status;
194   HANDLE Key;
195
196   wcscpy(KeyPathBuffer, L"\\Registry\\");
197   wcscat(KeyPathBuffer, KeyName);
198
199         RtlInitUnicodeString(&KeyPath, KeyPathBuffer);
200
201   InitializeObjectAttributes(&ObjectAttributes,
202                 &KeyPath,
203                 OBJ_CASE_INSENSITIVE,
204                 NULL,
205                 NULL);
206
207   Status = NtOpenKey(&Key,
208                 KEY_ALL_ACCESS,
209                 &ObjectAttributes);
210
211   if (CHECKED)
212     {
213       if (!NT_SUCCESS(Status))
214                                 {
215           DbgPrint("KeyPath %wZ  Status: %.08x", KeyPath, Status);
216           DbgPrint("KeyPath %S  Status: %.08x", KeyPath.Buffer, Status);
217           assert(NT_SUCCESS(Status));
218                                 }
219     }
220
221   CmiCheckKey(Verbose, Key);
222
223   NtClose(Key);
224 }
225
226
227 VOID
228 CmiCheckRegistry(BOOLEAN Verbose)
229 {
230   if (Verbose)
231     DbgPrint("Checking registry internals\n");
232
233   CmiCheckByName(Verbose, L"Machine");
234   CmiCheckByName(Verbose, L"User");
235 }
236
237
238 VOID
239 CmInitializeRegistry(VOID)
240 {
241   OBJECT_ATTRIBUTES ObjectAttributes;
242   UNICODE_STRING RootKeyName;
243   HANDLE RootKeyHandle;
244   PKEY_OBJECT NewKey;
245   HANDLE KeyHandle;
246   NTSTATUS Status;
247   
248   /*  Initialize the Key object type  */
249   CmiKeyType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
250   assert(CmiKeyType);
251   CmiKeyType->TotalObjects = 0;
252   CmiKeyType->TotalHandles = 0;
253   CmiKeyType->MaxObjects = LONG_MAX;
254   CmiKeyType->MaxHandles = LONG_MAX;
255   CmiKeyType->PagedPoolCharge = 0;
256   CmiKeyType->NonpagedPoolCharge = sizeof(KEY_OBJECT);
257   CmiKeyType->Mapping = &CmiKeyMapping;
258   CmiKeyType->Dump = NULL;
259   CmiKeyType->Open = NULL;
260   CmiKeyType->Close = NULL;
261   CmiKeyType->Delete = CmiObjectDelete;
262   CmiKeyType->Parse = CmiObjectParse;
263   CmiKeyType->Security = NULL;
264   CmiKeyType->QueryName = NULL;
265   CmiKeyType->OkayToClose = NULL;
266   CmiKeyType->Create = CmiObjectCreate;
267   CmiKeyType->DuplicationNotify = NULL;
268   RtlInitUnicodeString(&CmiKeyType->TypeName, L"Key");
269
270   /*  Build volatile registry store  */
271   Status = CmiCreateRegistryHive(NULL, &CmiVolatileHive, FALSE);
272   assert(NT_SUCCESS(Status));
273
274   /* Build the Root Key Object */
275   RtlInitUnicodeString(&RootKeyName, REG_ROOT_KEY_NAME);
276   InitializeObjectAttributes(&ObjectAttributes, &RootKeyName, 0, NULL, NULL);
277   Status = ObCreateObject(&RootKeyHandle,
278                 STANDARD_RIGHTS_REQUIRED,
279                 &ObjectAttributes,
280                 CmiKeyType,
281                 (PVOID *) &NewKey);
282   assert(NT_SUCCESS(Status));
283   CmiRootKey = NewKey;
284   Status = ObReferenceObjectByHandle(RootKeyHandle,
285     STANDARD_RIGHTS_REQUIRED,
286                 CmiKeyType,
287                 KernelMode,
288                 (PVOID *) &CmiRootKey,
289                 NULL);
290   assert(NT_SUCCESS(Status));
291   CmiRootKey->RegistryHive = CmiVolatileHive;
292   NewKey->BlockOffset = CmiVolatileHive->HiveHeader->RootKeyCell;
293   NewKey->KeyCell = CmiGetBlock(CmiVolatileHive, NewKey->BlockOffset, NULL);
294   CmiRootKey->Flags = 0;
295   CmiRootKey->NumberOfSubKeys = 0;
296   CmiRootKey->SubKeys = NULL;
297   CmiRootKey->SizeOfSubKeys = 0;
298   CmiRootKey->Name = ExAllocatePool(PagedPool, strlen("Registry"));
299   CmiRootKey->NameSize = strlen("Registry");
300   memcpy(CmiRootKey->Name, "Registry", strlen("Registry"));
301
302   KeInitializeSpinLock(&CmiKeyListLock);
303
304   /* Create initial predefined symbolic links */
305
306   /* HKEY_LOCAL_MACHINE */
307   Status = ObCreateObject(&KeyHandle,
308     STANDARD_RIGHTS_REQUIRED,
309     NULL,
310     CmiKeyType,
311     (PVOID*) &NewKey);
312   assert(NT_SUCCESS(Status));
313   Status = CmiAddSubKey(CmiVolatileHive,
314                 CmiRootKey,
315                 NewKey,
316                 L"Machine",
317                 wcslen(L"Machine") * sizeof(WCHAR),
318                 0,
319                 NULL,
320                 0);
321   assert(NT_SUCCESS(Status));
322         NewKey->RegistryHive = CmiVolatileHive;
323         NewKey->Flags = 0;
324         NewKey->NumberOfSubKeys = 0;
325         NewKey->SubKeys = NULL;
326         NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
327         NewKey->Name = ExAllocatePool(PagedPool, strlen("Machine"));
328         NewKey->NameSize = strlen("Machine");
329         memcpy(NewKey->Name, "Machine", strlen("Machine"));
330   CmiAddKeyToList(CmiRootKey, NewKey);
331   CmiMachineKey = NewKey;
332
333   /* HKEY_USERS */
334   Status = ObCreateObject(&KeyHandle,
335                 STANDARD_RIGHTS_REQUIRED,
336                 NULL,
337                 CmiKeyType,
338                 (PVOID*) &NewKey);
339   assert(NT_SUCCESS(Status));
340   Status = CmiAddSubKey(CmiVolatileHive,
341     CmiRootKey,
342     NewKey,
343     L"User",
344     wcslen(L"User") * sizeof(WCHAR),
345     0,
346     NULL,
347     0);
348   assert(NT_SUCCESS(Status));
349         NewKey->RegistryHive = CmiVolatileHive;
350         NewKey->Flags = 0;
351         NewKey->NumberOfSubKeys = 0;
352         NewKey->SubKeys = NULL;
353         NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
354         NewKey->Name = ExAllocatePool(PagedPool, strlen("User"));
355         NewKey->NameSize = strlen("User");
356         memcpy(NewKey->Name, "User", strlen("User"));
357         CmiAddKeyToList(CmiRootKey, NewKey);
358         CmiUserKey = NewKey;
359
360   /* Create '\\Registry\\Machine\\HARDWARE' key. */
361   Status = ObCreateObject(&KeyHandle,
362                 STANDARD_RIGHTS_REQUIRED,
363                 NULL,
364                 CmiKeyType,
365                 (PVOID*)&NewKey);
366   assert(NT_SUCCESS(Status));
367   Status = CmiAddSubKey(CmiVolatileHive,
368     CmiMachineKey,
369     NewKey,
370     L"HARDWARE",
371     wcslen(L"HARDWARE") * sizeof(WCHAR),
372     0,
373     NULL,
374     0);
375   assert(NT_SUCCESS(Status));
376   NewKey->RegistryHive = CmiVolatileHive;
377   NewKey->Flags = 0;
378   NewKey->NumberOfSubKeys = 0;
379   NewKey->SubKeys = NULL;
380   NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
381   NewKey->Name = ExAllocatePool(PagedPool, strlen("HARDWARE"));
382   NewKey->NameSize = strlen("HARDWARE");
383   memcpy(NewKey->Name, "HARDWARE", strlen("HARDWARE"));
384   CmiAddKeyToList(CmiMachineKey, NewKey);
385   CmiHardwareKey = NewKey;
386
387   /* Create '\\Registry\\Machine\\HARDWARE\\DESCRIPTION' key. */
388   Status = ObCreateObject(&KeyHandle,
389                 STANDARD_RIGHTS_REQUIRED,
390                 NULL,
391                 CmiKeyType,
392                 (PVOID*) &NewKey);
393   assert(NT_SUCCESS(Status));
394   Status = CmiAddSubKey(CmiVolatileHive,
395                 CmiHardwareKey,
396                 NewKey,
397                 L"DESCRIPTION",
398                 wcslen(L"DESCRIPTION") * sizeof(WCHAR),
399                 0,
400                 NULL,
401                 0);
402   assert(NT_SUCCESS(Status));
403   NewKey->RegistryHive = CmiVolatileHive;
404   NewKey->Flags = 0;
405   NewKey->NumberOfSubKeys = 0;
406   NewKey->SubKeys = NULL;
407   NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
408   NewKey->Name = ExAllocatePool(PagedPool, strlen("DESCRIPTION"));
409   NewKey->NameSize = strlen("DESCRIPTION");
410   memcpy(NewKey->Name, "DESCRIPTION", strlen("DESCRIPTION"));
411   CmiAddKeyToList(CmiHardwareKey, NewKey);
412
413   /* Create '\\Registry\\Machine\\HARDWARE\\DEVICEMAP' key. */
414   Status = ObCreateObject(&KeyHandle,
415                 STANDARD_RIGHTS_REQUIRED,
416                 NULL,
417                 CmiKeyType,
418                 (PVOID*) &NewKey);
419   assert(NT_SUCCESS(Status));
420   Status = CmiAddSubKey(CmiVolatileHive,
421     CmiHardwareKey,
422     NewKey,
423     L"DEVICEMAP",
424                 wcslen(L"DEVICEMAP") * sizeof(WCHAR),
425     0,
426     NULL,
427     0);
428   assert(NT_SUCCESS(Status));
429   NewKey->RegistryHive = CmiVolatileHive;
430   NewKey->Flags = 0;
431   NewKey->NumberOfSubKeys = 0;
432   NewKey->SubKeys = NULL;
433   NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
434   NewKey->Name = ExAllocatePool(PagedPool, strlen("DEVICEMAP"));
435   NewKey->NameSize = strlen("DEVICEMAP");
436   memcpy(NewKey->Name, "DEVICEMAP", strlen("DEVICEMAP"));
437   CmiAddKeyToList(CmiHardwareKey,NewKey);
438
439   /* Create '\\Registry\\Machine\\HARDWARE\\RESOURCEMAP' key. */
440   Status = ObCreateObject(&KeyHandle,
441                 STANDARD_RIGHTS_REQUIRED,
442                 NULL,
443                 CmiKeyType,
444                 (PVOID*) &NewKey);
445   assert(NT_SUCCESS(Status));
446   Status = CmiAddSubKey(CmiVolatileHive,
447                 CmiHardwareKey,
448                 NewKey,
449                 L"RESOURCEMAP",
450                 wcslen(L"RESOURCEMAP") * sizeof(WCHAR),
451                 0,
452                 NULL,
453                 0);
454   assert(NT_SUCCESS(Status));
455   NewKey->RegistryHive = CmiVolatileHive;
456   NewKey->Flags = 0;
457   NewKey->NumberOfSubKeys = 0;
458   NewKey->SubKeys = NULL;
459   NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
460   NewKey->Name = ExAllocatePool(PagedPool, strlen("RESOURCEMAP"));
461   NewKey->NameSize = strlen("RESOURCEMAP");
462   memcpy(NewKey->Name, "RESOURCEMAP", strlen("RESOURCEMAP"));
463   CmiAddKeyToList(CmiHardwareKey, NewKey);
464
465   /* FIXME: create remaining structure needed for default handles  */
466   /* FIXME: load volatile registry data from ROSDTECT  */
467 }
468
469
470 VOID
471 CmInit2(PCHAR CommandLine)
472 {
473   PCHAR p1, p2;
474   ULONG PiceStart;
475
476   /* FIXME: Store current command line */
477
478   /* Create the 'CurrentControlSet' link. */
479   CmiCreateCurrentControlSetLink();
480
481
482   /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
483   PiceStart = 4;
484   p1 = (PCHAR)CommandLine;
485   while (p1 && (p2 = strchr(p1, '/')))
486     {
487       p2++;
488       if (_strnicmp(p2, "DEBUGPORT", 9) == 0)
489         {
490           p2 += 9;
491           if (*p2 == '=')
492             {
493               p2++;
494               if (_strnicmp(p2, "PICE", 4) == 0)
495                 {
496                   p2 += 4;
497                   PiceStart = 1;
498                 }
499             }
500         }
501       p1 = p2;
502     }
503
504   RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
505                         L"\\Pice",
506                         L"Start",
507                         REG_DWORD,
508                         &PiceStart,
509                         sizeof(ULONG));
510
511 }
512
513
514 static NTSTATUS
515 CmiCreateCurrentControlSetLink(VOID)
516 {
517   RTL_QUERY_REGISTRY_TABLE QueryTable[5];
518   WCHAR TargetNameBuffer[80];
519   ULONG TargetNameLength;
520   UNICODE_STRING LinkName;
521   UNICODE_STRING LinkValue;
522   ULONG CurrentSet;
523   ULONG DefaultSet;
524   ULONG Failed;
525   ULONG LastKnownGood;
526   NTSTATUS Status;
527   OBJECT_ATTRIBUTES ObjectAttributes;
528   HANDLE KeyHandle;
529
530   DPRINT("CmiCreateCurrentControlSetLink() called\n");
531
532   RtlZeroMemory(&QueryTable, sizeof(QueryTable));
533
534   QueryTable[0].Name = L"Current";
535   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
536   QueryTable[0].EntryContext = &CurrentSet;
537
538   QueryTable[1].Name = L"Default";
539   QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
540   QueryTable[1].EntryContext = &DefaultSet;
541
542   QueryTable[2].Name = L"Failed";
543   QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
544   QueryTable[2].EntryContext = &Failed;
545
546   QueryTable[3].Name = L"LastKnownGood";
547   QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
548   QueryTable[3].EntryContext = &LastKnownGood;
549
550   Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
551                                   L"\\Registry\\Machine\\SYSTEM\\Select",
552                                   QueryTable,
553                                   NULL,
554                                   NULL);
555   if (!NT_SUCCESS(Status))
556     {
557       return(Status);
558     }
559
560   DPRINT("Current %ld  Default %ld\n", CurrentSet, DefaultSet);
561
562   swprintf(TargetNameBuffer,
563            L"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
564            CurrentSet);
565   TargetNameLength = wcslen(TargetNameBuffer) * sizeof(WCHAR);
566
567   DPRINT("Link target '%S'\n", TargetNameBuffer);
568
569   RtlInitUnicodeStringFromLiteral(&LinkName,
570                        L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
571   InitializeObjectAttributes(&ObjectAttributes,
572                              &LinkName,
573                              OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
574                              NULL,
575                              NULL);
576   Status = NtCreateKey(&KeyHandle,
577                        KEY_ALL_ACCESS | KEY_CREATE_LINK,
578                        &ObjectAttributes,
579                        0,
580                        NULL,
581                        REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
582                        NULL);
583   if (!NT_SUCCESS(Status))
584     {
585       DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
586       return(Status);
587     }
588
589   RtlInitUnicodeStringFromLiteral(&LinkValue,
590                        L"SymbolicLinkValue");
591   Status=NtSetValueKey(KeyHandle,
592                        &LinkValue,
593                        0,
594                        REG_LINK,
595                        (PVOID)TargetNameBuffer,
596                        TargetNameLength);
597   if (!NT_SUCCESS(Status))
598     {
599       DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
600     }
601
602   NtClose(KeyHandle);
603
604   return(Status);
605 }
606
607
608 NTSTATUS
609 CmiConnectHive(PWSTR FileName,
610   PWSTR FullName,
611   PCHAR KeyName,
612   PKEY_OBJECT Parent,
613   BOOLEAN CreateNew)
614 {
615   OBJECT_ATTRIBUTES ObjectAttributes;
616   PREGISTRY_HIVE RegistryHive = NULL;
617   UNICODE_STRING uKeyName;
618   PKEY_OBJECT NewKey;
619   HANDLE KeyHandle;
620   NTSTATUS Status;
621
622   DPRINT("Called. FileName %S\n", FullName);
623
624   Status = CmiCreateRegistryHive(FileName, &RegistryHive, CreateNew);
625   if (!NT_SUCCESS(Status))
626     return(Status);
627
628   RtlInitUnicodeString(&uKeyName, FullName);
629
630   InitializeObjectAttributes(&ObjectAttributes,
631                              &uKeyName,
632                              0,
633                              NULL,
634                              NULL);
635
636   Status = ObCreateObject(&KeyHandle,
637                           STANDARD_RIGHTS_REQUIRED,
638                           &ObjectAttributes,
639                           CmiKeyType,
640                           (PVOID*)&NewKey);
641   if (!NT_SUCCESS(Status))
642     return(Status);
643
644   NewKey->RegistryHive = RegistryHive;
645   NewKey->BlockOffset = RegistryHive->HiveHeader->RootKeyCell;
646   NewKey->KeyCell = CmiGetBlock(RegistryHive, NewKey->BlockOffset, NULL);
647   NewKey->Flags = 0;
648   NewKey->NumberOfSubKeys = 0;
649   NewKey->SubKeys = ExAllocatePool(PagedPool,
650   NewKey->KeyCell->NumberOfSubKeys * sizeof(DWORD));
651
652   if ((NewKey->SubKeys == NULL) && (NewKey->KeyCell->NumberOfSubKeys != 0))
653     {
654       /* FIXME: Cleanup from CmiCreateRegistryHive() */
655       DPRINT("NumberOfSubKeys %d\n", NewKey->KeyCell->NumberOfSubKeys);
656       ZwClose(NewKey);
657       return(STATUS_INSUFFICIENT_RESOURCES);
658     }
659
660   NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
661   NewKey->Name = ExAllocatePool(PagedPool, strlen(KeyName));
662
663   if ((NewKey->Name == NULL) && (strlen(KeyName) != 0))
664     {
665       /* FIXME: Cleanup from CmiCreateRegistryHive() */
666       DPRINT("strlen(KeyName) %d\n", strlen(KeyName));
667       if (NewKey->SubKeys != NULL)
668         ExFreePool(NewKey->SubKeys);
669       ZwClose(NewKey);
670       return(STATUS_INSUFFICIENT_RESOURCES);
671     }
672
673   NewKey->NameSize = strlen(KeyName);
674   memcpy(NewKey->Name, KeyName, strlen(KeyName));
675   CmiAddKeyToList(Parent, NewKey);
676
677   VERIFY_KEY_OBJECT(NewKey);
678
679   return(STATUS_SUCCESS);
680 }
681
682
683 NTSTATUS
684 CmiInitializeHive(PWSTR FileName,
685   PWSTR FullName,
686   PCHAR KeyName,
687   PKEY_OBJECT Parent,
688   BOOLEAN CreateNew)
689 {
690   NTSTATUS Status;
691
692   DPRINT("CmiInitializeHive(%s) called\n", KeyName);
693
694   /* Try to connect the hive */
695   //Status = CmiConnectHive(FileName, FullName, KeyName, Parent, FALSE);
696   Status = CmiConnectHive(FileName, FullName, KeyName, Parent, CreateNew);
697
698   if (!NT_SUCCESS(Status))
699     {
700       DPRINT("Status %.08x\n", Status);
701 #if 0
702       WCHAR AltFileName[MAX_PATH];
703
704       CPRINT("WARNING! Registry file %S not found\n", FileName);
705
706       wcscpy(AltFileName, FileName);
707       wcscat(AltFileName, L".alt");
708
709       /* Try to connect the alternative hive */
710       Status = CmiConnectHive(AltFileName, FullName, KeyName, Parent, TRUE);
711
712       if (!NT_SUCCESS(Status))
713         {
714           CPRINT("WARNING! Alternative registry file %S not found\n", AltFileName);
715           DPRINT("Status %.08x\n", Status);
716         }
717 #endif
718     }
719
720   DPRINT("CmiInitializeHive() done\n");
721
722   return(Status);
723 }
724
725
726 NTSTATUS
727 CmiInitHives(BOOLEAN SetUpBoot)
728 {
729   NTSTATUS Status;
730
731   DPRINT("CmiInitHives() called\n");
732
733   CmiDoVerify = TRUE;
734
735   /* FIXME: Delete temporary \Registry\Machine\System */
736
737   /* Connect the SYSTEM hive */
738   /* FIXME: Don't overwrite the existing 'System' hive yet */
739 //  Status = CmiInitializeHive(SYSTEM_REG_FILE, REG_SYSTEM_KEY_NAME, "System", CmiMachineKey);
740 //  assert(NT_SUCCESS(Status));
741
742   /* Connect the SOFTWARE hive */
743   Status = CmiInitializeHive(SOFTWARE_REG_FILE, REG_SOFTWARE_KEY_NAME, "Software", CmiMachineKey, SetUpBoot);
744   //assert(NT_SUCCESS(Status));
745
746   /* Connect the SAM hive */
747   Status = CmiInitializeHive(SAM_REG_FILE,REG_SAM_KEY_NAME, "Sam", CmiMachineKey, SetUpBoot);
748   //assert(NT_SUCCESS(Status));
749
750   /* Connect the SECURITY hive */
751   Status = CmiInitializeHive(SEC_REG_FILE, REG_SEC_KEY_NAME, "Security", CmiMachineKey, SetUpBoot);
752   //assert(NT_SUCCESS(Status));
753
754   /* Connect the DEFAULT hive */
755   Status = CmiInitializeHive(USER_REG_FILE, REG_USER_KEY_NAME, ".Default", CmiUserKey, SetUpBoot);
756   //assert(NT_SUCCESS(Status));
757
758   /* FIXME : initialize standards symbolic links */
759
760 //  CmiCheckRegistry(TRUE);
761
762   DPRINT("CmiInitHives() done\n");
763
764   return(STATUS_SUCCESS);
765 }
766
767
768 VOID
769 CmShutdownRegistry(VOID)
770 {
771   DPRINT("CmShutdownRegistry() called\n");
772
773   /* Note:
774    *    Don't call UNIMPLEMENTED() here since this function is
775    *    called by NtShutdownSystem().
776    */
777 }
778
779 /* EOF */