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
);
336 CmInitializeRegistry(VOID
)
338 OBJECT_ATTRIBUTES ObjectAttributes
;
339 UNICODE_STRING KeyName
;
342 PSECURITY_CELL RootSecurityCell
;
344 HANDLE RootKeyHandle
;
347 LARGE_INTEGER DueTime
;
350 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
353 DPRINT("Creating Registry Object Type\n");
355 /* Initialize the Key object type */
356 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
357 RtlInitUnicodeString(&Name
, L
"Key");
358 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
359 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(KEY_OBJECT
);
360 ObjectTypeInitializer
.GenericMapping
= CmiKeyMapping
;
361 ObjectTypeInitializer
.PoolType
= PagedPool
;
362 ObjectTypeInitializer
.ValidAccessMask
= KEY_ALL_ACCESS
;
363 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
364 ObjectTypeInitializer
.DeleteProcedure
= CmiObjectDelete
;
365 ObjectTypeInitializer
.ParseProcedure
= CmiObjectParse
;
366 ObjectTypeInitializer
.SecurityProcedure
= CmiObjectSecurity
;
367 ObjectTypeInitializer
.QueryNameProcedure
= CmiObjectQueryName
;
369 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &CmiKeyType
);
371 /* Initialize the hive list */
372 InitializeListHead(&CmiHiveListHead
);
374 /* Initialize registry lock */
375 ExInitializeResourceLite(&CmiRegistryLock
);
377 /* Initialize the key object list */
378 InitializeListHead(&CmiKeyObjectListHead
);
380 /* Initialize the worker timer */
381 KeInitializeTimerEx(&CmiWorkerTimer
, SynchronizationTimer
);
383 /* Initialize the worker thread */
384 Status
= PsCreateSystemThread(&ThreadHandle
,
391 if (!NT_SUCCESS(Status
))
396 /* Start the timer */
397 DueTime
.QuadPart
= -1;
398 KeSetTimerEx(&CmiWorkerTimer
, DueTime
, 5000, NULL
); /* 5sec */
400 /* Build volatile registry store */
401 Status
= CmiCreateVolatileHive (&CmiVolatileHive
);
402 ASSERT(NT_SUCCESS(Status
));
404 InitializeListHead(&CmiCallbackHead
);
405 ExInitializeFastMutex(&CmiCallbackLock
);
407 /* Create '\Registry' key. */
408 RtlInitUnicodeString(&KeyName
, REG_ROOT_KEY_NAME
);
409 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, 0, NULL
, NULL
);
410 Status
= ObCreateObject(KernelMode
,
419 ASSERT(NT_SUCCESS(Status
));
420 Status
= ObInsertObject(RootKey
,
426 ASSERT(NT_SUCCESS(Status
));
427 RootKey
->RegistryHive
= CmiVolatileHive
;
428 RootKey
->KeyCellOffset
= CmiVolatileHive
->HiveHeader
->RootKeyOffset
;
429 RootKey
->KeyCell
= CmiGetCell (CmiVolatileHive
, RootKey
->KeyCellOffset
, NULL
);
430 RootKey
->ParentKey
= RootKey
;
432 RootKey
->NumberOfSubKeys
= 0;
433 RootKey
->SubKeys
= NULL
;
434 RootKey
->SizeOfSubKeys
= 0;
435 InsertTailList(&CmiKeyObjectListHead
, &RootKey
->ListEntry
);
436 Status
= RtlpCreateUnicodeString(&RootKey
->Name
, L
"Registry", NonPagedPool
);
437 ASSERT(NT_SUCCESS(Status
));
440 Status
= CmiAllocateCell(CmiVolatileHive
,
441 0x10, //LONG CellSize,
442 (PVOID
*)&RootSecurityCell
,
443 &RootKey
->KeyCell
->SecurityKeyOffset
);
444 ASSERT(NT_SUCCESS(Status
));
446 /* Copy the security descriptor */
448 CmiVolatileHive
->RootSecurityCell
= RootSecurityCell
;
452 /* Create '\Registry\Machine' key. */
453 RtlInitUnicodeString(&KeyName
,
455 InitializeObjectAttributes(&ObjectAttributes
,
460 Status
= ZwCreateKey(&KeyHandle
,
467 ASSERT(NT_SUCCESS(Status
));
469 /* Create '\Registry\User' key. */
470 RtlInitUnicodeString(&KeyName
,
472 InitializeObjectAttributes(&ObjectAttributes
,
477 Status
= ZwCreateKey(&KeyHandle
,
484 ASSERT(NT_SUCCESS(Status
));
489 CmInit2(PCHAR CommandLine
)
492 BOOLEAN MiniNT
= FALSE
;
493 PWCHAR SystemBootDevice
;
494 PWCHAR SystemStartOptions
;
498 /* Create the 'CurrentControlSet' link. */
499 Status
= CmiCreateCurrentControlSetLink();
500 if (!NT_SUCCESS(Status
))
501 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
504 * Parse the system boot device.
507 SystemBootDevice
= ExAllocatePool(PagedPool
,
508 (strlen(CommandLine
) + 1) * sizeof(WCHAR
));
509 if (SystemBootDevice
== NULL
)
511 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
514 while (*CommandLine
!= 0 && *CommandLine
!= ' ')
515 SystemBootDevice
[Position
++] = *(CommandLine
++);
516 SystemBootDevice
[Position
++] = 0;
519 * Write the system boot device to registry.
521 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
522 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
526 Position
* sizeof(WCHAR
));
527 if (!NT_SUCCESS(Status
))
529 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
533 * Parse the system start options.
536 SystemStartOptions
= SystemBootDevice
;
537 while ((CommandLine
= strchr(CommandLine
, '/')) != NULL
)
539 /* Skip over the slash */
542 /* Special options */
543 if (!_strnicmp(CommandLine
, "MININT", 6))
545 else if (!_strnicmp(CommandLine
, "DEBUGPORT=PICE", 14))
548 /* Add a space between the options */
550 SystemStartOptions
[Position
++] = L
' ';
552 /* Copy the command */
553 while (*CommandLine
!= 0 && *CommandLine
!= ' ')
554 SystemStartOptions
[Position
++] = *(CommandLine
++);
556 SystemStartOptions
[Position
++] = 0;
559 * Write the system start options to registry.
561 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
562 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
563 L
"SystemStartOptions",
566 Position
* sizeof(WCHAR
));
567 if (!NT_SUCCESS(Status
))
569 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
573 * Create a CurrentControlSet\Control\MiniNT key that is used
574 * to detect WinPE/MiniNT systems.
578 Status
= RtlCreateRegistryKey(RTL_REGISTRY_CONTROL
, L
"MiniNT");
579 if (!NT_SUCCESS(Status
))
580 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
583 /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
584 Status
= RtlWriteRegistryValue(
585 RTL_REGISTRY_SERVICES
,
591 if (!NT_SUCCESS(Status
))
592 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
594 ExFreePool(SystemBootDevice
);
599 CmiCreateCurrentControlSetLink(VOID
)
601 RTL_QUERY_REGISTRY_TABLE QueryTable
[5];
602 WCHAR TargetNameBuffer
[80];
603 ULONG TargetNameLength
;
604 UNICODE_STRING LinkName
;
605 UNICODE_STRING LinkValue
;
611 OBJECT_ATTRIBUTES ObjectAttributes
;
614 DPRINT("CmiCreateCurrentControlSetLink() called\n");
616 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
618 QueryTable
[0].Name
= L
"Current";
619 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
620 QueryTable
[0].EntryContext
= &CurrentSet
;
622 QueryTable
[1].Name
= L
"Default";
623 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
624 QueryTable
[1].EntryContext
= &DefaultSet
;
626 QueryTable
[2].Name
= L
"Failed";
627 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
628 QueryTable
[2].EntryContext
= &Failed
;
630 QueryTable
[3].Name
= L
"LastKnownGood";
631 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
632 QueryTable
[3].EntryContext
= &LastKnownGood
;
634 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
635 L
"\\Registry\\Machine\\SYSTEM\\Select",
639 if (!NT_SUCCESS(Status
))
644 DPRINT("Current %ld Default %ld\n", CurrentSet
, DefaultSet
);
646 swprintf(TargetNameBuffer
,
647 L
"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
649 TargetNameLength
= wcslen(TargetNameBuffer
) * sizeof(WCHAR
);
651 DPRINT("Link target '%S'\n", TargetNameBuffer
);
653 RtlRosInitUnicodeStringFromLiteral(&LinkName
,
654 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
655 InitializeObjectAttributes(&ObjectAttributes
,
657 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_OPENLINK
,
660 Status
= ZwCreateKey(&KeyHandle
,
661 KEY_ALL_ACCESS
| KEY_CREATE_LINK
,
665 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
667 if (!NT_SUCCESS(Status
))
669 DPRINT1("ZwCreateKey() failed (Status %lx)\n", Status
);
673 RtlRosInitUnicodeStringFromLiteral(&LinkValue
,
674 L
"SymbolicLinkValue");
675 Status
= ZwSetValueKey(KeyHandle
,
679 (PVOID
)TargetNameBuffer
,
681 if (!NT_SUCCESS(Status
))
683 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
693 CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
694 IN PREGISTRY_HIVE RegistryHive
)
696 UNICODE_STRING RemainingPath
;
697 PKEY_OBJECT ParentKey
;
702 DPRINT("CmiConnectHive(%p, %p) called.\n",
703 KeyObjectAttributes
, RegistryHive
);
705 Status
= CmpFindObject(KeyObjectAttributes
,
709 if (!NT_SUCCESS(Status
))
714 DPRINT ("RemainingPath %wZ\n", &RemainingPath
);
716 if ((RemainingPath
.Buffer
== NULL
) || (RemainingPath
.Buffer
[0] == 0))
718 ObDereferenceObject (ParentKey
);
719 RtlFreeUnicodeString(&RemainingPath
);
720 return STATUS_OBJECT_NAME_COLLISION
;
723 /* Ignore leading backslash */
724 SubName
= RemainingPath
.Buffer
;
725 if (*SubName
== L
'\\')
728 /* If RemainingPath contains \ we must return error
729 because CmiConnectHive() can not create trees */
730 if (wcschr (SubName
, L
'\\') != NULL
)
732 ObDereferenceObject (ParentKey
);
733 RtlFreeUnicodeString(&RemainingPath
);
734 return STATUS_OBJECT_NAME_NOT_FOUND
;
737 DPRINT("RemainingPath %wZ ParentKey %p\n",
738 &RemainingPath
, ParentKey
);
740 Status
= ObCreateObject(KernelMode
,
750 if (!NT_SUCCESS(Status
))
752 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status
);
753 ObDereferenceObject (ParentKey
);
754 RtlFreeUnicodeString(&RemainingPath
);
757 DPRINT("Inserting Key into Object Tree\n");
758 Status
= ObInsertObject((PVOID
)NewKey
,
764 DPRINT("Status %x\n", Status
);
765 NewKey
->RegistryHive
= RegistryHive
;
766 NewKey
->KeyCellOffset
= RegistryHive
->HiveHeader
->RootKeyOffset
;
767 NewKey
->KeyCell
= CmiGetCell (RegistryHive
, NewKey
->KeyCellOffset
, NULL
);
769 NewKey
->NumberOfSubKeys
= 0;
770 InsertTailList(&CmiKeyObjectListHead
, &NewKey
->ListEntry
);
771 if (NewKey
->KeyCell
->NumberOfSubKeys
!= 0)
773 NewKey
->SubKeys
= ExAllocatePool(NonPagedPool
,
774 NewKey
->KeyCell
->NumberOfSubKeys
* sizeof(ULONG
));
775 if (NewKey
->SubKeys
== NULL
)
777 DPRINT("ExAllocatePool() failed\n");
778 ObDereferenceObject (NewKey
);
779 ObDereferenceObject (ParentKey
);
780 RtlFreeUnicodeString(&RemainingPath
);
781 return STATUS_INSUFFICIENT_RESOURCES
;
786 NewKey
->SubKeys
= NULL
;
789 DPRINT ("SubName %S\n", SubName
);
791 Status
= RtlpCreateUnicodeString(&NewKey
->Name
,
792 SubName
, NonPagedPool
);
793 RtlFreeUnicodeString(&RemainingPath
);
794 if (!NT_SUCCESS(Status
))
796 DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status
);
797 if (NewKey
->SubKeys
!= NULL
)
799 ExFreePool (NewKey
->SubKeys
);
801 ObDereferenceObject (NewKey
);
802 ObDereferenceObject (ParentKey
);
803 return STATUS_INSUFFICIENT_RESOURCES
;
806 CmiAddKeyToList (ParentKey
, NewKey
);
807 ObDereferenceObject (ParentKey
);
809 VERIFY_KEY_OBJECT(NewKey
);
811 /* Note: Do not dereference NewKey here! */
813 return STATUS_SUCCESS
;
818 CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
819 OUT PREGISTRY_HIVE
*RegistryHive
)
821 PKEY_OBJECT KeyObject
;
825 PLIST_ENTRY CurrentEntry
;
826 PKEY_OBJECT CurrentKey
;
828 DPRINT("CmiDisconnectHive() called\n");
830 *RegistryHive
= NULL
;
832 Status
= ObOpenObjectByName (KeyObjectAttributes
,
836 STANDARD_RIGHTS_REQUIRED
,
839 if (!NT_SUCCESS(Status
))
841 DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status
);
845 Status
= ObReferenceObjectByHandle (KeyHandle
,
846 STANDARD_RIGHTS_REQUIRED
,
852 if (!NT_SUCCESS(Status
))
854 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status
);
857 DPRINT ("KeyObject %p Hive %p\n", KeyObject
, KeyObject
->RegistryHive
);
859 if (!(KeyObject
->KeyCell
->Flags
& REG_KEY_ROOT_CELL
))
861 DPRINT1 ("Key is not the Hive-Root-Key\n");
862 ObDereferenceObject (KeyObject
);
863 return STATUS_INVALID_PARAMETER
;
866 /* Acquire registry lock exclusively */
867 KeEnterCriticalRegion();
868 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
870 CurrentEntry
= CmiKeyObjectListHead
.Flink
;
871 while (CurrentEntry
!= &CmiKeyObjectListHead
)
873 CurrentKey
= CONTAINING_RECORD(CurrentEntry
, KEY_OBJECT
, ListEntry
);
874 if (1 == ObGetObjectPointerCount(CurrentKey
) &&
875 !(CurrentKey
->Flags
& KO_MARKED_FOR_DELETE
))
877 ObDereferenceObject(CurrentKey
);
878 CurrentEntry
= CmiKeyObjectListHead
.Flink
;
882 CurrentEntry
= CurrentEntry
->Flink
;
886 if (ObGetObjectHandleCount (KeyObject
) != 0 ||
887 ObGetObjectPointerCount (KeyObject
) != 2)
889 DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject
), ObGetObjectPointerCount (KeyObject
));
890 ObDereferenceObject (KeyObject
);
892 /* Release registry lock */
893 ExReleaseResourceLite (&CmiRegistryLock
);
894 KeLeaveCriticalRegion();
896 return STATUS_UNSUCCESSFUL
;
899 Hive
= KeyObject
->RegistryHive
;
901 /* Dereference KeyObject twice to delete it */
902 ObDereferenceObject (KeyObject
);
903 ObDereferenceObject (KeyObject
);
905 *RegistryHive
= Hive
;
907 /* Release registry lock */
908 ExReleaseResourceLite (&CmiRegistryLock
);
909 KeLeaveCriticalRegion();
911 DPRINT ("CmiDisconnectHive() done\n");
913 return STATUS_SUCCESS
;
918 CmiInitControlSetLink (VOID
)
920 OBJECT_ATTRIBUTES ObjectAttributes
;
921 UNICODE_STRING ControlSetKeyName
;
922 UNICODE_STRING ControlSetLinkName
;
923 UNICODE_STRING ControlSetValueName
;
927 /* Create 'ControlSet001' key */
928 RtlRosInitUnicodeStringFromLiteral (&ControlSetKeyName
,
929 L
"\\Registry\\Machine\\SYSTEM\\ControlSet001");
930 InitializeObjectAttributes (&ObjectAttributes
,
932 OBJ_CASE_INSENSITIVE
,
935 Status
= ZwCreateKey (&KeyHandle
,
940 REG_OPTION_NON_VOLATILE
,
942 if (!NT_SUCCESS(Status
))
944 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status
);
949 /* Link 'CurrentControlSet' to 'ControlSet001' key */
950 RtlRosInitUnicodeStringFromLiteral (&ControlSetLinkName
,
951 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
952 InitializeObjectAttributes (&ObjectAttributes
,
954 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_OPENLINK
,
957 Status
= ZwCreateKey (&KeyHandle
,
958 KEY_ALL_ACCESS
| KEY_CREATE_LINK
,
962 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
964 if (!NT_SUCCESS(Status
))
966 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status
);
970 RtlRosInitUnicodeStringFromLiteral (&ControlSetValueName
,
971 L
"SymbolicLinkValue");
972 Status
= ZwSetValueKey (KeyHandle
,
973 &ControlSetValueName
,
976 (PVOID
)ControlSetKeyName
.Buffer
,
977 ControlSetKeyName
.Length
);
978 if (!NT_SUCCESS(Status
))
980 DPRINT1 ("ZwSetValueKey() failed (Status %lx)\n", Status
);
984 return STATUS_SUCCESS
;
989 CmiInitHives(BOOLEAN SetupBoot
)
991 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
992 OBJECT_ATTRIBUTES ObjectAttributes
;
993 UNICODE_STRING FileName
;
994 UNICODE_STRING KeyName
;
995 UNICODE_STRING ValueName
;
1000 WCHAR ConfigPath
[MAX_PATH
];
1007 DPRINT("CmiInitHives() called\n");
1009 if (SetupBoot
== TRUE
)
1011 RtlRosInitUnicodeStringFromLiteral(&KeyName
,
1012 L
"\\Registry\\Machine\\HARDWARE");
1013 InitializeObjectAttributes(&ObjectAttributes
,
1015 OBJ_CASE_INSENSITIVE
,
1018 Status
= ZwOpenKey(&KeyHandle
,
1021 if (!NT_SUCCESS(Status
))
1023 DPRINT1("ZwOpenKey() failed (Status %lx)\n", Status
);
1027 RtlRosInitUnicodeStringFromLiteral(&ValueName
,
1030 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
1031 ValueInfo
= ExAllocatePool(PagedPool
,
1033 if (ValueInfo
== NULL
)
1036 return(STATUS_INSUFFICIENT_RESOURCES
);
1039 Status
= ZwQueryValueKey(KeyHandle
,
1041 KeyValuePartialInformation
,
1046 if (!NT_SUCCESS(Status
))
1048 ExFreePool(ValueInfo
);
1052 RtlCopyMemory(ConfigPath
,
1054 ValueInfo
->DataLength
);
1055 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = (WCHAR
)0;
1056 ExFreePool(ValueInfo
);
1060 wcscpy(ConfigPath
, L
"\\SystemRoot");
1062 wcscat(ConfigPath
, L
"\\system32\\config");
1064 DPRINT("ConfigPath: %S\n", ConfigPath
);
1066 EndPtr
= ConfigPath
+ wcslen(ConfigPath
);
1070 /* FIXME: Save boot log */
1072 /* Connect the SYSTEM hive only if it has been created */
1073 if (SetupBoot
== TRUE
)
1075 wcscpy(EndPtr
, REG_SYSTEM_FILE_NAME
);
1076 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1078 RtlInitUnicodeString (&KeyName
,
1079 REG_SYSTEM_KEY_NAME
);
1080 InitializeObjectAttributes(&ObjectAttributes
,
1082 OBJ_CASE_INSENSITIVE
,
1086 RtlInitUnicodeString (&FileName
,
1088 Status
= CmiLoadHive (&ObjectAttributes
,
1091 if (!NT_SUCCESS(Status
))
1093 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
1097 Status
= CmiInitControlSetLink ();
1098 if (!NT_SUCCESS(Status
))
1100 DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status
);
1105 /* Connect the SOFTWARE hive */
1106 wcscpy(EndPtr
, REG_SOFTWARE_FILE_NAME
);
1107 RtlInitUnicodeString (&FileName
,
1109 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1111 RtlInitUnicodeString (&KeyName
,
1112 REG_SOFTWARE_KEY_NAME
);
1113 InitializeObjectAttributes(&ObjectAttributes
,
1115 OBJ_CASE_INSENSITIVE
,
1119 Status
= CmiLoadHive (&ObjectAttributes
,
1122 if (!NT_SUCCESS(Status
))
1124 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1128 /* Connect the SAM hive */
1129 wcscpy(EndPtr
, REG_SAM_FILE_NAME
);
1130 RtlInitUnicodeString (&FileName
,
1132 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1134 RtlInitUnicodeString (&KeyName
,
1136 InitializeObjectAttributes(&ObjectAttributes
,
1138 OBJ_CASE_INSENSITIVE
,
1141 Status
= CmiLoadHive (&ObjectAttributes
,
1144 if (!NT_SUCCESS(Status
))
1146 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1150 /* Connect the SECURITY hive */
1151 wcscpy(EndPtr
, REG_SEC_FILE_NAME
);
1152 RtlInitUnicodeString (&FileName
,
1154 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1156 RtlInitUnicodeString (&KeyName
,
1158 InitializeObjectAttributes(&ObjectAttributes
,
1160 OBJ_CASE_INSENSITIVE
,
1163 Status
= CmiLoadHive (&ObjectAttributes
,
1166 if (!NT_SUCCESS(Status
))
1168 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1172 /* Connect the DEFAULT hive */
1173 wcscpy(EndPtr
, REG_DEFAULT_USER_FILE_NAME
);
1174 RtlInitUnicodeString (&FileName
,
1176 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1178 RtlInitUnicodeString (&KeyName
,
1179 REG_DEFAULT_USER_KEY_NAME
);
1180 InitializeObjectAttributes(&ObjectAttributes
,
1182 OBJ_CASE_INSENSITIVE
,
1185 Status
= CmiLoadHive (&ObjectAttributes
,
1188 if (!NT_SUCCESS(Status
))
1190 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1194 // CmiCheckRegistry(TRUE);
1196 /* Start automatic hive synchronization */
1197 KeInitializeDpc(&CmiHiveSyncDpc
,
1198 CmiHiveSyncDpcRoutine
,
1200 KeInitializeTimer(&CmiHiveSyncTimer
);
1201 CmiHiveSyncEnabled
= TRUE
;
1203 DPRINT("CmiInitHives() done\n");
1205 return(STATUS_SUCCESS
);
1210 CmShutdownRegistry(VOID
)
1212 PREGISTRY_HIVE Hive
;
1215 DPRINT("CmShutdownRegistry() called\n");
1217 /* Stop automatic hive synchronization */
1218 CmiHiveSyncEnabled
= FALSE
;
1220 /* Cancel pending hive synchronization */
1221 if (CmiHiveSyncPending
== TRUE
)
1223 KeCancelTimer(&CmiHiveSyncTimer
);
1224 CmiHiveSyncPending
= FALSE
;
1227 /* Acquire hive list lock exclusively */
1228 KeEnterCriticalRegion();
1229 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1231 Entry
= CmiHiveListHead
.Flink
;
1232 while (Entry
!= &CmiHiveListHead
)
1234 Hive
= CONTAINING_RECORD(Entry
, REGISTRY_HIVE
, HiveList
);
1236 if (!(IsNoFileHive(Hive
) || IsNoSynchHive(Hive
)))
1238 /* Flush non-volatile hive */
1239 CmiFlushRegistryHive(Hive
);
1242 Entry
= Entry
->Flink
;
1245 /* Release hive list lock */
1246 ExReleaseResourceLite(&CmiRegistryLock
);
1247 KeLeaveCriticalRegion();
1249 DPRINT("CmShutdownRegistry() done\n");
1254 CmiHiveSyncRoutine(PVOID DeferredContext
)
1256 PREGISTRY_HIVE Hive
;
1259 DPRINT("CmiHiveSyncRoutine() called\n");
1261 CmiHiveSyncPending
= FALSE
;
1263 /* Acquire hive list lock exclusively */
1264 KeEnterCriticalRegion();
1265 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1267 Entry
= CmiHiveListHead
.Flink
;
1268 while (Entry
!= &CmiHiveListHead
)
1270 Hive
= CONTAINING_RECORD(Entry
, REGISTRY_HIVE
, HiveList
);
1272 if (!(IsNoFileHive(Hive
) || IsNoSynchHive(Hive
)))
1274 /* Flush non-volatile hive */
1275 CmiFlushRegistryHive(Hive
);
1278 Entry
= Entry
->Flink
;
1281 /* Release hive list lock */
1282 ExReleaseResourceLite(&CmiRegistryLock
);
1283 KeLeaveCriticalRegion();
1285 DPRINT("DeferredContext %x\n", DeferredContext
);
1286 ExFreePool(DeferredContext
);
1288 DPRINT("CmiHiveSyncRoutine() done\n");
1293 CmiHiveSyncDpcRoutine(PKDPC Dpc
,
1294 PVOID DeferredContext
,
1295 PVOID SystemArgument1
,
1296 PVOID SystemArgument2
)
1298 PWORK_QUEUE_ITEM WorkQueueItem
;
1300 WorkQueueItem
= ExAllocatePool(NonPagedPool
,
1301 sizeof(WORK_QUEUE_ITEM
));
1302 if (WorkQueueItem
== NULL
)
1304 DbgPrint("Failed to allocate work item\n");
1308 ExInitializeWorkItem(WorkQueueItem
,
1312 DPRINT("DeferredContext %x\n", WorkQueueItem
);
1313 ExQueueWorkItem(WorkQueueItem
,
1321 LARGE_INTEGER Timeout
;
1323 DPRINT("CmiSyncHives() called\n");
1325 if (CmiHiveSyncEnabled
== FALSE
||
1326 CmiHiveSyncPending
== TRUE
)
1329 CmiHiveSyncPending
= TRUE
;
1331 Timeout
.QuadPart
= (LONGLONG
)-50000000;
1332 KeSetTimer(&CmiHiveSyncTimer
,