3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/registry.c
6 * PURPOSE: Registry functions
8 * PROGRAMMERS: Rex Jolliff
15 #include <internal/debug.h>
19 /* GLOBALS ******************************************************************/
21 POBJECT_TYPE CmiKeyType
= NULL
;
22 PREGISTRY_HIVE CmiVolatileHive
= NULL
;
24 LIST_ENTRY CmiHiveListHead
;
26 ERESOURCE CmiRegistryLock
;
28 KTIMER CmiWorkerTimer
;
29 LIST_ENTRY CmiKeyObjectListHead
;
32 volatile BOOLEAN CmiHiveSyncEnabled
= FALSE
;
33 volatile BOOLEAN CmiHiveSyncPending
= FALSE
;
35 KTIMER CmiHiveSyncTimer
;
37 static GENERIC_MAPPING CmiKeyMapping
=
38 {KEY_READ
, KEY_WRITE
, KEY_EXECUTE
, KEY_ALL_ACCESS
};
43 CmiCheckKey(BOOLEAN Verbose
,
47 CmiCreateCurrentControlSetLink(VOID
);
50 CmiHiveSyncDpcRoutine(PKDPC Dpc
,
51 PVOID DeferredContext
,
52 PVOID SystemArgument1
,
53 PVOID SystemArgument2
);
55 extern LIST_ENTRY CmiCallbackHead
;
56 extern FAST_MUTEX CmiCallbackLock
;
58 /* FUNCTIONS ****************************************************************/
61 CmiCheckSubKeys(BOOLEAN Verbose
,
64 OBJECT_ATTRIBUTES ObjectAttributes
;
65 PKEY_NODE_INFORMATION KeyInfo
;
66 WCHAR KeyBuffer
[MAX_PATH
];
67 UNICODE_STRING KeyPath
;
78 BufferSize
= sizeof(KEY_NODE_INFORMATION
) + 4096;
79 KeyInfo
= ExAllocatePool(PagedPool
, BufferSize
);
81 Status
= ZwEnumerateKey(Key
,
87 if (!NT_SUCCESS(Status
))
90 if (Status
== STATUS_NO_MORE_ENTRIES
)
91 Status
= STATUS_SUCCESS
;
97 KeyInfo
->NameLength
/ sizeof(WCHAR
));
101 DbgPrint("Key: %S\n", Name
);
104 /* FIXME: Check info. */
108 wcscpy(KeyBuffer
, L
"\\Registry\\");
109 wcscat(KeyBuffer
, Name
);
111 RtlInitUnicodeString(&KeyPath
, KeyBuffer
);
113 InitializeObjectAttributes(&ObjectAttributes
,
115 OBJ_CASE_INSENSITIVE
,
119 Status
= ZwOpenKey(&SubKey
,
123 ASSERT(NT_SUCCESS(Status
));
125 CmiCheckKey(Verbose
, SubKey
);
132 ASSERT(NT_SUCCESS(Status
));
137 CmiCheckValues(BOOLEAN Verbose
,
140 PKEY_NODE_INFORMATION ValueInfo
;
141 WCHAR Name
[MAX_PATH
];
150 BufferSize
= sizeof(KEY_NODE_INFORMATION
) + 4096;
151 ValueInfo
= ExAllocatePool(PagedPool
, BufferSize
);
153 Status
= ZwEnumerateValueKey(Key
,
159 if (!NT_SUCCESS(Status
))
161 ExFreePool(ValueInfo
);
162 if (Status
== STATUS_NO_MORE_ENTRIES
)
163 Status
= STATUS_SUCCESS
;
169 ValueInfo
->NameLength
/ sizeof(WCHAR
));
173 DbgPrint("Value: %S\n", Name
);
176 /* FIXME: Check info. */
178 ExFreePool(ValueInfo
);
183 ASSERT(NT_SUCCESS(Status
));
188 CmiCheckKey(BOOLEAN Verbose
,
191 CmiCheckValues(Verbose
, Key
);
192 CmiCheckSubKeys(Verbose
, Key
);
197 CmiCheckByName(BOOLEAN Verbose
,
200 OBJECT_ATTRIBUTES ObjectAttributes
;
201 WCHAR KeyPathBuffer
[MAX_PATH
];
202 UNICODE_STRING KeyPath
;
206 wcscpy(KeyPathBuffer
, L
"\\Registry\\");
207 wcscat(KeyPathBuffer
, KeyName
);
209 RtlInitUnicodeString(&KeyPath
, KeyPathBuffer
);
211 InitializeObjectAttributes(&ObjectAttributes
,
213 OBJ_CASE_INSENSITIVE
,
217 Status
= ZwOpenKey(&Key
,
223 if (!NT_SUCCESS(Status
))
225 DbgPrint("KeyPath %wZ Status: %.08x", KeyPath
, Status
);
226 DbgPrint("KeyPath %S Status: %.08x", KeyPath
.Buffer
, Status
);
227 ASSERT(NT_SUCCESS(Status
));
231 CmiCheckKey(Verbose
, Key
);
238 CmiCheckRegistry(BOOLEAN Verbose
)
241 DbgPrint("Checking registry internals\n");
243 CmiCheckByName(Verbose
, L
"Machine");
244 CmiCheckByName(Verbose
, L
"User");
248 CmiWorkerThread(PVOID Param
)
251 PLIST_ENTRY CurrentEntry
;
252 PKEY_OBJECT CurrentKey
;
258 Status
= KeWaitForSingleObject(&CmiWorkerTimer
,
263 if (Status
== STATUS_SUCCESS
)
265 DPRINT("CmiWorkerThread\n");
267 /* Acquire hive lock */
268 KeEnterCriticalRegion();
269 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
274 CurrentEntry
= CmiKeyObjectListHead
.Blink
;
275 while (CurrentEntry
!= &CmiKeyObjectListHead
)
277 CurrentKey
= CONTAINING_RECORD(CurrentEntry
, KEY_OBJECT
, ListEntry
);
278 if (CurrentKey
->TimeStamp
+ 120 > CmiTimer
)
280 /* The object was accessed in the last 10min */
283 if (1 == ObGetObjectPointerCount(CurrentKey
) &&
284 !(CurrentKey
->Flags
& KO_MARKED_FOR_DELETE
))
286 ObDereferenceObject(CurrentKey
);
287 CurrentEntry
= CmiKeyObjectListHead
.Blink
;
292 CurrentEntry
= CurrentEntry
->Blink
;
295 ExReleaseResourceLite(&CmiRegistryLock
);
296 KeLeaveCriticalRegion();
298 DPRINT("Removed %d key objects\n", Count
);
311 CmInitHives(BOOLEAN SetupBoot
)
315 /* Load Registry Hives. This one can be missing. */
316 if (CachedModules
[SystemRegistry
]) {
317 BaseAddress
= (PCHAR
)CachedModules
[SystemRegistry
]->ModStart
;
318 CmImportSystemHive(BaseAddress
,
319 CachedModules
[SystemRegistry
]->ModEnd
- (ULONG_PTR
)BaseAddress
);
322 BaseAddress
= (PCHAR
)CachedModules
[HardwareRegistry
]->ModStart
;
323 CmImportHardwareHive(BaseAddress
,
324 CachedModules
[HardwareRegistry
]->ModEnd
- (ULONG_PTR
)BaseAddress
);
327 /* Create dummy keys if no hardware hive was found */
328 CmImportHardwareHive (NULL
, 0);
330 /* Initialize volatile registry settings */
331 if (SetupBoot
== FALSE
) CmInit2((PCHAR
)KeLoaderBlock
.CommandLine
);
335 CmInitializeRegistry(VOID
)
337 OBJECT_ATTRIBUTES ObjectAttributes
;
338 UNICODE_STRING KeyName
;
341 PSECURITY_CELL RootSecurityCell
;
343 HANDLE RootKeyHandle
;
346 LARGE_INTEGER DueTime
;
350 /* Initialize the Key object type */
351 CmiKeyType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
353 CmiKeyType
->Tag
= TAG('R', 'e', 'g', 'K');
354 CmiKeyType
->TotalObjects
= 0;
355 CmiKeyType
->TotalHandles
= 0;
356 CmiKeyType
->PeakObjects
= 0;
357 CmiKeyType
->PeakHandles
= 0;
358 CmiKeyType
->PagedPoolCharge
= 0;
359 CmiKeyType
->NonpagedPoolCharge
= sizeof(KEY_OBJECT
);
360 CmiKeyType
->Mapping
= &CmiKeyMapping
;
361 CmiKeyType
->Dump
= NULL
;
362 CmiKeyType
->Open
= NULL
;
363 CmiKeyType
->Close
= NULL
;
364 CmiKeyType
->Delete
= CmiObjectDelete
;
365 CmiKeyType
->Parse
= CmiObjectParse
;
366 CmiKeyType
->Security
= CmiObjectSecurity
;
367 CmiKeyType
->QueryName
= CmiObjectQueryName
;
368 CmiKeyType
->OkayToClose
= NULL
;
369 RtlInitUnicodeString(&CmiKeyType
->TypeName
, L
"Key");
371 ObpCreateTypeObject (CmiKeyType
);
373 /* Initialize the hive list */
374 InitializeListHead(&CmiHiveListHead
);
376 /* Initialize registry lock */
377 ExInitializeResourceLite(&CmiRegistryLock
);
379 /* Initialize the key object list */
380 InitializeListHead(&CmiKeyObjectListHead
);
382 /* Initialize the worker timer */
383 KeInitializeTimerEx(&CmiWorkerTimer
, SynchronizationTimer
);
385 /* Initialize the worker thread */
386 Status
= PsCreateSystemThread(&ThreadHandle
,
393 if (!NT_SUCCESS(Status
))
398 /* Start the timer */
399 DueTime
.QuadPart
= -1;
400 KeSetTimerEx(&CmiWorkerTimer
, DueTime
, 5000, NULL
); /* 5sec */
402 /* Build volatile registry store */
403 Status
= CmiCreateVolatileHive (&CmiVolatileHive
);
404 ASSERT(NT_SUCCESS(Status
));
406 InitializeListHead(&CmiCallbackHead
);
407 ExInitializeFastMutex(&CmiCallbackLock
);
409 /* Create '\Registry' key. */
410 RtlInitUnicodeString(&KeyName
, REG_ROOT_KEY_NAME
);
411 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, 0, NULL
, NULL
);
412 Status
= ObCreateObject(KernelMode
,
421 ASSERT(NT_SUCCESS(Status
));
422 Status
= ObInsertObject(RootKey
,
428 ASSERT(NT_SUCCESS(Status
));
429 RootKey
->RegistryHive
= CmiVolatileHive
;
430 RootKey
->KeyCellOffset
= CmiVolatileHive
->HiveHeader
->RootKeyOffset
;
431 RootKey
->KeyCell
= CmiGetCell (CmiVolatileHive
, RootKey
->KeyCellOffset
, NULL
);
432 RootKey
->ParentKey
= RootKey
;
434 RootKey
->NumberOfSubKeys
= 0;
435 RootKey
->SubKeys
= NULL
;
436 RootKey
->SizeOfSubKeys
= 0;
437 InsertTailList(&CmiKeyObjectListHead
, &RootKey
->ListEntry
);
438 Status
= RtlpCreateUnicodeString(&RootKey
->Name
, L
"Registry", NonPagedPool
);
439 ASSERT(NT_SUCCESS(Status
));
442 Status
= CmiAllocateCell(CmiVolatileHive
,
443 0x10, //LONG CellSize,
444 (PVOID
*)&RootSecurityCell
,
445 &RootKey
->KeyCell
->SecurityKeyOffset
);
446 ASSERT(NT_SUCCESS(Status
));
448 /* Copy the security descriptor */
450 CmiVolatileHive
->RootSecurityCell
= RootSecurityCell
;
454 /* Create '\Registry\Machine' key. */
455 RtlInitUnicodeString(&KeyName
,
457 InitializeObjectAttributes(&ObjectAttributes
,
462 Status
= ZwCreateKey(&KeyHandle
,
469 ASSERT(NT_SUCCESS(Status
));
471 /* Create '\Registry\User' key. */
472 RtlInitUnicodeString(&KeyName
,
474 InitializeObjectAttributes(&ObjectAttributes
,
479 Status
= ZwCreateKey(&KeyHandle
,
486 ASSERT(NT_SUCCESS(Status
));
491 CmInit2(PCHAR CommandLine
)
494 BOOLEAN MiniNT
= FALSE
;
495 PWCHAR SystemBootDevice
;
496 PWCHAR SystemStartOptions
;
500 /* Create the 'CurrentControlSet' link. */
501 Status
= CmiCreateCurrentControlSetLink();
502 if (!NT_SUCCESS(Status
))
503 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
506 * Parse the system boot device.
509 SystemBootDevice
= ExAllocatePool(PagedPool
,
510 (strlen(CommandLine
) + 1) * sizeof(WCHAR
));
511 if (SystemBootDevice
== NULL
)
513 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
516 while (*CommandLine
!= 0 && *CommandLine
!= ' ')
517 SystemBootDevice
[Position
++] = *(CommandLine
++);
518 SystemBootDevice
[Position
++] = 0;
521 * Write the system boot device to registry.
523 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
524 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
528 Position
* sizeof(WCHAR
));
529 if (!NT_SUCCESS(Status
))
531 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
535 * Parse the system start options.
538 SystemStartOptions
= SystemBootDevice
;
539 while ((CommandLine
= strchr(CommandLine
, '/')) != NULL
)
541 /* Skip over the slash */
544 /* Special options */
545 if (!_strnicmp(CommandLine
, "MININT", 6))
547 else if (!_strnicmp(CommandLine
, "DEBUGPORT=PICE", 14))
550 /* Add a space between the options */
552 SystemStartOptions
[Position
++] = L
' ';
554 /* Copy the command */
555 while (*CommandLine
!= 0 && *CommandLine
!= ' ')
556 SystemStartOptions
[Position
++] = *(CommandLine
++);
558 SystemStartOptions
[Position
++] = 0;
561 * Write the system start options to registry.
563 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
564 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
565 L
"SystemStartOptions",
568 Position
* sizeof(WCHAR
));
569 if (!NT_SUCCESS(Status
))
571 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
575 * Create a CurrentControlSet\Control\MiniNT key that is used
576 * to detect WinPE/MiniNT systems.
580 Status
= RtlCreateRegistryKey(RTL_REGISTRY_CONTROL
, L
"MiniNT");
581 if (!NT_SUCCESS(Status
))
582 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
585 /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
586 Status
= RtlWriteRegistryValue(
587 RTL_REGISTRY_SERVICES
,
593 if (!NT_SUCCESS(Status
))
594 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
596 ExFreePool(SystemBootDevice
);
601 CmiCreateCurrentControlSetLink(VOID
)
603 RTL_QUERY_REGISTRY_TABLE QueryTable
[5];
604 WCHAR TargetNameBuffer
[80];
605 ULONG TargetNameLength
;
606 UNICODE_STRING LinkName
;
607 UNICODE_STRING LinkValue
;
613 OBJECT_ATTRIBUTES ObjectAttributes
;
616 DPRINT("CmiCreateCurrentControlSetLink() called\n");
618 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
620 QueryTable
[0].Name
= L
"Current";
621 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
622 QueryTable
[0].EntryContext
= &CurrentSet
;
624 QueryTable
[1].Name
= L
"Default";
625 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
626 QueryTable
[1].EntryContext
= &DefaultSet
;
628 QueryTable
[2].Name
= L
"Failed";
629 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
630 QueryTable
[2].EntryContext
= &Failed
;
632 QueryTable
[3].Name
= L
"LastKnownGood";
633 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
634 QueryTable
[3].EntryContext
= &LastKnownGood
;
636 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
637 L
"\\Registry\\Machine\\SYSTEM\\Select",
641 if (!NT_SUCCESS(Status
))
646 DPRINT("Current %ld Default %ld\n", CurrentSet
, DefaultSet
);
648 swprintf(TargetNameBuffer
,
649 L
"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
651 TargetNameLength
= wcslen(TargetNameBuffer
) * sizeof(WCHAR
);
653 DPRINT("Link target '%S'\n", TargetNameBuffer
);
655 RtlRosInitUnicodeStringFromLiteral(&LinkName
,
656 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
657 InitializeObjectAttributes(&ObjectAttributes
,
659 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_OPENLINK
,
662 Status
= ZwCreateKey(&KeyHandle
,
663 KEY_ALL_ACCESS
| KEY_CREATE_LINK
,
667 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
669 if (!NT_SUCCESS(Status
))
671 DPRINT1("ZwCreateKey() failed (Status %lx)\n", Status
);
675 RtlRosInitUnicodeStringFromLiteral(&LinkValue
,
676 L
"SymbolicLinkValue");
677 Status
= ZwSetValueKey(KeyHandle
,
681 (PVOID
)TargetNameBuffer
,
683 if (!NT_SUCCESS(Status
))
685 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
695 CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
696 IN PREGISTRY_HIVE RegistryHive
)
698 UNICODE_STRING RemainingPath
;
699 PKEY_OBJECT ParentKey
;
704 DPRINT("CmiConnectHive(%p, %p) called.\n",
705 KeyObjectAttributes
, RegistryHive
);
707 Status
= ObFindObject(KeyObjectAttributes
,
711 if (!NT_SUCCESS(Status
))
716 DPRINT ("RemainingPath %wZ\n", &RemainingPath
);
718 if ((RemainingPath
.Buffer
== NULL
) || (RemainingPath
.Buffer
[0] == 0))
720 ObDereferenceObject (ParentKey
);
721 RtlFreeUnicodeString(&RemainingPath
);
722 return STATUS_OBJECT_NAME_COLLISION
;
725 /* Ignore leading backslash */
726 SubName
= RemainingPath
.Buffer
;
727 if (*SubName
== L
'\\')
730 /* If RemainingPath contains \ we must return error
731 because CmiConnectHive() can not create trees */
732 if (wcschr (SubName
, L
'\\') != NULL
)
734 ObDereferenceObject (ParentKey
);
735 RtlFreeUnicodeString(&RemainingPath
);
736 return STATUS_OBJECT_NAME_NOT_FOUND
;
739 DPRINT("RemainingPath %wZ ParentKey %p\n",
740 &RemainingPath
, ParentKey
);
742 Status
= ObCreateObject(KernelMode
,
751 if (!NT_SUCCESS(Status
))
753 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status
);
754 ObDereferenceObject (ParentKey
);
755 RtlFreeUnicodeString(&RemainingPath
);
759 NewKey
->RegistryHive
= RegistryHive
;
760 NewKey
->KeyCellOffset
= RegistryHive
->HiveHeader
->RootKeyOffset
;
761 NewKey
->KeyCell
= CmiGetCell (RegistryHive
, NewKey
->KeyCellOffset
, NULL
);
763 NewKey
->NumberOfSubKeys
= 0;
764 InsertTailList(&CmiKeyObjectListHead
, &NewKey
->ListEntry
);
765 if (NewKey
->KeyCell
->NumberOfSubKeys
!= 0)
767 NewKey
->SubKeys
= ExAllocatePool(NonPagedPool
,
768 NewKey
->KeyCell
->NumberOfSubKeys
* sizeof(ULONG
));
769 if (NewKey
->SubKeys
== NULL
)
771 DPRINT("ExAllocatePool() failed\n");
772 ObDereferenceObject (NewKey
);
773 ObDereferenceObject (ParentKey
);
774 RtlFreeUnicodeString(&RemainingPath
);
775 return STATUS_INSUFFICIENT_RESOURCES
;
780 NewKey
->SubKeys
= NULL
;
783 DPRINT ("SubName %S\n", SubName
);
785 Status
= RtlpCreateUnicodeString(&NewKey
->Name
,
786 SubName
, NonPagedPool
);
787 RtlFreeUnicodeString(&RemainingPath
);
788 if (!NT_SUCCESS(Status
))
790 DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status
);
791 if (NewKey
->SubKeys
!= NULL
)
793 ExFreePool (NewKey
->SubKeys
);
795 ObDereferenceObject (NewKey
);
796 ObDereferenceObject (ParentKey
);
797 return STATUS_INSUFFICIENT_RESOURCES
;
800 CmiAddKeyToList (ParentKey
, NewKey
);
801 ObDereferenceObject (ParentKey
);
803 VERIFY_KEY_OBJECT(NewKey
);
805 /* Note: Do not dereference NewKey here! */
807 return STATUS_SUCCESS
;
812 CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
813 OUT PREGISTRY_HIVE
*RegistryHive
)
815 PKEY_OBJECT KeyObject
;
819 PLIST_ENTRY CurrentEntry
;
820 PKEY_OBJECT CurrentKey
;
822 DPRINT("CmiDisconnectHive() called\n");
824 *RegistryHive
= NULL
;
826 Status
= ObOpenObjectByName (KeyObjectAttributes
,
830 STANDARD_RIGHTS_REQUIRED
,
833 if (!NT_SUCCESS(Status
))
835 DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status
);
839 Status
= ObReferenceObjectByHandle (KeyHandle
,
840 STANDARD_RIGHTS_REQUIRED
,
846 if (!NT_SUCCESS(Status
))
848 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status
);
851 DPRINT ("KeyObject %p Hive %p\n", KeyObject
, KeyObject
->RegistryHive
);
853 if (!(KeyObject
->KeyCell
->Flags
& REG_KEY_ROOT_CELL
))
855 DPRINT1 ("Key is not the Hive-Root-Key\n");
856 ObDereferenceObject (KeyObject
);
857 return STATUS_INVALID_PARAMETER
;
860 /* Acquire registry lock exclusively */
861 KeEnterCriticalRegion();
862 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
864 CurrentEntry
= CmiKeyObjectListHead
.Flink
;
865 while (CurrentEntry
!= &CmiKeyObjectListHead
)
867 CurrentKey
= CONTAINING_RECORD(CurrentEntry
, KEY_OBJECT
, ListEntry
);
868 if (1 == ObGetObjectPointerCount(CurrentKey
) &&
869 !(CurrentKey
->Flags
& KO_MARKED_FOR_DELETE
))
871 ObDereferenceObject(CurrentKey
);
872 CurrentEntry
= CmiKeyObjectListHead
.Flink
;
876 CurrentEntry
= CurrentEntry
->Flink
;
880 if (ObGetObjectHandleCount (KeyObject
) != 0 ||
881 ObGetObjectPointerCount (KeyObject
) != 2)
883 DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject
), ObGetObjectPointerCount (KeyObject
));
884 ObDereferenceObject (KeyObject
);
886 /* Release registry lock */
887 ExReleaseResourceLite (&CmiRegistryLock
);
888 KeLeaveCriticalRegion();
890 return STATUS_UNSUCCESSFUL
;
893 Hive
= KeyObject
->RegistryHive
;
895 /* Dereference KeyObject twice to delete it */
896 ObDereferenceObject (KeyObject
);
897 ObDereferenceObject (KeyObject
);
899 *RegistryHive
= Hive
;
901 /* Release registry lock */
902 ExReleaseResourceLite (&CmiRegistryLock
);
903 KeLeaveCriticalRegion();
905 DPRINT ("CmiDisconnectHive() done\n");
907 return STATUS_SUCCESS
;
912 CmiInitControlSetLink (VOID
)
914 OBJECT_ATTRIBUTES ObjectAttributes
;
915 UNICODE_STRING ControlSetKeyName
;
916 UNICODE_STRING ControlSetLinkName
;
917 UNICODE_STRING ControlSetValueName
;
921 /* Create 'ControlSet001' key */
922 RtlRosInitUnicodeStringFromLiteral (&ControlSetKeyName
,
923 L
"\\Registry\\Machine\\SYSTEM\\ControlSet001");
924 InitializeObjectAttributes (&ObjectAttributes
,
926 OBJ_CASE_INSENSITIVE
,
929 Status
= ZwCreateKey (&KeyHandle
,
934 REG_OPTION_NON_VOLATILE
,
936 if (!NT_SUCCESS(Status
))
938 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status
);
943 /* Link 'CurrentControlSet' to 'ControlSet001' key */
944 RtlRosInitUnicodeStringFromLiteral (&ControlSetLinkName
,
945 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
946 InitializeObjectAttributes (&ObjectAttributes
,
948 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_OPENLINK
,
951 Status
= ZwCreateKey (&KeyHandle
,
952 KEY_ALL_ACCESS
| KEY_CREATE_LINK
,
956 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
958 if (!NT_SUCCESS(Status
))
960 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status
);
964 RtlRosInitUnicodeStringFromLiteral (&ControlSetValueName
,
965 L
"SymbolicLinkValue");
966 Status
= ZwSetValueKey (KeyHandle
,
967 &ControlSetValueName
,
970 (PVOID
)ControlSetKeyName
.Buffer
,
971 ControlSetKeyName
.Length
);
972 if (!NT_SUCCESS(Status
))
974 DPRINT1 ("ZwSetValueKey() failed (Status %lx)\n", Status
);
978 return STATUS_SUCCESS
;
983 CmiInitHives(BOOLEAN SetupBoot
)
985 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
986 OBJECT_ATTRIBUTES ObjectAttributes
;
987 UNICODE_STRING FileName
;
988 UNICODE_STRING KeyName
;
989 UNICODE_STRING ValueName
;
994 WCHAR ConfigPath
[MAX_PATH
];
1001 DPRINT("CmiInitHives() called\n");
1003 if (SetupBoot
== TRUE
)
1005 RtlRosInitUnicodeStringFromLiteral(&KeyName
,
1006 L
"\\Registry\\Machine\\HARDWARE");
1007 InitializeObjectAttributes(&ObjectAttributes
,
1009 OBJ_CASE_INSENSITIVE
,
1012 Status
= ZwOpenKey(&KeyHandle
,
1015 if (!NT_SUCCESS(Status
))
1017 DPRINT1("ZwOpenKey() failed (Status %lx)\n", Status
);
1021 RtlRosInitUnicodeStringFromLiteral(&ValueName
,
1024 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
1025 ValueInfo
= ExAllocatePool(PagedPool
,
1027 if (ValueInfo
== NULL
)
1030 return(STATUS_INSUFFICIENT_RESOURCES
);
1033 Status
= ZwQueryValueKey(KeyHandle
,
1035 KeyValuePartialInformation
,
1040 if (!NT_SUCCESS(Status
))
1042 ExFreePool(ValueInfo
);
1046 RtlCopyMemory(ConfigPath
,
1048 ValueInfo
->DataLength
);
1049 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = (WCHAR
)0;
1050 ExFreePool(ValueInfo
);
1054 wcscpy(ConfigPath
, L
"\\SystemRoot");
1056 wcscat(ConfigPath
, L
"\\system32\\config");
1058 DPRINT("ConfigPath: %S\n", ConfigPath
);
1060 EndPtr
= ConfigPath
+ wcslen(ConfigPath
);
1064 /* FIXME: Save boot log */
1066 /* Connect the SYSTEM hive only if it has been created */
1067 if (SetupBoot
== TRUE
)
1069 wcscpy(EndPtr
, REG_SYSTEM_FILE_NAME
);
1070 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1072 RtlInitUnicodeString (&KeyName
,
1073 REG_SYSTEM_KEY_NAME
);
1074 InitializeObjectAttributes(&ObjectAttributes
,
1076 OBJ_CASE_INSENSITIVE
,
1080 RtlInitUnicodeString (&FileName
,
1082 Status
= CmiLoadHive (&ObjectAttributes
,
1085 if (!NT_SUCCESS(Status
))
1087 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
1091 Status
= CmiInitControlSetLink ();
1092 if (!NT_SUCCESS(Status
))
1094 DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status
);
1099 /* Connect the SOFTWARE hive */
1100 wcscpy(EndPtr
, REG_SOFTWARE_FILE_NAME
);
1101 RtlInitUnicodeString (&FileName
,
1103 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1105 RtlInitUnicodeString (&KeyName
,
1106 REG_SOFTWARE_KEY_NAME
);
1107 InitializeObjectAttributes(&ObjectAttributes
,
1109 OBJ_CASE_INSENSITIVE
,
1113 Status
= CmiLoadHive (&ObjectAttributes
,
1116 if (!NT_SUCCESS(Status
))
1118 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1122 /* Connect the SAM hive */
1123 wcscpy(EndPtr
, REG_SAM_FILE_NAME
);
1124 RtlInitUnicodeString (&FileName
,
1126 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1128 RtlInitUnicodeString (&KeyName
,
1130 InitializeObjectAttributes(&ObjectAttributes
,
1132 OBJ_CASE_INSENSITIVE
,
1135 Status
= CmiLoadHive (&ObjectAttributes
,
1138 if (!NT_SUCCESS(Status
))
1140 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1144 /* Connect the SECURITY hive */
1145 wcscpy(EndPtr
, REG_SEC_FILE_NAME
);
1146 RtlInitUnicodeString (&FileName
,
1148 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1150 RtlInitUnicodeString (&KeyName
,
1152 InitializeObjectAttributes(&ObjectAttributes
,
1154 OBJ_CASE_INSENSITIVE
,
1157 Status
= CmiLoadHive (&ObjectAttributes
,
1160 if (!NT_SUCCESS(Status
))
1162 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1166 /* Connect the DEFAULT hive */
1167 wcscpy(EndPtr
, REG_DEFAULT_USER_FILE_NAME
);
1168 RtlInitUnicodeString (&FileName
,
1170 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1172 RtlInitUnicodeString (&KeyName
,
1173 REG_DEFAULT_USER_KEY_NAME
);
1174 InitializeObjectAttributes(&ObjectAttributes
,
1176 OBJ_CASE_INSENSITIVE
,
1179 Status
= CmiLoadHive (&ObjectAttributes
,
1182 if (!NT_SUCCESS(Status
))
1184 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1188 // CmiCheckRegistry(TRUE);
1190 /* Start automatic hive synchronization */
1191 KeInitializeDpc(&CmiHiveSyncDpc
,
1192 CmiHiveSyncDpcRoutine
,
1194 KeInitializeTimer(&CmiHiveSyncTimer
);
1195 CmiHiveSyncEnabled
= TRUE
;
1197 DPRINT("CmiInitHives() done\n");
1199 return(STATUS_SUCCESS
);
1204 CmShutdownRegistry(VOID
)
1206 PREGISTRY_HIVE Hive
;
1209 DPRINT("CmShutdownRegistry() called\n");
1211 /* Stop automatic hive synchronization */
1212 CmiHiveSyncEnabled
= FALSE
;
1214 /* Cancel pending hive synchronization */
1215 if (CmiHiveSyncPending
== TRUE
)
1217 KeCancelTimer(&CmiHiveSyncTimer
);
1218 CmiHiveSyncPending
= FALSE
;
1221 /* Acquire hive list lock exclusively */
1222 KeEnterCriticalRegion();
1223 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1225 Entry
= CmiHiveListHead
.Flink
;
1226 while (Entry
!= &CmiHiveListHead
)
1228 Hive
= CONTAINING_RECORD(Entry
, REGISTRY_HIVE
, HiveList
);
1230 if (!(IsNoFileHive(Hive
) || IsNoSynchHive(Hive
)))
1232 /* Flush non-volatile hive */
1233 CmiFlushRegistryHive(Hive
);
1236 Entry
= Entry
->Flink
;
1239 /* Release hive list lock */
1240 ExReleaseResourceLite(&CmiRegistryLock
);
1241 KeLeaveCriticalRegion();
1243 DPRINT("CmShutdownRegistry() done\n");
1248 CmiHiveSyncRoutine(PVOID DeferredContext
)
1250 PREGISTRY_HIVE Hive
;
1253 DPRINT("CmiHiveSyncRoutine() called\n");
1255 CmiHiveSyncPending
= FALSE
;
1257 /* Acquire hive list lock exclusively */
1258 KeEnterCriticalRegion();
1259 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1261 Entry
= CmiHiveListHead
.Flink
;
1262 while (Entry
!= &CmiHiveListHead
)
1264 Hive
= CONTAINING_RECORD(Entry
, REGISTRY_HIVE
, HiveList
);
1266 if (!(IsNoFileHive(Hive
) || IsNoSynchHive(Hive
)))
1268 /* Flush non-volatile hive */
1269 CmiFlushRegistryHive(Hive
);
1272 Entry
= Entry
->Flink
;
1275 /* Release hive list lock */
1276 ExReleaseResourceLite(&CmiRegistryLock
);
1277 KeLeaveCriticalRegion();
1279 DPRINT("DeferredContext %x\n", DeferredContext
);
1280 ExFreePool(DeferredContext
);
1282 DPRINT("CmiHiveSyncRoutine() done\n");
1287 CmiHiveSyncDpcRoutine(PKDPC Dpc
,
1288 PVOID DeferredContext
,
1289 PVOID SystemArgument1
,
1290 PVOID SystemArgument2
)
1292 PWORK_QUEUE_ITEM WorkQueueItem
;
1294 WorkQueueItem
= ExAllocatePool(NonPagedPool
,
1295 sizeof(WORK_QUEUE_ITEM
));
1296 if (WorkQueueItem
== NULL
)
1298 DbgPrint("Failed to allocate work item\n");
1302 ExInitializeWorkItem(WorkQueueItem
,
1306 DPRINT("DeferredContext %x\n", WorkQueueItem
);
1307 ExQueueWorkItem(WorkQueueItem
,
1315 LARGE_INTEGER Timeout
;
1317 DPRINT("CmiSyncHives() called\n");
1319 if (CmiHiveSyncEnabled
== FALSE
||
1320 CmiHiveSyncPending
== TRUE
)
1323 CmiHiveSyncPending
= TRUE
;
1325 Timeout
.QuadPart
= (LONGLONG
)-50000000;
1326 KeSetTimer(&CmiHiveSyncTimer
,