update for HEAD-2003021201
[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 #ifdef WIN32_REGDBG
15 #include "cm_win32.h"
16 #else
17 #include <ddk/ntddk.h>
18 #include <roscfg.h>
19 #include <limits.h>
20 #include <string.h>
21 #include <internal/pool.h>
22 #include <internal/registry.h>
23 #include <reactos/bugcodes.h>
24
25 #define NDEBUG
26 #include <internal/debug.h>
27
28 #include "cm.h"
29 #endif
30
31 /*  -------------------------------------------------  File Statics  */
32
33 POBJECT_TYPE  CmiKeyType = NULL;
34 PREGISTRY_HIVE  CmiVolatileHive = NULL;
35 KSPIN_LOCK  CmiKeyListLock;
36
37 LIST_ENTRY CmiHiveListHead;
38 ERESOURCE CmiHiveListLock;
39
40 volatile BOOLEAN CmiHiveSyncEnabled = FALSE;
41 volatile BOOLEAN CmiHiveSyncPending = FALSE;
42 KDPC CmiHiveSyncDpc;
43 KTIMER CmiHiveSyncTimer;
44
45 static PKEY_OBJECT  CmiRootKey = NULL;
46 static PKEY_OBJECT  CmiMachineKey = NULL;
47 static PKEY_OBJECT  CmiUserKey = NULL;
48 static PKEY_OBJECT  CmiHardwareKey = NULL;
49
50 static GENERIC_MAPPING CmiKeyMapping =
51         {KEY_READ, KEY_WRITE, KEY_EXECUTE, KEY_ALL_ACCESS};
52
53
54
55 VOID
56 CmiCheckKey(BOOLEAN Verbose,
57   HANDLE Key);
58
59 static NTSTATUS
60 CmiCreateCurrentControlSetLink(VOID);
61
62 static VOID STDCALL
63 CmiHiveSyncDpcRoutine(PKDPC Dpc,
64                       PVOID DeferredContext,
65                       PVOID SystemArgument1,
66                       PVOID SystemArgument2);
67
68 /* FUNCTIONS ****************************************************************/
69
70 VOID
71 CmiCheckSubKeys(BOOLEAN Verbose,
72   HANDLE Key)
73 {
74   OBJECT_ATTRIBUTES ObjectAttributes;
75   PKEY_NODE_INFORMATION KeyInfo;
76   WCHAR KeyBuffer[MAX_PATH];
77   UNICODE_STRING KeyPath;
78   WCHAR Name[MAX_PATH];
79   ULONG BufferSize;
80   ULONG ResultSize;
81   NTSTATUS Status;
82   HANDLE SubKey;
83   ULONG Index;
84
85   Index = 0;
86   while (TRUE)
87     {
88       BufferSize = sizeof(KEY_NODE_INFORMATION) + 4096;
89       KeyInfo = ExAllocatePool(PagedPool, BufferSize);
90
91       Status = NtEnumerateKey(Key,
92                               Index,
93                               KeyNodeInformation,
94                               KeyInfo,
95                               BufferSize,
96                               &ResultSize);
97       if (!NT_SUCCESS(Status))
98         {
99           ExFreePool(KeyInfo);
100           if (Status == STATUS_NO_MORE_ENTRIES)
101             Status = STATUS_SUCCESS;
102           break;
103         }
104
105       wcsncpy(Name,
106               KeyInfo->Name,
107               KeyInfo->NameLength / sizeof(WCHAR));
108
109       if (Verbose)
110         {
111           DbgPrint("Key: %S\n", Name);
112         }
113
114       /* FIXME: Check info. */
115
116       ExFreePool(KeyInfo);
117
118       wcscpy(KeyBuffer, L"\\Registry\\");
119       wcscat(KeyBuffer, Name);
120
121       RtlInitUnicodeString(&KeyPath, KeyBuffer);
122
123       InitializeObjectAttributes(&ObjectAttributes,
124                                  &KeyPath,
125                                  OBJ_CASE_INSENSITIVE,
126                                  NULL,
127                                  NULL);
128
129       Status = NtOpenKey(&SubKey,
130                          KEY_ALL_ACCESS,
131                          &ObjectAttributes);
132
133       assert(NT_SUCCESS(Status));
134
135       CmiCheckKey(Verbose, SubKey);
136
137       NtClose(SubKey);
138
139       Index++;
140     }
141
142   assert(NT_SUCCESS(Status));
143 }
144
145
146 VOID
147 CmiCheckValues(BOOLEAN Verbose,
148   HANDLE Key)
149 {
150   PKEY_NODE_INFORMATION ValueInfo;
151   WCHAR Name[MAX_PATH];
152   ULONG BufferSize;
153   ULONG ResultSize;
154   NTSTATUS Status;
155   ULONG Index;
156
157   Index = 0;
158   while (TRUE)
159     {
160       BufferSize = sizeof(KEY_NODE_INFORMATION) + 4096;
161       ValueInfo = ExAllocatePool(PagedPool, BufferSize);
162
163       Status = NtEnumerateValueKey(Key,
164                                    Index,
165                                    KeyNodeInformation,
166                                    ValueInfo,
167                                    BufferSize,
168                                    &ResultSize);
169       if (!NT_SUCCESS(Status))
170         {
171           ExFreePool(ValueInfo);
172           if (Status == STATUS_NO_MORE_ENTRIES)
173             Status = STATUS_SUCCESS;
174           break;
175         }
176
177       wcsncpy(Name,
178               ValueInfo->Name,
179               ValueInfo->NameLength / sizeof(WCHAR));
180
181       if (Verbose)
182         {
183           DbgPrint("Value: %S\n", Name);
184         }
185
186       /* FIXME: Check info. */
187
188       ExFreePool(ValueInfo);
189
190       Index++;
191     }
192
193   assert(NT_SUCCESS(Status));
194 }
195
196
197 VOID
198 CmiCheckKey(BOOLEAN Verbose,
199   HANDLE Key)
200 {
201   CmiCheckValues(Verbose, Key);
202   CmiCheckSubKeys(Verbose, Key);
203 }
204
205
206 VOID
207 CmiCheckByName(BOOLEAN Verbose,
208   PWSTR KeyName)
209 {
210   OBJECT_ATTRIBUTES ObjectAttributes;
211   WCHAR KeyPathBuffer[MAX_PATH];
212   UNICODE_STRING KeyPath;
213   NTSTATUS Status;
214   HANDLE Key;
215
216   wcscpy(KeyPathBuffer, L"\\Registry\\");
217   wcscat(KeyPathBuffer, KeyName);
218
219   RtlInitUnicodeString(&KeyPath, KeyPathBuffer);
220
221   InitializeObjectAttributes(&ObjectAttributes,
222                 &KeyPath,
223                 OBJ_CASE_INSENSITIVE,
224                 NULL,
225                 NULL);
226
227   Status = NtOpenKey(&Key,
228                 KEY_ALL_ACCESS,
229                 &ObjectAttributes);
230
231   if (CHECKED)
232     {
233       if (!NT_SUCCESS(Status))
234         {
235           DbgPrint("KeyPath %wZ  Status: %.08x", KeyPath, Status);
236           DbgPrint("KeyPath %S  Status: %.08x", KeyPath.Buffer, Status);
237           assert(NT_SUCCESS(Status));
238         }
239     }
240
241   CmiCheckKey(Verbose, Key);
242
243   NtClose(Key);
244 }
245
246
247 VOID
248 CmiCheckRegistry(BOOLEAN Verbose)
249 {
250   if (Verbose)
251     DbgPrint("Checking registry internals\n");
252
253   CmiCheckByName(Verbose, L"Machine");
254   CmiCheckByName(Verbose, L"User");
255 }
256
257
258 VOID
259 CmInitializeRegistry(VOID)
260 {
261   OBJECT_ATTRIBUTES ObjectAttributes;
262   UNICODE_STRING RootKeyName;
263   HANDLE RootKeyHandle;
264   PKEY_OBJECT NewKey;
265   HANDLE KeyHandle;
266   NTSTATUS Status;
267
268   /*  Initialize the Key object type  */
269   CmiKeyType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
270   assert(CmiKeyType);
271   CmiKeyType->TotalObjects = 0;
272   CmiKeyType->TotalHandles = 0;
273   CmiKeyType->MaxObjects = LONG_MAX;
274   CmiKeyType->MaxHandles = LONG_MAX;
275   CmiKeyType->PagedPoolCharge = 0;
276   CmiKeyType->NonpagedPoolCharge = sizeof(KEY_OBJECT);
277   CmiKeyType->Mapping = &CmiKeyMapping;
278   CmiKeyType->Dump = NULL;
279   CmiKeyType->Open = NULL;
280   CmiKeyType->Close = NULL;
281   CmiKeyType->Delete = CmiObjectDelete;
282   CmiKeyType->Parse = CmiObjectParse;
283   CmiKeyType->Security = NULL;
284   CmiKeyType->QueryName = NULL;
285   CmiKeyType->OkayToClose = NULL;
286   CmiKeyType->Create = CmiObjectCreate;
287   CmiKeyType->DuplicationNotify = NULL;
288   RtlInitUnicodeString(&CmiKeyType->TypeName, L"Key");
289
290   /* Initialize the hive list */
291   InitializeListHead(&CmiHiveListHead);
292   ExInitializeResourceLite(&CmiHiveListLock);
293
294   /*  Build volatile registry store  */
295   Status = CmiCreateRegistryHive(NULL, &CmiVolatileHive, FALSE);
296   assert(NT_SUCCESS(Status));
297
298   /* Create '\Registry' key. */
299   RtlInitUnicodeString(&RootKeyName, REG_ROOT_KEY_NAME);
300   InitializeObjectAttributes(&ObjectAttributes, &RootKeyName, 0, NULL, NULL);
301   Status = ObCreateObject(&RootKeyHandle,
302                 STANDARD_RIGHTS_REQUIRED,
303                 &ObjectAttributes,
304                 CmiKeyType,
305                 (PVOID *) &NewKey);
306   assert(NT_SUCCESS(Status));
307   CmiRootKey = NewKey;
308   Status = ObReferenceObjectByHandle(RootKeyHandle,
309     STANDARD_RIGHTS_REQUIRED,
310                 CmiKeyType,
311                 KernelMode,
312                 (PVOID *) &CmiRootKey,
313                 NULL);
314   assert(NT_SUCCESS(Status));
315   CmiRootKey->RegistryHive = CmiVolatileHive;
316   NewKey->BlockOffset = CmiVolatileHive->HiveHeader->RootKeyCell;
317   NewKey->KeyCell = CmiGetBlock(CmiVolatileHive, NewKey->BlockOffset, NULL);
318   CmiRootKey->Flags = 0;
319   CmiRootKey->NumberOfSubKeys = 0;
320   CmiRootKey->SubKeys = NULL;
321   CmiRootKey->SizeOfSubKeys = 0;
322   CmiRootKey->Name = ExAllocatePool(PagedPool, strlen("Registry"));
323   CmiRootKey->NameSize = strlen("Registry");
324   memcpy(CmiRootKey->Name, "Registry", strlen("Registry"));
325
326   KeInitializeSpinLock(&CmiKeyListLock);
327
328   /* Create initial predefined symbolic links */
329
330   /* Create '\Registry\Machine' key. */
331   Status = ObCreateObject(&KeyHandle,
332     STANDARD_RIGHTS_REQUIRED,
333     NULL,
334     CmiKeyType,
335     (PVOID*) &NewKey);
336   assert(NT_SUCCESS(Status));
337   Status = CmiAddSubKey(CmiVolatileHive,
338                 CmiRootKey,
339                 NewKey,
340                 L"Machine",
341                 wcslen(L"Machine") * sizeof(WCHAR),
342                 0,
343                 NULL,
344                 0);
345   assert(NT_SUCCESS(Status));
346         NewKey->RegistryHive = CmiVolatileHive;
347         NewKey->Flags = 0;
348         NewKey->NumberOfSubKeys = 0;
349         NewKey->SubKeys = NULL;
350         NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
351         NewKey->Name = ExAllocatePool(PagedPool, strlen("Machine"));
352         NewKey->NameSize = strlen("Machine");
353         memcpy(NewKey->Name, "Machine", strlen("Machine"));
354   CmiAddKeyToList(CmiRootKey, NewKey);
355   CmiMachineKey = NewKey;
356
357   /* Create '\Registry\User' key. */
358   Status = ObCreateObject(&KeyHandle,
359                 STANDARD_RIGHTS_REQUIRED,
360                 NULL,
361                 CmiKeyType,
362                 (PVOID*) &NewKey);
363   assert(NT_SUCCESS(Status));
364   Status = CmiAddSubKey(CmiVolatileHive,
365     CmiRootKey,
366     NewKey,
367     L"User",
368     wcslen(L"User") * sizeof(WCHAR),
369     0,
370     NULL,
371     0);
372   assert(NT_SUCCESS(Status));
373         NewKey->RegistryHive = CmiVolatileHive;
374         NewKey->Flags = 0;
375         NewKey->NumberOfSubKeys = 0;
376         NewKey->SubKeys = NULL;
377         NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
378         NewKey->Name = ExAllocatePool(PagedPool, strlen("User"));
379         NewKey->NameSize = strlen("User");
380         memcpy(NewKey->Name, "User", strlen("User"));
381         CmiAddKeyToList(CmiRootKey, NewKey);
382         CmiUserKey = NewKey;
383
384   /* Create '\Registry\Machine\HARDWARE' key. */
385   Status = ObCreateObject(&KeyHandle,
386                 STANDARD_RIGHTS_REQUIRED,
387                 NULL,
388                 CmiKeyType,
389                 (PVOID*)&NewKey);
390   assert(NT_SUCCESS(Status));
391   Status = CmiAddSubKey(CmiVolatileHive,
392     CmiMachineKey,
393     NewKey,
394     L"HARDWARE",
395     wcslen(L"HARDWARE") * sizeof(WCHAR),
396     0,
397     NULL,
398     0);
399   assert(NT_SUCCESS(Status));
400   NewKey->RegistryHive = CmiVolatileHive;
401   NewKey->Flags = 0;
402   NewKey->NumberOfSubKeys = 0;
403   NewKey->SubKeys = NULL;
404   NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
405   NewKey->Name = ExAllocatePool(PagedPool, strlen("HARDWARE"));
406   NewKey->NameSize = strlen("HARDWARE");
407   memcpy(NewKey->Name, "HARDWARE", strlen("HARDWARE"));
408   CmiAddKeyToList(CmiMachineKey, NewKey);
409   CmiHardwareKey = NewKey;
410
411   /* Create '\Registry\Machine\HARDWARE\DESCRIPTION' key. */
412   Status = ObCreateObject(&KeyHandle,
413                 STANDARD_RIGHTS_REQUIRED,
414                 NULL,
415                 CmiKeyType,
416                 (PVOID*) &NewKey);
417   assert(NT_SUCCESS(Status));
418   Status = CmiAddSubKey(CmiVolatileHive,
419                 CmiHardwareKey,
420                 NewKey,
421                 L"DESCRIPTION",
422                 wcslen(L"DESCRIPTION") * sizeof(WCHAR),
423                 0,
424                 NULL,
425                 0);
426   assert(NT_SUCCESS(Status));
427   NewKey->RegistryHive = CmiVolatileHive;
428   NewKey->Flags = 0;
429   NewKey->NumberOfSubKeys = 0;
430   NewKey->SubKeys = NULL;
431   NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
432   NewKey->Name = ExAllocatePool(PagedPool, strlen("DESCRIPTION"));
433   NewKey->NameSize = strlen("DESCRIPTION");
434   memcpy(NewKey->Name, "DESCRIPTION", strlen("DESCRIPTION"));
435   CmiAddKeyToList(CmiHardwareKey, NewKey);
436
437   /* Create '\Registry\Machine\HARDWARE\DEVICEMAP' key. */
438   Status = ObCreateObject(&KeyHandle,
439                 STANDARD_RIGHTS_REQUIRED,
440                 NULL,
441                 CmiKeyType,
442                 (PVOID*) &NewKey);
443   assert(NT_SUCCESS(Status));
444   Status = CmiAddSubKey(CmiVolatileHive,
445     CmiHardwareKey,
446     NewKey,
447     L"DEVICEMAP",
448                 wcslen(L"DEVICEMAP") * sizeof(WCHAR),
449     0,
450     NULL,
451     0);
452   assert(NT_SUCCESS(Status));
453   NewKey->RegistryHive = CmiVolatileHive;
454   NewKey->Flags = 0;
455   NewKey->NumberOfSubKeys = 0;
456   NewKey->SubKeys = NULL;
457   NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
458   NewKey->Name = ExAllocatePool(PagedPool, strlen("DEVICEMAP"));
459   NewKey->NameSize = strlen("DEVICEMAP");
460   memcpy(NewKey->Name, "DEVICEMAP", strlen("DEVICEMAP"));
461   CmiAddKeyToList(CmiHardwareKey,NewKey);
462
463   /* Create '\Registry\Machine\HARDWARE\RESOURCEMAP' key. */
464   Status = ObCreateObject(&KeyHandle,
465                 STANDARD_RIGHTS_REQUIRED,
466                 NULL,
467                 CmiKeyType,
468                 (PVOID*) &NewKey);
469   assert(NT_SUCCESS(Status));
470   Status = CmiAddSubKey(CmiVolatileHive,
471                 CmiHardwareKey,
472                 NewKey,
473                 L"RESOURCEMAP",
474                 wcslen(L"RESOURCEMAP") * sizeof(WCHAR),
475                 0,
476                 NULL,
477                 0);
478   assert(NT_SUCCESS(Status));
479   NewKey->RegistryHive = CmiVolatileHive;
480   NewKey->Flags = 0;
481   NewKey->NumberOfSubKeys = 0;
482   NewKey->SubKeys = NULL;
483   NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
484   NewKey->Name = ExAllocatePool(PagedPool, strlen("RESOURCEMAP"));
485   NewKey->NameSize = strlen("RESOURCEMAP");
486   memcpy(NewKey->Name, "RESOURCEMAP", strlen("RESOURCEMAP"));
487   CmiAddKeyToList(CmiHardwareKey, NewKey);
488
489   /* FIXME: create remaining structure needed for default handles  */
490   /* FIXME: load volatile registry data from ROSDTECT  */
491 }
492
493
494 VOID
495 CmInit2(PCHAR CommandLine)
496 {
497   PCHAR p1, p2;
498   ULONG PiceStart;
499   NTSTATUS Status;
500
501   /* FIXME: Store system start options */
502
503
504
505   /* Create the 'CurrentControlSet' link. */
506   Status = CmiCreateCurrentControlSetLink();
507 #ifndef WIN32_REGDBG
508   if (!NT_SUCCESS(Status))
509     {
510       KeBugCheck(CONFIG_INITIALIZATION_FAILED);
511     }
512 #endif
513
514   /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
515   PiceStart = 4;
516   p1 = (PCHAR)CommandLine;
517   while (p1 && (p2 = strchr(p1, '/')))
518     {
519       p2++;
520       if (_strnicmp(p2, "DEBUGPORT", 9) == 0)
521         {
522           p2 += 9;
523           if (*p2 == '=')
524             {
525               p2++;
526               if (_strnicmp(p2, "PICE", 4) == 0)
527                 {
528                   p2 += 4;
529                   PiceStart = 1;
530                 }
531             }
532         }
533       p1 = p2;
534     }
535 #ifndef WIN32_REGDBG
536   Status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
537                                  L"\\Pice",
538                                  L"Start",
539                                  REG_DWORD,
540                                  &PiceStart,
541                                  sizeof(ULONG));
542   if (!NT_SUCCESS(Status))
543     {
544       KeBugCheck(CONFIG_INITIALIZATION_FAILED);
545     }
546 #endif
547 }
548
549
550 static NTSTATUS
551 CmiCreateCurrentControlSetLink(VOID)
552 {
553   RTL_QUERY_REGISTRY_TABLE QueryTable[5];
554   WCHAR TargetNameBuffer[80];
555   ULONG TargetNameLength;
556   UNICODE_STRING LinkName;
557   UNICODE_STRING LinkValue;
558   ULONG CurrentSet;
559   ULONG DefaultSet;
560   ULONG Failed;
561   ULONG LastKnownGood;
562   NTSTATUS Status;
563   OBJECT_ATTRIBUTES ObjectAttributes;
564   HANDLE KeyHandle;
565
566   DPRINT("CmiCreateCurrentControlSetLink() called\n");
567
568   RtlZeroMemory(&QueryTable, sizeof(QueryTable));
569
570   QueryTable[0].Name = L"Current";
571   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
572   QueryTable[0].EntryContext = &CurrentSet;
573
574   QueryTable[1].Name = L"Default";
575   QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
576   QueryTable[1].EntryContext = &DefaultSet;
577
578   QueryTable[2].Name = L"Failed";
579   QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
580   QueryTable[2].EntryContext = &Failed;
581
582   QueryTable[3].Name = L"LastKnownGood";
583   QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
584   QueryTable[3].EntryContext = &LastKnownGood;
585
586   Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
587                                   L"\\Registry\\Machine\\SYSTEM\\Select",
588                                   QueryTable,
589                                   NULL,
590                                   NULL);
591   if (!NT_SUCCESS(Status))
592     {
593       return(Status);
594     }
595
596   DPRINT("Current %ld  Default %ld\n", CurrentSet, DefaultSet);
597
598   swprintf(TargetNameBuffer,
599            L"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
600            CurrentSet);
601   TargetNameLength = wcslen(TargetNameBuffer) * sizeof(WCHAR);
602
603   DPRINT("Link target '%S'\n", TargetNameBuffer);
604
605   RtlInitUnicodeStringFromLiteral(&LinkName,
606                        L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
607   InitializeObjectAttributes(&ObjectAttributes,
608                              &LinkName,
609                              OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
610                              NULL,
611                              NULL);
612   Status = NtCreateKey(&KeyHandle,
613                        KEY_ALL_ACCESS | KEY_CREATE_LINK,
614                        &ObjectAttributes,
615                        0,
616                        NULL,
617                        REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
618                        NULL);
619   if (!NT_SUCCESS(Status))
620     {
621       DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
622       return(Status);
623     }
624
625   RtlInitUnicodeStringFromLiteral(&LinkValue,
626                        L"SymbolicLinkValue");
627   Status = NtSetValueKey(KeyHandle,
628                          &LinkValue,
629                          0,
630                          REG_LINK,
631                          (PVOID)TargetNameBuffer,
632                          TargetNameLength);
633   if (!NT_SUCCESS(Status))
634     {
635       DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
636     }
637
638   NtClose(KeyHandle);
639
640   return(Status);
641 }
642
643
644 NTSTATUS
645 CmiConnectHive(PWSTR FileName,
646   PWSTR FullName,
647   PCHAR KeyName,
648   PKEY_OBJECT Parent,
649   BOOLEAN CreateNew)
650 {
651   OBJECT_ATTRIBUTES ObjectAttributes;
652   PREGISTRY_HIVE RegistryHive = NULL;
653   UNICODE_STRING uKeyName;
654   PKEY_OBJECT NewKey;
655   HANDLE KeyHandle;
656   NTSTATUS Status;
657
658   DPRINT("CmiConnectHive(%S, %S, %s, %p, %d) - Called.\n", FileName, FullName, KeyName, Parent, CreateNew);
659
660   Status = CmiCreateRegistryHive(FileName, &RegistryHive, CreateNew);
661   if (!NT_SUCCESS(Status))
662     {
663       DPRINT1("CmiCreateRegistryHive() failed (Status %lx)\n", Status);
664       KeBugCheck(0);
665       return(Status);
666     }
667
668   RtlInitUnicodeString(&uKeyName, FullName);
669
670   InitializeObjectAttributes(&ObjectAttributes,
671                              &uKeyName,
672                              0,
673                              NULL,
674                              NULL);
675
676   Status = ObCreateObject(&KeyHandle,
677                           STANDARD_RIGHTS_REQUIRED,
678                           &ObjectAttributes,
679                           CmiKeyType,
680                           (PVOID*)&NewKey);
681   if (!NT_SUCCESS(Status))
682     {
683       DPRINT1("ObCreateObject() failed (Status %lx)\n", Status);
684       KeBugCheck(0);
685       CmiRemoveRegistryHive(RegistryHive);
686       return(Status);
687     }
688
689   NewKey->RegistryHive = RegistryHive;
690   NewKey->BlockOffset = RegistryHive->HiveHeader->RootKeyCell;
691   NewKey->KeyCell = CmiGetBlock(RegistryHive, NewKey->BlockOffset, NULL);
692   NewKey->Flags = 0;
693   NewKey->NumberOfSubKeys = 0;
694   NewKey->SubKeys = ExAllocatePool(PagedPool,
695   NewKey->KeyCell->NumberOfSubKeys * sizeof(DWORD));
696
697   if ((NewKey->SubKeys == NULL) && (NewKey->KeyCell->NumberOfSubKeys != 0))
698     {
699       DPRINT("NumberOfSubKeys %d\n", NewKey->KeyCell->NumberOfSubKeys);
700       ZwClose(NewKey);
701       CmiRemoveRegistryHive(RegistryHive);
702       return(STATUS_INSUFFICIENT_RESOURCES);
703     }
704
705   NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
706   NewKey->Name = ExAllocatePool(PagedPool, strlen(KeyName));
707
708   if ((NewKey->Name == NULL) && (strlen(KeyName) != 0))
709     {
710       DPRINT("strlen(KeyName) %d\n", strlen(KeyName));
711       if (NewKey->SubKeys != NULL)
712         ExFreePool(NewKey->SubKeys);
713       ZwClose(NewKey);
714       CmiRemoveRegistryHive(RegistryHive);
715       return(STATUS_INSUFFICIENT_RESOURCES);
716     }
717
718   NewKey->NameSize = strlen(KeyName);
719   memcpy(NewKey->Name, KeyName, strlen(KeyName));
720   CmiAddKeyToList(Parent, NewKey);
721
722   VERIFY_KEY_OBJECT(NewKey);
723
724   return(STATUS_SUCCESS);
725 }
726
727
728 NTSTATUS
729 CmiInitializeHive(PWSTR FileName,
730   PWSTR FullName,
731   PCHAR KeyName,
732   PKEY_OBJECT Parent,
733   BOOLEAN CreateNew)
734 {
735   NTSTATUS Status;
736
737   DPRINT("CmiInitializeHive(%s) called\n", KeyName);
738
739   /* Try to connect the hive */
740   //Status = CmiConnectHive(FileName, FullName, KeyName, Parent, FALSE);
741   Status = CmiConnectHive(FileName, FullName, KeyName, Parent, CreateNew);
742
743   if (!NT_SUCCESS(Status))
744     {
745 #if 0
746 #ifdef WIN32_REGDBG
747       WCHAR AltFileName[MAX_PATH];
748
749       CPRINT("WARNING! Registry file %S not found\n", FileName);
750       //DPRINT("Status %.08x\n", Status);
751
752       wcscpy(AltFileName, FileName);
753       wcscat(AltFileName, L".alt");
754
755       DPRINT("Attempting to connect the alternative hive %S\n", AltFileName);
756       /* Try to connect the alternative hive */
757       Status = CmiConnectHive(AltFileName, FullName, KeyName, Parent, TRUE);
758
759       if (!NT_SUCCESS(Status)) {
760               CPRINT("WARNING! Alternative registry file %S not found\n", AltFileName);
761             //DPRINT("Status %.08x\n", Status);
762           }
763 #endif
764 #endif
765     }
766
767   DPRINT("CmiInitializeHive() done\n");
768
769   return(Status);
770 }
771
772
773 NTSTATUS
774 CmiInitHives(BOOLEAN SetUpBoot)
775 {
776   PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
777   OBJECT_ATTRIBUTES ObjectAttributes;
778   UNICODE_STRING KeyName;
779   UNICODE_STRING ValueName;
780   HANDLE KeyHandle;
781
782   NTSTATUS Status;
783
784   WCHAR ConfigPath[MAX_PATH];
785
786   ULONG BufferSize;
787   ULONG ResultSize;
788   PWSTR EndPtr;
789
790
791   DPRINT("CmiInitHives() called\n");
792
793   if (SetUpBoot == TRUE)
794   {
795     RtlInitUnicodeStringFromLiteral(&KeyName,
796                                     L"\\Registry\\Machine\\HARDWARE");
797     InitializeObjectAttributes(&ObjectAttributes,
798                                &KeyName,
799                                OBJ_CASE_INSENSITIVE,
800                                NULL,
801                                NULL);
802     Status =  NtOpenKey(&KeyHandle,
803                         KEY_ALL_ACCESS,
804                         &ObjectAttributes);
805     if (!NT_SUCCESS(Status))
806     {
807       DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
808       return(Status);
809     }
810
811     RtlInitUnicodeStringFromLiteral(&ValueName,
812                                     L"InstallPath");
813
814     BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
815     ValueInfo = ExAllocatePool(PagedPool,
816                                BufferSize);
817     if (ValueInfo == NULL)
818     {
819       NtClose(KeyHandle);
820       return(STATUS_INSUFFICIENT_RESOURCES);
821     }
822
823     Status = NtQueryValueKey(KeyHandle,
824                              &ValueName,
825                              KeyValuePartialInformation,
826                              ValueInfo,
827                              BufferSize,
828                              &ResultSize);
829     NtClose(KeyHandle);
830     if (ValueInfo == NULL)
831     {
832       ExFreePool(ValueInfo);
833       return(Status);
834     }
835
836     RtlCopyMemory(ConfigPath,
837                   ValueInfo->Data,
838                   ValueInfo->DataLength);
839     ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = (WCHAR)0;
840     ExFreePool(ValueInfo);
841   }
842   else
843   {
844     wcscpy(ConfigPath, L"\\SystemRoot");
845   }
846   wcscat(ConfigPath, L"\\system32\\config");
847
848   DPRINT("ConfigPath: %S\n", ConfigPath);
849
850   EndPtr = ConfigPath + wcslen(ConfigPath);
851
852   CmiDoVerify = TRUE;
853
854   /* FIXME: Save boot log */
855
856   /* FIXME: Rename \Registry\Machine\System */
857
858   /* Connect the SYSTEM hive */
859 //  Status = CmiInitializeHive(SYSTEM_REG_FILE, REG_SYSTEM_KEY_NAME, "System", CmiMachineKey, SetUpBoot);
860 //  assert(NT_SUCCESS(Status));
861
862   /* FIXME: Synchronize old and new system hive (??) */
863
864   /* FIXME: Delete old system hive */
865
866   /* Connect the SOFTWARE hive */
867   wcscpy(EndPtr, REG_SOFTWARE_FILE_NAME);
868   DPRINT1("ConfigPath: %S\n", ConfigPath);
869
870   Status = CmiInitializeHive(ConfigPath,
871                              REG_SOFTWARE_KEY_NAME,
872                              "Software",
873                              CmiMachineKey,
874                              SetUpBoot);
875   if (!NT_SUCCESS(Status))
876   {
877     DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
878     return(Status);
879   }
880
881   /* Connect the SAM hive */
882   wcscpy(EndPtr, REG_SAM_FILE_NAME);
883   DPRINT1("ConfigPath: %S\n", ConfigPath);
884
885   Status = CmiInitializeHive(ConfigPath,
886                              REG_SAM_KEY_NAME,
887                              "Sam",
888                              CmiMachineKey,
889                              SetUpBoot);
890   if (!NT_SUCCESS(Status))
891   {
892     DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
893     return(Status);
894   }
895
896   /* Connect the SECURITY hive */
897   wcscpy(EndPtr, REG_SEC_FILE_NAME);
898   DPRINT1("ConfigPath: %S\n", ConfigPath);
899   Status = CmiInitializeHive(ConfigPath,
900                              REG_SEC_KEY_NAME,
901                              "Security",
902                              CmiMachineKey,
903                              SetUpBoot);
904   if (!NT_SUCCESS(Status))
905   {
906     DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
907     return(Status);
908   }
909
910   /* Connect the DEFAULT hive */
911   wcscpy(EndPtr, REG_USER_FILE_NAME);
912   DPRINT1("ConfigPath: %S\n", ConfigPath);
913
914   Status = CmiInitializeHive(ConfigPath,
915                              REG_USER_KEY_NAME,
916                              ".Default",
917                              CmiUserKey,
918                              SetUpBoot);
919   if (!NT_SUCCESS(Status))
920   {
921     DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
922     return(Status);
923   }
924
925   /* FIXME : initialize standards symbolic links */
926
927 //  CmiCheckRegistry(TRUE);
928
929   /* Start automatic hive synchronization */
930   KeInitializeDpc(&CmiHiveSyncDpc,
931                   CmiHiveSyncDpcRoutine,
932                   NULL);
933   KeInitializeTimer(&CmiHiveSyncTimer);
934   CmiHiveSyncEnabled = TRUE;
935
936   DPRINT("CmiInitHives() done\n");
937
938   return(STATUS_SUCCESS);
939 }
940
941
942 VOID
943 CmShutdownRegistry(VOID)
944 {
945   PREGISTRY_HIVE Hive;
946   PLIST_ENTRY Entry;
947
948   DPRINT1("CmShutdownRegistry() called\n");
949
950   /* Stop automatic hive synchronization */
951   CmiHiveSyncEnabled = FALSE;
952
953   /* Acquire hive list lock exclusively */
954   ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
955
956   Entry = CmiHiveListHead.Flink;
957   while (Entry != &CmiHiveListHead)
958     {
959       Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
960
961       if (IsPermanentHive(Hive))
962         {
963           /* Acquire hive resource exclusively */
964           ExAcquireResourceExclusiveLite(&Hive->HiveResource,
965                                          TRUE);
966
967           /* Flush non-volatile hive */
968           CmiFlushRegistryHive(Hive);
969
970           /* Dereference file */
971           ObDereferenceObject(Hive->FileObject);
972           Hive->FileObject = NULL;
973
974           /* Release hive resource */
975           ExReleaseResourceLite(&Hive->HiveResource);
976         }
977
978       Entry = Entry->Flink;
979     }
980
981   /* Release hive list lock */
982   ExReleaseResourceLite(&CmiHiveListLock);
983
984   DPRINT1("CmShutdownRegistry() done\n");
985 }
986
987
988 VOID STDCALL
989 CmiHiveSyncRoutine(PVOID DeferredContext)
990 {
991   PREGISTRY_HIVE Hive;
992   PLIST_ENTRY Entry;
993
994   DPRINT1("CmiHiveSyncRoutine() called\n");
995
996   CmiHiveSyncPending = FALSE;
997
998   /* Acquire hive list lock exclusively */
999   ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1000
1001   Entry = CmiHiveListHead.Flink;
1002   while (Entry != &CmiHiveListHead)
1003     {
1004       Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
1005
1006       if (IsPermanentHive(Hive))
1007         {
1008           /* Acquire hive resource exclusively */
1009           ExAcquireResourceExclusiveLite(&Hive->HiveResource,
1010                                          TRUE);
1011
1012           /* Flush non-volatile hive */
1013           CmiFlushRegistryHive(Hive);
1014
1015           /* Release hive resource */
1016           ExReleaseResourceLite(&Hive->HiveResource);
1017         }
1018
1019       Entry = Entry->Flink;
1020     }
1021
1022   /* Release hive list lock */
1023   ExReleaseResourceLite(&CmiHiveListLock);
1024
1025   DPRINT("DeferredContext %x\n", DeferredContext);
1026   ExFreePool(DeferredContext);
1027 }
1028
1029
1030 static VOID STDCALL
1031 CmiHiveSyncDpcRoutine(PKDPC Dpc,
1032                       PVOID DeferredContext,
1033                       PVOID SystemArgument1,
1034                       PVOID SystemArgument2)
1035 {
1036   PWORK_QUEUE_ITEM WorkQueueItem;
1037
1038   WorkQueueItem = ExAllocatePool(NonPagedPool,
1039                                  sizeof(WORK_QUEUE_ITEM));
1040   if (WorkQueueItem == NULL)
1041     {
1042       DbgPrint("Failed to allocate work item\n");
1043       return;
1044     }
1045
1046   ExInitializeWorkItem(WorkQueueItem,
1047                        CmiHiveSyncRoutine,
1048                        WorkQueueItem);
1049
1050   DPRINT("DeferredContext %x\n", WorkQueueItem);
1051   ExQueueWorkItem(WorkQueueItem,
1052                   CriticalWorkQueue);
1053 }
1054
1055
1056 VOID
1057 CmiSyncHives(VOID)
1058 {
1059   LARGE_INTEGER Timeout;
1060
1061   DPRINT("CmiSyncHives() called\n");
1062
1063   if (CmiHiveSyncEnabled == FALSE ||
1064       CmiHiveSyncPending == TRUE)
1065     return;
1066
1067   CmiHiveSyncPending = TRUE;
1068
1069
1070   Timeout.QuadPart = -50000000LL;
1071   KeSetTimer(&CmiHiveSyncTimer,
1072              Timeout,
1073              &CmiHiveSyncDpc);
1074 }
1075
1076 /* EOF */