-/*\r
- * PROJECT: ReactOS Kernel\r
- * LICENSE: GPL - See COPYING in the top level directory\r
- * FILE: ntoskrnl/config/cmsysini.c\r
- * PURPOSE: Configuration Manager - System Initialization Code\r
- * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)\r
- */\r
-\r
-/* INCLUDES ******************************************************************/\r
-\r
-#include "ntoskrnl.h"\r
-#include "cm.h"\r
-#define NDEBUG\r
-#include "debug.h"\r
-\r
-KGUARDED_MUTEX CmpSelfHealQueueLock;\r
-LIST_ENTRY CmpSelfHealQueueListHead;\r
-PEPROCESS CmpSystemProcess;\r
-\r
-/* FUNCTIONS *****************************************************************/\r
-\r
-NTSTATUS\r
-NTAPI\r
-CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock)\r
-{\r
- OBJECT_ATTRIBUTES ObjectAttributes;\r
- UNICODE_STRING KeyName, ValueName;\r
- HANDLE KeyHandle;\r
- NTSTATUS Status;\r
- ASSERT(LoaderBlock != NULL);\r
- if (ExpInTextModeSetup) return STATUS_SUCCESS;\r
-\r
- /* Setup attributes for loader options */\r
- RtlInitUnicodeString(&KeyName,\r
- L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"\r
- L"Control");\r
- InitializeObjectAttributes(&ObjectAttributes,\r
- &KeyName,\r
- OBJ_CASE_INSENSITIVE,\r
- NULL,\r
- NULL);\r
- Status = NtOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);\r
- if (!NT_SUCCESS(Status)) goto Quickie;\r
-\r
- /* Key opened, now write to the key */\r
- RtlInitUnicodeString(&KeyName, L"SystemStartOptions");\r
- Status = NtSetValueKey(KeyHandle,\r
- &KeyName,\r
- 0,\r
- REG_SZ,\r
- CmpSystemStartOptions.Buffer,\r
- CmpSystemStartOptions.Length);\r
- if (!NT_SUCCESS(Status)) goto Quickie;\r
-\r
- /* Free the options now */\r
- ExFreePool(CmpSystemStartOptions.Buffer);\r
-\r
- /* Setup value name for system boot device */\r
- RtlInitUnicodeString(&KeyName, L"SystemBootDevice");\r
- RtlCreateUnicodeStringFromAsciiz(&ValueName, LoaderBlock->NtBootPathName);\r
- Status = NtSetValueKey(KeyHandle,\r
- &KeyName,\r
- 0,\r
- REG_SZ,\r
- ValueName.Buffer,\r
- ValueName.Length);\r
-\r
-Quickie:\r
- /* Free the buffers */\r
- RtlFreeUnicodeString(&ValueName);\r
-\r
- /* Close the key and return */\r
- NtClose(KeyHandle);\r
-\r
- /* Return the status */\r
- return Status;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock)\r
-{\r
- UNICODE_STRING ConfigName = RTL_CONSTANT_STRING(L"Control\\IDConfigDB");\r
- UNICODE_STRING SelectName =\r
- RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\Select");\r
- UNICODE_STRING KeyName;\r
- OBJECT_ATTRIBUTES ObjectAttributes;\r
- CHAR ValueInfoBuffer[128];\r
- PKEY_VALUE_FULL_INFORMATION ValueInfo;\r
- CHAR Buffer[128];\r
- WCHAR UnicodeBuffer[128];\r
- HANDLE SelectHandle, KeyHandle, ConfigHandle = NULL, ProfileHandle = NULL;\r
- HANDLE ParentHandle = NULL;\r
- ULONG ControlSet, HwProfile;\r
- ANSI_STRING TempString;\r
- NTSTATUS Status;\r
- ULONG ResultLength, Disposition;\r
- PLOADER_PARAMETER_EXTENSION LoaderExtension;\r
- PAGED_CODE();\r
- if (ExpInTextModeSetup) return STATUS_SUCCESS;\r
-\r
- /* Open the select key */\r
- InitializeObjectAttributes(&ObjectAttributes,\r
- &SelectName,\r
- OBJ_CASE_INSENSITIVE,\r
- NULL,\r
- NULL);\r
- Status = NtOpenKey(&SelectHandle, KEY_READ, &ObjectAttributes);\r
- if (!NT_SUCCESS(Status)) return(Status);\r
-\r
- /* Open the current value */\r
- RtlInitUnicodeString(&KeyName, L"Current");\r
- Status = NtQueryValueKey(SelectHandle,\r
- &KeyName,\r
- KeyValueFullInformation,\r
- ValueInfoBuffer,\r
- sizeof(ValueInfoBuffer),\r
- &ResultLength);\r
- NtClose(SelectHandle);\r
- if (!NT_SUCCESS(Status)) return Status;\r
-\r
- /* Get the actual value pointer, and get the control set ID */\r
- ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;\r
- ControlSet = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);\r
-\r
- /* Create the current control set key */\r
- RtlInitUnicodeString(&KeyName,\r
- L"\\Registry\\Machine\\System\\CurrentControlSet");\r
- InitializeObjectAttributes(&ObjectAttributes,\r
- &KeyName,\r
- OBJ_CASE_INSENSITIVE,\r
- NULL,\r
- NULL);\r
- Status = NtCreateKey(&KeyHandle,\r
- KEY_CREATE_LINK,\r
- &ObjectAttributes,\r
- 0,\r
- NULL,\r
- REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,\r
- &Disposition);\r
- if (!NT_SUCCESS(Status)) return Status;\r
-\r
- /* Sanity check */\r
- ASSERT(Disposition == REG_CREATED_NEW_KEY);\r
-\r
- /* Initialize the symbolic link name */\r
- sprintf(Buffer,\r
- "\\Registry\\Machine\\System\\ControlSet%03ld",\r
- ControlSet);\r
- RtlInitAnsiString(&TempString, Buffer);\r
-\r
- /* Create a Unicode string out of it */\r
- KeyName.MaximumLength = sizeof(UnicodeBuffer);\r
- KeyName.Buffer = UnicodeBuffer;\r
- Status = RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE);\r
-\r
- /* Set the value */\r
- Status = NtSetValueKey(KeyHandle,\r
- &CmSymbolicLinkValueName,\r
- 0,\r
- REG_LINK,\r
- KeyName.Buffer,\r
- KeyName.Length);\r
- if (!NT_SUCCESS(Status)) return Status;\r
-\r
- /* Get the configuration database key */\r
- InitializeObjectAttributes(&ObjectAttributes,\r
- &ConfigName,\r
- OBJ_CASE_INSENSITIVE,\r
- KeyHandle,\r
- NULL);\r
- Status = NtOpenKey(&ConfigHandle, KEY_READ, &ObjectAttributes);\r
- NtClose(KeyHandle);\r
-\r
- /* Check if we don't have one */\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Cleanup and exit */\r
- ConfigHandle = 0;\r
- goto Cleanup;\r
- }\r
-\r
- /* Now get the current config */\r
- RtlInitUnicodeString(&KeyName, L"CurrentConfig");\r
- Status = NtQueryValueKey(ConfigHandle,\r
- &KeyName,\r
- KeyValueFullInformation,\r
- ValueInfoBuffer,\r
- sizeof(ValueInfoBuffer),\r
- &ResultLength);\r
-\r
- /* Set pointer to buffer */\r
- ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;\r
-\r
- /* Check if we failed or got a non DWORD-value */\r
- if (!(NT_SUCCESS(Status)) || (ValueInfo->Type != REG_DWORD)) goto Cleanup;\r
-\r
- /* Get the hadware profile */\r
- HwProfile = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);\r
-\r
- /* Open the hardware profile key */\r
- RtlInitUnicodeString(&KeyName,\r
- L"\\Registry\\Machine\\System\\CurrentControlSet"\r
- L"\\Hardware Profiles");\r
- InitializeObjectAttributes(&ObjectAttributes,\r
- &KeyName,\r
- OBJ_CASE_INSENSITIVE,\r
- NULL,\r
- NULL);\r
- Status = NtOpenKey(&ParentHandle, KEY_READ, &ObjectAttributes);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Exit and clean up */\r
- ParentHandle = 0;\r
- goto Cleanup;\r
- }\r
-\r
- /* Build the profile name */\r
- sprintf(Buffer, "%04ld", HwProfile);\r
- RtlInitAnsiString(&TempString, Buffer);\r
-\r
- /* Convert it to Unicode */\r
- KeyName.MaximumLength = sizeof(UnicodeBuffer);\r
- KeyName.Buffer = UnicodeBuffer;\r
- Status = RtlAnsiStringToUnicodeString(&KeyName,\r
- &TempString,\r
- FALSE);\r
- ASSERT(Status == STATUS_SUCCESS);\r
-\r
- /* Open the associated key */\r
- InitializeObjectAttributes(&ObjectAttributes,\r
- &KeyName,\r
- OBJ_CASE_INSENSITIVE,\r
- ParentHandle,\r
- NULL);\r
- Status = NtOpenKey(&ProfileHandle,\r
- KEY_READ | KEY_WRITE,\r
- &ObjectAttributes);\r
- if (!NT_SUCCESS (Status))\r
- {\r
- /* Cleanup and exit */\r
- ProfileHandle = 0;\r
- goto Cleanup;\r
- }\r
-\r
- /* Check if we have a loader block extension */\r
- LoaderExtension = LoaderBlock->Extension;\r
- if (LoaderExtension)\r
- {\r
- ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE);\r
- }\r
-\r
- /* Create the current hardware profile key */\r
- RtlInitUnicodeString(&KeyName,\r
- L"\\Registry\\Machine\\System\\CurrentControlSet\\"\r
- L"Hardware Profiles\\Current");\r
- InitializeObjectAttributes(&ObjectAttributes,\r
- &KeyName,\r
- OBJ_CASE_INSENSITIVE,\r
- NULL,\r
- NULL);\r
- Status = NtCreateKey(&KeyHandle,\r
- KEY_CREATE_LINK,\r
- &ObjectAttributes,\r
- 0,\r
- NULL,\r
- REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,\r
- &Disposition);\r
- if (NT_SUCCESS(Status))\r
- {\r
- /* Sanity check */\r
- ASSERT(Disposition == REG_CREATED_NEW_KEY);\r
-\r
- /* Create the profile name */\r
- sprintf(Buffer,\r
- "\\Registry\\Machine\\System\\CurrentControlSet\\"\r
- "Hardware Profiles\\%04ld",\r
- HwProfile);\r
- RtlInitAnsiString(&TempString, Buffer);\r
-\r
- /* Convert it to Unicode */\r
- KeyName.MaximumLength = sizeof(UnicodeBuffer);\r
- KeyName.Buffer = UnicodeBuffer;\r
- Status = RtlAnsiStringToUnicodeString(&KeyName,\r
- &TempString,\r
- FALSE);\r
- ASSERT(STATUS_SUCCESS == Status);\r
-\r
- /* Set it */\r
- Status = NtSetValueKey(KeyHandle,\r
- &CmSymbolicLinkValueName,\r
- 0,\r
- REG_LINK,\r
- KeyName.Buffer,\r
- KeyName.Length);\r
- NtClose(KeyHandle);\r
- }\r
-\r
- /* Close every opened handle */\r
-Cleanup:\r
- if (ConfigHandle) NtClose(ConfigHandle);\r
- if (ProfileHandle) NtClose(ProfileHandle);\r
- if (ParentHandle) NtClose(ParentHandle);\r
-\r
- /* Return success */\r
- return STATUS_SUCCESS;\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock)\r
-{\r
- PVOID HiveBase;\r
- ANSI_STRING LoadString;\r
- PVOID Buffer;\r
- ULONG Length;\r
- NTSTATUS Status;\r
- BOOLEAN Allocate;\r
- UNICODE_STRING KeyName;\r
- PEREGISTRY_HIVE SystemHive = NULL;\r
- UNICODE_STRING HiveName = RTL_CONSTANT_STRING(L"SYSTEM");\r
- PSECURITY_DESCRIPTOR SecurityDescriptor;\r
- PAGED_CODE();\r
-\r
- /* Setup the ansi string */\r
- RtlInitAnsiString(&LoadString, LoaderBlock->LoadOptions);\r
-\r
- /* Allocate the unicode buffer */\r
- Length = LoadString.Length * sizeof(WCHAR) + sizeof(UNICODE_NULL);\r
- Buffer = ExAllocatePoolWithTag(PagedPool, Length, 0);\r
- if (!Buffer)\r
- {\r
- /* Fail */\r
- KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO, 3, 1, (ULONG_PTR)LoaderBlock, 0);\r
- }\r
-\r
- /* Setup the unicode string */\r
- RtlInitEmptyUnicodeString(&CmpLoadOptions, Buffer, Length);\r
-\r
- /* Add the load options and null-terminate */\r
- RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE);\r
- CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL;\r
- CmpLoadOptions.Length += sizeof(WCHAR);\r
-\r
- /* Get the System Hive base address */\r
- HiveBase = LoaderBlock->RegistryBase;\r
- if (HiveBase)\r
- {\r
- /* Import it */\r
- ((PHBASE_BLOCK)HiveBase)->Length = LoaderBlock->RegistryLength;\r
- Status = CmpInitializeHive((PCMHIVE*)&SystemHive,\r
- HINIT_MEMORY,\r
- 0, //HIVE_NOLAZYFLUSH,\r
- HFILE_TYPE_LOG,\r
- HiveBase,\r
- NULL,\r
- NULL,\r
- NULL,\r
- &HiveName,\r
- 2);\r
- if (!NT_SUCCESS(Status)) return FALSE;\r
- CmPrepareHive(&SystemHive->Hive);\r
-\r
- /* Set the hive filename */\r
- RtlCreateUnicodeString(&SystemHive->HiveFileName, SYSTEM_REG_FILE);\r
-\r
- /* We imported, no need to create a new hive */\r
- Allocate = FALSE;\r
-\r
- /* Manually set the hive as volatile, if in Live CD mode */\r
- if (CmpShareSystemHives) SystemHive->Hive.HiveFlags = HIVE_VOLATILE;\r
- }\r
- else\r
- {\r
-#if 0\r
- /* Create it */\r
- Status = CmpInitializeHive((PCMHIVE*)&SystemHive,\r
- HINIT_CREATE,\r
- HIVE_NOLAZYFLUSH,\r
- HFILE_TYPE_LOG,\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL,\r
- &HiveName,\r
- 0);\r
- if (!NT_SUCCESS(Status)) return FALSE;\r
-#endif\r
-\r
- /* Tell CmpLinkHiveToMaster to allocate a hive */\r
- Allocate = TRUE;\r
- }\r
-\r
- /* Save the boot type */\r
- if (SystemHive) CmpBootType = SystemHive->Hive.HiveHeader->BootType;\r
-\r
- /* Are we in self-healing mode? */\r
- if (!CmSelfHeal)\r
- {\r
- /* Disable self-healing internally and check if boot type wanted it */\r
- CmpSelfHeal = FALSE;\r
- if (CmpBootType & 4)\r
- {\r
- /* We're disabled, so bugcheck */\r
- KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO,\r
- 3,\r
- 3,\r
- (ULONG_PTR)SystemHive,\r
- 0);\r
- }\r
- }\r
-\r
- /* Create the default security descriptor */\r
- SecurityDescriptor = CmpHiveRootSecurityDescriptor();\r
-\r
- /* Attach it to the system key */\r
- RtlInitUnicodeString(&KeyName, REG_SYSTEM_KEY_NAME);\r
- Status = CmpLinkHiveToMaster(&KeyName,\r
- NULL,\r
- (PCMHIVE)SystemHive,\r
- Allocate,\r
- SecurityDescriptor);\r
-\r
- /* Free the security descriptor */\r
- ExFreePool(SecurityDescriptor);\r
- if (!NT_SUCCESS(Status)) return FALSE;\r
-\r
- /* Add the hive to the hive list */\r
- CmpMachineHiveList[3].CmHive = (PCMHIVE)SystemHive;\r
-\r
- /* Success! */\r
- return TRUE;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-CmpCreateObjectTypes(VOID)\r
-{\r
- OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;\r
- UNICODE_STRING Name;\r
- GENERIC_MAPPING CmpKeyMapping = {KEY_READ,\r
- KEY_WRITE,\r
- KEY_EXECUTE,\r
- KEY_ALL_ACCESS};\r
- PAGED_CODE();\r
-\r
- /* Initialize the Key object type */\r
- RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));\r
- RtlInitUnicodeString(&Name, L"Key");\r
- ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);\r
- ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY);\r
- ObjectTypeInitializer.GenericMapping = CmpKeyMapping;\r
- ObjectTypeInitializer.PoolType = PagedPool;\r
- ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;\r
- ObjectTypeInitializer.UseDefaultObject = TRUE;\r
- ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject;\r
- ObjectTypeInitializer.ParseProcedure = CmpParseKey;\r
- ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod;\r
- ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName;\r
- //ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;\r
- ObjectTypeInitializer.SecurityRequired = TRUE;\r
-\r
- /* Create it */\r
- return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType);\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-CmpCreateRootNode(IN PHHIVE Hive,\r
- IN PCWSTR Name,\r
- OUT PHCELL_INDEX Index)\r
-{\r
- UNICODE_STRING KeyName;\r
- PCM_KEY_NODE KeyCell;\r
- LARGE_INTEGER SystemTime;\r
- PAGED_CODE();\r
-\r
- /* Initialize the node name and allocate it */\r
- RtlInitUnicodeString(&KeyName, Name);\r
- *Index = HvAllocateCell(Hive,\r
- FIELD_OFFSET(CM_KEY_NODE, Name) +\r
- CmpNameSize(Hive, &KeyName),\r
- HvStable); // FIXME: , HCELL_NIL);\r
- if (*Index == HCELL_NIL) return FALSE;\r
-\r
- /* Set the cell index and get the data */\r
- Hive->HiveHeader->RootCell = *Index;\r
- KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index);\r
- if (!KeyCell) return FALSE;\r
-\r
- /* Setup the cell */\r
- KeyCell->Signature = (USHORT)CM_KEY_NODE_SIGNATURE;;\r
- KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE;\r
- KeQuerySystemTime(&SystemTime);\r
- KeyCell->LastWriteTime = SystemTime;\r
- KeyCell->Parent = HCELL_NIL;\r
- KeyCell->SubKeyCounts[HvStable] = 0;\r
- KeyCell->SubKeyCounts[HvVolatile] = 0;\r
- KeyCell->SubKeyLists[HvStable] = HCELL_NIL;\r
- KeyCell->SubKeyLists[HvVolatile] = HCELL_NIL;\r
- KeyCell->ValueList.Count = 0;\r
- KeyCell->ValueList.List = HCELL_NIL;\r
- KeyCell->Security = HCELL_NIL;\r
- KeyCell->Class = HCELL_NIL;\r
- KeyCell->ClassLength = 0;\r
- KeyCell->MaxNameLen = 0;\r
- KeyCell->MaxClassLen = 0;\r
- KeyCell->MaxValueNameLen = 0;\r
- KeyCell->MaxValueDataLen = 0;\r
-\r
- /* Copy the name (this will also set the length) */\r
- KeyCell->NameLength = CmpCopyName(Hive, (PWCHAR)KeyCell->Name, &KeyName);\r
-\r
- /* Check if the name was compressed */\r
- if (KeyCell->NameLength < KeyName.Length)\r
- {\r
- /* Set the flag */\r
- KeyCell->Flags |= KEY_COMP_NAME;\r
- }\r
-\r
- /* Return success */\r
- HvReleaseCell(Hive, *Index);\r
- return TRUE;\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-CmpCreateRegistryRoot(VOID)\r
-{\r
- UNICODE_STRING KeyName;\r
- OBJECT_ATTRIBUTES ObjectAttributes;\r
-#if 0\r
- PCM_KEY_BODY RootKey;\r
-#else\r
- PKEY_OBJECT RootKey;\r
-#endif\r
- HCELL_INDEX RootIndex;\r
- NTSTATUS Status;\r
- PCM_KEY_NODE KeyCell;\r
- PSECURITY_DESCRIPTOR SecurityDescriptor;\r
- PCM_KEY_CONTROL_BLOCK Kcb;\r
- PAGED_CODE();\r
-\r
- /* Setup the root node */\r
- if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex))\r
- {\r
- /* We failed */\r
- return FALSE;\r
- }\r
-\r
- /* Create '\Registry' key. */\r
- RtlInitUnicodeString(&KeyName, L"\\Registry");\r
- SecurityDescriptor = CmpHiveRootSecurityDescriptor();\r
- InitializeObjectAttributes(&ObjectAttributes,\r
- &KeyName,\r
- OBJ_CASE_INSENSITIVE,\r
- NULL,\r
- NULL);\r
- Status = ObCreateObject(KernelMode,\r
- CmpKeyObjectType,\r
- &ObjectAttributes,\r
- KernelMode,\r
- NULL,\r
- sizeof(KEY_OBJECT),\r
- 0,\r
- 0,\r
- (PVOID*)&RootKey);\r
- ExFreePool(SecurityDescriptor);\r
- if (!NT_SUCCESS(Status)) return FALSE;\r
-\r
- /* Sanity check, and get the key cell */\r
- ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL);\r
- KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex);\r
- if (!KeyCell) return FALSE;\r
-\r
- /* Create the KCB */\r
- RtlInitUnicodeString(&KeyName, L"Registry");\r
- Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive,\r
- RootIndex,\r
- KeyCell,\r
- NULL,\r
- 0,\r
- &KeyName);\r
- if (!Kcb) return FALSE;\r
-\r
- /* Initialize the object */\r
-#if 0\r
- RootKey->Type = TAG('k', 'v', '0', '2';\r
- RootKey->KeyControlBlock = Kcb;\r
- RootKey->NotifyBlock = NULL;\r
- RootKey->ProcessID = PsGetCurrentProcessId();\r
-#else\r
- RtlpCreateUnicodeString(&RootKey->Name, L"Registry", NonPagedPool);\r
- RootKey->RegistryHive = CmiVolatileHive;\r
- RootKey->KeyCellOffset = RootIndex;\r
- RootKey->KeyCell = KeyCell;\r
- RootKey->ParentKey = RootKey;\r
- RootKey->Flags = 0;\r
- RootKey->SubKeyCounts = 0;\r
- RootKey->SubKeys = NULL;\r
- RootKey->SizeOfSubKeys = 0;\r
-#endif\r
-\r
- /* Insert it into the object list head */\r
- EnlistKeyBodyWithKCB(RootKey, 0);\r
-\r
- /* Insert the key into the namespace */\r
- Status = ObInsertObject(RootKey,\r
- NULL,\r
- KEY_ALL_ACCESS,\r
- 0,\r
- NULL,\r
- &CmpRegistryRootHandle);\r
- if (!NT_SUCCESS(Status)) return FALSE;\r
-\r
- /* Reference the key again so that we never lose it */\r
- Status = ObReferenceObjectByHandle(CmpRegistryRootHandle,\r
- KEY_READ,\r
- NULL,\r
- KernelMode,\r
- (PVOID*)&RootKey,\r
- NULL);\r
- if (!NT_SUCCESS(Status)) return FALSE;\r
-\r
- /* Completely sucessful */\r
- return TRUE;\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-CmInitSystem1(VOID)\r
-{\r
- OBJECT_ATTRIBUTES ObjectAttributes;\r
- UNICODE_STRING KeyName;\r
- HANDLE KeyHandle;\r
- NTSTATUS Status;\r
- LARGE_INTEGER DueTime;\r
- HANDLE ThreadHandle;\r
- CLIENT_ID ThreadId;\r
- PEREGISTRY_HIVE HardwareHive;\r
- PVOID BaseAddress;\r
- ULONG Length;\r
- PSECURITY_DESCRIPTOR SecurityDescriptor;\r
- PAGED_CODE();\r
-\r
- /* Check if this is PE-boot */\r
- if (InitIsWinPEMode)\r
- {\r
- /* Set registry to PE mode */\r
- CmpMiniNTBoot = TRUE;\r
- CmpShareSystemHives = TRUE;\r
- }\r
-\r
- /* Initialize the hive list and lock */\r
- InitializeListHead(&CmpHiveListHead);\r
- ExInitializePushLock((PVOID)&CmpHiveListHeadLock);\r
- ExInitializePushLock((PVOID)&CmpLoadHiveLock);\r
-\r
- /* Initialize registry lock */\r
- ExInitializeResourceLite(&CmpRegistryLock);\r
-\r
- /* Initialize the cache */\r
- CmpInitializeCache();\r
-\r
- /* Initialize allocation and delayed dereferencing */\r
- CmpInitCmPrivateAlloc();\r
- CmpInitCmPrivateDelayAlloc();\r
- CmpInitDelayDerefKCBEngine();\r
-\r
- /* Initialize callbacks */\r
- CmpInitCallback();\r
-\r
- /* Initialize self healing */\r
- KeInitializeGuardedMutex(&CmpSelfHealQueueLock);\r
- InitializeListHead(&CmpSelfHealQueueListHead);\r
-\r
- /* Save the current process and lock the registry */\r
- CmpSystemProcess = PsGetCurrentProcess();\r
-\r
-#if 1\r
- /* OLD CM: Initialize the key object list */\r
- InitializeListHead(&CmiKeyObjectListHead);\r
- InitializeListHead(&CmiConnectedHiveList);\r
-\r
- /* OLD CM: Initialize the worker timer */\r
- KeInitializeTimerEx(&CmiWorkerTimer, SynchronizationTimer);\r
-\r
- /* OLD CM: Initialize the worker thread */\r
- Status = PsCreateSystemThread(&ThreadHandle,\r
- THREAD_ALL_ACCESS,\r
- NULL,\r
- NULL,\r
- &ThreadId,\r
- CmiWorkerThread,\r
- NULL);\r
- if (!NT_SUCCESS(Status)) return FALSE;\r
-\r
- /* OLD CM: Start the timer */\r
- DueTime.QuadPart = -1;\r
- KeSetTimerEx(&CmiWorkerTimer, DueTime, 5000, NULL); /* 5sec */\r
-#endif\r
-\r
- /* Create the key object types */\r
- Status = CmpCreateObjectTypes();\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Bugcheck */\r
- KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0);\r
- }\r
-\r
- /* Build the master hive */\r
- Status = CmpInitializeHive((PCMHIVE*)&CmiVolatileHive,\r
- HINIT_CREATE,\r
- HIVE_VOLATILE | HIVE_NO_FILE,\r
- HFILE_TYPE_PRIMARY,\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL,\r
- 0);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Bugcheck */\r
- KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0);\r
- }\r
-\r
- /* Create the \REGISTRY key node */\r
- if (!CmpCreateRegistryRoot())\r
- {\r
- /* Bugcheck */\r
- KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0);\r
- }\r
-\r
- /* Create the default security descriptor */\r
- SecurityDescriptor = CmpHiveRootSecurityDescriptor();\r
-\r
- /* Create '\Registry\Machine' key. */\r
- RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE");\r
- InitializeObjectAttributes(&ObjectAttributes,\r
- &KeyName,\r
- OBJ_CASE_INSENSITIVE,\r
- NULL,\r
- SecurityDescriptor);\r
- Status = NtCreateKey(&KeyHandle,\r
- KEY_READ | KEY_WRITE,\r
- &ObjectAttributes,\r
- 0,\r
- NULL,\r
- 0,\r
- NULL);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Bugcheck */\r
- KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0);\r
- }\r
-\r
- /* Close the handle */\r
- NtClose(KeyHandle);\r
-\r
- /* Create '\Registry\User' key. */\r
- RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER");\r
- InitializeObjectAttributes(&ObjectAttributes,\r
- &KeyName,\r
- OBJ_CASE_INSENSITIVE,\r
- NULL,\r
- SecurityDescriptor);\r
- Status = NtCreateKey(&KeyHandle,\r
- KEY_READ | KEY_WRITE,\r
- &ObjectAttributes,\r
- 0,\r
- NULL,\r
- 0,\r
- NULL);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Bugcheck */\r
- KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0);\r
- }\r
-\r
- /* Close the handle */\r
- NtClose(KeyHandle);\r
-\r
- /* Initialize the system hive */\r
- if (!CmpInitializeSystemHive(KeLoaderBlock))\r
- {\r
- /* Bugcheck */\r
- KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0);\r
- }\r
-\r
- /* Create the 'CurrentControlSet' link. */\r
- Status = CmpCreateControlSet(KeLoaderBlock);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Bugcheck */\r
- KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0);\r
- }\r
-\r
- /* Import the hardware hive (FIXME: We should create it from scratch) */\r
- BaseAddress = CmpRosGetHardwareHive(&Length);\r
- ((PHBASE_BLOCK)BaseAddress)->Length = Length;\r
- Status = CmpInitializeHive((PCMHIVE*)&HardwareHive,\r
- HINIT_MEMORY, //HINIT_CREATE,\r
- HIVE_NO_FILE, //HIVE_VOLATILE,\r
- HFILE_TYPE_PRIMARY,\r
- BaseAddress, // NULL,\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL,\r
- 0);\r
- CmPrepareHive(&HardwareHive->Hive);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Bugcheck */\r
- KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0);\r
- }\r
-\r
- /* Attach it to the machine key */\r
- RtlInitUnicodeString(&KeyName, REG_HARDWARE_KEY_NAME);\r
- Status = CmpLinkHiveToMaster(&KeyName,\r
- NULL,\r
- (PCMHIVE)HardwareHive,\r
- FALSE,\r
- SecurityDescriptor);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Bugcheck */\r
- KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0);\r
- }\r
-\r
- /* Fill out the Hardware key with the ARC Data from the Loader */\r
- Status = CmpInitializeHardwareConfiguration(KeLoaderBlock);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Bugcheck */\r
- KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0);\r
- }\r
-\r
- /* Initialize machine-dependent information into the registry */\r
- Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Bugcheck */\r
- KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0);\r
- }\r
-\r
- /* Initialize volatile registry settings */\r
- Status = CmpSetSystemValues(KeLoaderBlock);\r
- if (!NT_SUCCESS(Status))\r
- {\r
- /* Bugcheck */\r
- KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0);\r
- }\r
-\r
- /* Free the load options */\r
- ExFreePool(CmpLoadOptions.Buffer);\r
-\r
- /* If we got here, all went well */\r
- return TRUE;\r
-}\r
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: ntoskrnl/config/cmsysini.c
+ * PURPOSE: Configuration Manager - System Initialization Code
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "ntoskrnl.h"
+#define NDEBUG
+#include "debug.h"
+
+POBJECT_TYPE CmpKeyObjectType;
+PCMHIVE CmiVolatileHive;
+LIST_ENTRY CmpHiveListHead;
+ERESOURCE CmpRegistryLock;
+KGUARDED_MUTEX CmpSelfHealQueueLock;
+LIST_ENTRY CmpSelfHealQueueListHead;
+KEVENT CmpLoadWorkerEvent;
+LONG CmpLoadWorkerIncrement;
+PEPROCESS CmpSystemProcess;
+BOOLEAN HvShutdownComplete;
+PVOID CmpRegistryLockCallerCaller, CmpRegistryLockCaller;
+BOOLEAN CmpFlushOnLockRelease;
+BOOLEAN CmpSpecialBootCondition;
+BOOLEAN CmpNoWrite;
+BOOLEAN CmpWasSetupBoot;
+ULONG CmpTraceLevel = 0;
+
+extern LONG CmpFlushStarveWriters;
+extern BOOLEAN CmFirstTime;
+
+/* FUNCTIONS *****************************************************************/
+
+VOID
+NTAPI
+CmpDeleteKeyObject(PVOID DeletedObject)
+{
+ PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)DeletedObject;
+ PCM_KEY_CONTROL_BLOCK Kcb;
+ REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo;
+ REG_POST_OPERATION_INFORMATION PostOperationInfo;
+ NTSTATUS Status;
+ PAGED_CODE();
+
+ /* First off, prepare the handle close information callback */
+ PostOperationInfo.Object = KeyBody;
+ KeyHandleCloseInfo.Object = KeyBody;
+ Status = CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose,
+ &KeyHandleCloseInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ /* If we failed, notify the post routine */
+ PostOperationInfo.Status = Status;
+ CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo);
+ return;
+ }
+
+ /* Acquire hive lock */
+ CmpLockRegistry();
+
+ /* Make sure this is a valid key body */
+ if (KeyBody->Type == '20yk')
+ {
+ /* Get the KCB */
+ Kcb = KeyBody->KeyControlBlock;
+ if (Kcb)
+ {
+ /* Delist the key */
+ DelistKeyBodyFromKCB(KeyBody, FALSE);
+
+ /* Dereference the KCB */
+ CmpDelayDerefKeyControlBlock(Kcb);
+ }
+ }
+
+ /* Release the registry lock */
+ CmpUnlockRegistry();
+
+ /* Do the post callback */
+ PostOperationInfo.Status = STATUS_SUCCESS;
+ CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo);
+}
+
+VOID
+NTAPI
+CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL,
+ IN PVOID Object,
+ IN ACCESS_MASK GrantedAccess,
+ IN ULONG ProcessHandleCount,
+ IN ULONG SystemHandleCount)
+{
+ PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)Object;
+ PAGED_CODE();
+
+ /* Don't do anything if we're not the last handle */
+ if (SystemHandleCount > 1) return;
+
+ /* Make sure we're a valid key body */
+ if (KeyBody->Type == '20yk')
+ {
+ /* Don't do anything if we don't have a notify block */
+ if (!KeyBody->NotifyBlock) return;
+
+ /* This shouldn't happen yet */
+ ASSERT(FALSE);
+ }
+}
+
+NTSTATUS
+NTAPI
+CmpQueryKeyName(IN PVOID ObjectBody,
+ IN BOOLEAN HasName,
+ IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
+ IN ULONG Length,
+ OUT PULONG ReturnLength,
+ IN KPROCESSOR_MODE PreviousMode)
+{
+ PUNICODE_STRING KeyName;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)ObjectBody;
+ PCM_KEY_CONTROL_BLOCK Kcb = KeyBody->KeyControlBlock;
+
+ /* Acquire hive lock */
+ CmpLockRegistry();
+
+ /* Lock KCB shared */
+ CmpAcquireKcbLockShared(Kcb);
+
+ /* Check if it's a deleted block */
+ if (Kcb->Delete)
+ {
+ /* Release the locks */
+ CmpReleaseKcbLock(Kcb);
+ CmpUnlockRegistry();
+
+ /* Let the caller know it's deleted */
+ return STATUS_KEY_DELETED;
+ }
+
+ /* Get the name */
+ KeyName = CmpConstructName(Kcb);
+
+ /* Release the locks */
+ CmpReleaseKcbLock(Kcb);
+ CmpUnlockRegistry();
+
+ /* Check if we got the name */
+ if (!KeyName) return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Set the returned length */
+ *ReturnLength = KeyName->Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR);
+
+ /* Check if it fits into the provided buffer */
+ if ((Length < sizeof(OBJECT_NAME_INFORMATION)) ||
+ (Length < (*ReturnLength - sizeof(OBJECT_NAME_INFORMATION))))
+ {
+ /* Free the buffer allocated by CmpConstructName */
+ ExFreePool(KeyName);
+
+ /* Return buffer length failure */
+ return STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ /* Fill in the result */
+ _SEH2_TRY
+ {
+ /* Return data to user */
+ ObjectNameInfo->Name.Buffer = (PWCHAR)(ObjectNameInfo + 1);
+ ObjectNameInfo->Name.MaximumLength = KeyName->Length;
+ ObjectNameInfo->Name.Length = KeyName->Length;
+
+ /* Copy string content*/
+ RtlCopyMemory(ObjectNameInfo->Name.Buffer,
+ KeyName->Buffer,
+ *ReturnLength);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the status */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Free the buffer allocated by CmpConstructName */
+ ExFreePool(KeyName);
+
+ /* Return status */
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName,
+ IN ULONG HiveFlags,
+ OUT PCMHIVE *Hive,
+ IN OUT PBOOLEAN New,
+ IN ULONG CheckFlags)
+{
+ ULONG HiveDisposition, LogDisposition;
+ HANDLE FileHandle = NULL, LogHandle = NULL;
+ NTSTATUS Status;
+ ULONG Operation, FileType;
+ PCMHIVE NewHive;
+ PAGED_CODE();
+
+ /* Assume failure */
+ *Hive = NULL;
+
+ /* Open or create the hive files */
+ Status = CmpOpenHiveFiles(HiveName,
+ L".LOG",
+ &FileHandle,
+ &LogHandle,
+ &HiveDisposition,
+ &LogDisposition,
+ *New,
+ FALSE,
+ TRUE,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Check if we have a log handle */
+ FileType = (LogHandle) ? HFILE_TYPE_LOG : HFILE_TYPE_PRIMARY;
+
+ /* Check if we created or opened the hive */
+ if (HiveDisposition == FILE_CREATED)
+ {
+ /* Do a create operation */
+ Operation = HINIT_CREATE;
+ *New = TRUE;
+ }
+ else
+ {
+ /* Open it as a file */
+ Operation = HINIT_FILE;
+ *New = FALSE;
+ }
+
+ /* Check if we're sharing hives */
+ if (CmpShareSystemHives)
+ {
+ /* Then force using the primary hive */
+ FileType = HFILE_TYPE_PRIMARY;
+ if (LogHandle)
+ {
+ /* Get rid of the log handle */
+ ZwClose(LogHandle);
+ LogHandle = NULL;
+ }
+ }
+
+ /* Check if we're too late */
+ if (HvShutdownComplete)
+ {
+ /* Fail */
+ ZwClose(FileHandle);
+ if (LogHandle) ZwClose(LogHandle);
+ return STATUS_TOO_LATE;
+ }
+
+ /* Initialize the hive */
+ Status = CmpInitializeHive((PCMHIVE*)&NewHive,
+ Operation,
+ HiveFlags,
+ FileType,
+ NULL,
+ FileHandle,
+ LogHandle,
+ NULL,
+ HiveName,
+ 0);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ ZwClose(FileHandle);
+ if (LogHandle) ZwClose(LogHandle);
+ return Status;
+ }
+
+ /* Success, return hive */
+ *Hive = NewHive;
+
+ /* ROS: Init root key cell and prepare the hive */
+ if (Operation == HINIT_CREATE) CmCreateRootNode(&NewHive->Hive, L"");
+
+ /* Duplicate the hive name */
+ NewHive->FileFullPath.Buffer = ExAllocatePoolWithTag(PagedPool,
+ HiveName->Length,
+ TAG_CM);
+ if (NewHive->FileFullPath.Buffer)
+ {
+ /* Copy the string */
+ RtlCopyMemory(NewHive->FileFullPath.Buffer,
+ HiveName->Buffer,
+ HiveName->Length);
+ NewHive->FileFullPath.Length = HiveName->Length;
+ NewHive->FileFullPath.MaximumLength = HiveName->MaximumLength;
+ }
+
+ /* Return success */
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING KeyName, ValueName = { 0, 0, NULL };
+ HANDLE KeyHandle;
+ NTSTATUS Status;
+ ASSERT(LoaderBlock != NULL);
+
+ /* Setup attributes for loader options */
+ RtlInitUnicodeString(&KeyName,
+ L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
+ L"Control");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+
+ /* Key opened, now write to the key */
+ RtlInitUnicodeString(&KeyName, L"SystemStartOptions");
+ Status = NtSetValueKey(KeyHandle,
+ &KeyName,
+ 0,
+ REG_SZ,
+ CmpLoadOptions.Buffer,
+ CmpLoadOptions.Length);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+
+ /* Setup value name for system boot device */
+ RtlInitUnicodeString(&KeyName, L"SystemBootDevice");
+ RtlCreateUnicodeStringFromAsciiz(&ValueName, LoaderBlock->NtBootPathName);
+ Status = NtSetValueKey(KeyHandle,
+ &KeyName,
+ 0,
+ REG_SZ,
+ ValueName.Buffer,
+ ValueName.Length);
+
+Quickie:
+ /* Free the buffers */
+ RtlFreeUnicodeString(&ValueName);
+
+ /* Close the key and return */
+ NtClose(KeyHandle);
+
+ /* Return the status */
+ return (ExpInTextModeSetup ? STATUS_SUCCESS : Status);
+}
+
+NTSTATUS
+NTAPI
+CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+ UNICODE_STRING ConfigName = RTL_CONSTANT_STRING(L"Control\\IDConfigDB");
+ UNICODE_STRING SelectName =
+ RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\Select");
+ UNICODE_STRING KeyName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ CHAR ValueInfoBuffer[128];
+ PKEY_VALUE_FULL_INFORMATION ValueInfo;
+ CHAR Buffer[128];
+ WCHAR UnicodeBuffer[128];
+ HANDLE SelectHandle, KeyHandle, ConfigHandle = NULL, ProfileHandle = NULL;
+ HANDLE ParentHandle = NULL;
+ ULONG ControlSet, HwProfile;
+ ANSI_STRING TempString;
+ NTSTATUS Status;
+ ULONG ResultLength, Disposition;
+ PLOADER_PARAMETER_EXTENSION LoaderExtension;
+ PAGED_CODE();
+
+ /* Open the select key */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SelectName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenKey(&SelectHandle, KEY_READ, &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
+ if (!LoaderBlock->RegistryBase)
+ {
+ /* Build the ControlSet001 key */
+ RtlInitUnicodeString(&KeyName,
+ L"\\Registry\\Machine\\System\\ControlSet001");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtCreateKey(&KeyHandle,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ 0,
+ &Disposition);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Don't need the handle */
+ ZwClose(KeyHandle);
+
+ /* Use hard-coded setting */
+ ControlSet = 1;
+ goto UseSet;
+ }
+
+ /* Fail for real boots */
+ return Status;
+ }
+
+ /* Open the current value */
+ RtlInitUnicodeString(&KeyName, L"Current");
+ Status = NtQueryValueKey(SelectHandle,
+ &KeyName,
+ KeyValueFullInformation,
+ ValueInfoBuffer,
+ sizeof(ValueInfoBuffer),
+ &ResultLength);
+ NtClose(SelectHandle);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Get the actual value pointer, and get the control set ID */
+ ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;
+ ControlSet = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);
+
+ /* Create the current control set key */
+UseSet:
+ RtlInitUnicodeString(&KeyName,
+ L"\\Registry\\Machine\\System\\CurrentControlSet");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtCreateKey(&KeyHandle,
+ KEY_CREATE_LINK,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
+ &Disposition);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Sanity check */
+ ASSERT(Disposition == REG_CREATED_NEW_KEY);
+
+ /* Initialize the symbolic link name */
+ sprintf(Buffer,
+ "\\Registry\\Machine\\System\\ControlSet%03ld",
+ ControlSet);
+ RtlInitAnsiString(&TempString, Buffer);
+
+ /* Create a Unicode string out of it */
+ KeyName.MaximumLength = sizeof(UnicodeBuffer);
+ KeyName.Buffer = UnicodeBuffer;
+ Status = RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE);
+
+ /* Set the value */
+ Status = NtSetValueKey(KeyHandle,
+ &CmSymbolicLinkValueName,
+ 0,
+ REG_LINK,
+ KeyName.Buffer,
+ KeyName.Length);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Get the configuration database key */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &ConfigName,
+ OBJ_CASE_INSENSITIVE,
+ KeyHandle,
+ NULL);
+ Status = NtOpenKey(&ConfigHandle, KEY_READ, &ObjectAttributes);
+ NtClose(KeyHandle);
+
+ /* Check if we don't have one */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Cleanup and exit */
+ ConfigHandle = 0;
+ goto Cleanup;
+ }
+
+ /* Now get the current config */
+ RtlInitUnicodeString(&KeyName, L"CurrentConfig");
+ Status = NtQueryValueKey(ConfigHandle,
+ &KeyName,
+ KeyValueFullInformation,
+ ValueInfoBuffer,
+ sizeof(ValueInfoBuffer),
+ &ResultLength);
+
+ /* Set pointer to buffer */
+ ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;
+
+ /* Check if we failed or got a non DWORD-value */
+ if (!(NT_SUCCESS(Status)) || (ValueInfo->Type != REG_DWORD)) goto Cleanup;
+
+ /* Get the hadware profile */
+ HwProfile = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);
+
+ /* Open the hardware profile key */
+ RtlInitUnicodeString(&KeyName,
+ L"\\Registry\\Machine\\System\\CurrentControlSet"
+ L"\\Hardware Profiles");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenKey(&ParentHandle, KEY_READ, &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Exit and clean up */
+ ParentHandle = 0;
+ goto Cleanup;
+ }
+
+ /* Build the profile name */
+ sprintf(Buffer, "%04ld", HwProfile);
+ RtlInitAnsiString(&TempString, Buffer);
+
+ /* Convert it to Unicode */
+ KeyName.MaximumLength = sizeof(UnicodeBuffer);
+ KeyName.Buffer = UnicodeBuffer;
+ Status = RtlAnsiStringToUnicodeString(&KeyName,
+ &TempString,
+ FALSE);
+ ASSERT(Status == STATUS_SUCCESS);
+
+ /* Open the associated key */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ ParentHandle,
+ NULL);
+ Status = NtOpenKey(&ProfileHandle,
+ KEY_READ | KEY_WRITE,
+ &ObjectAttributes);
+ if (!NT_SUCCESS (Status))
+ {
+ /* Cleanup and exit */
+ ProfileHandle = 0;
+ goto Cleanup;
+ }
+
+ /* Check if we have a loader block extension */
+ LoaderExtension = LoaderBlock->Extension;
+ if (LoaderExtension)
+ {
+ ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE);
+ }
+
+ /* Create the current hardware profile key */
+ RtlInitUnicodeString(&KeyName,
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\"
+ L"Hardware Profiles\\Current");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtCreateKey(&KeyHandle,
+ KEY_CREATE_LINK,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
+ &Disposition);
+ if (NT_SUCCESS(Status))
+ {
+ /* Sanity check */
+ ASSERT(Disposition == REG_CREATED_NEW_KEY);
+
+ /* Create the profile name */
+ sprintf(Buffer,
+ "\\Registry\\Machine\\System\\CurrentControlSet\\"
+ "Hardware Profiles\\%04ld",
+ HwProfile);
+ RtlInitAnsiString(&TempString, Buffer);
+
+ /* Convert it to Unicode */
+ KeyName.MaximumLength = sizeof(UnicodeBuffer);
+ KeyName.Buffer = UnicodeBuffer;
+ Status = RtlAnsiStringToUnicodeString(&KeyName,
+ &TempString,
+ FALSE);
+ ASSERT(STATUS_SUCCESS == Status);
+
+ /* Set it */
+ Status = NtSetValueKey(KeyHandle,
+ &CmSymbolicLinkValueName,
+ 0,
+ REG_LINK,
+ KeyName.Buffer,
+ KeyName.Length);
+ NtClose(KeyHandle);
+ }
+
+ /* Close every opened handle */
+Cleanup:
+ if (ConfigHandle) NtClose(ConfigHandle);
+ if (ProfileHandle) NtClose(ProfileHandle);
+ if (ParentHandle) NtClose(ParentHandle);
+
+ /* Return success */
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName,
+ IN HANDLE RootDirectory,
+ IN PCMHIVE RegistryHive,
+ IN BOOLEAN Allocate,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ CM_PARSE_CONTEXT ParseContext = {0};
+ HANDLE KeyHandle;
+ PCM_KEY_BODY KeyBody;
+ PAGED_CODE();
+
+ /* Setup the object attributes */
+ InitializeObjectAttributes(&ObjectAttributes,
+ LinkName,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ RootDirectory,
+ SecurityDescriptor);
+
+ /* Setup the parse context */
+ ParseContext.CreateLink = TRUE;
+ ParseContext.CreateOperation = TRUE;
+ ParseContext.ChildHive.KeyHive = &RegistryHive->Hive;
+
+ /* Check if we have a root keycell or if we need to create it */
+ if (Allocate)
+ {
+ /* Create it */
+ ParseContext.ChildHive.KeyCell = HCELL_NIL;
+ }
+ else
+ {
+ /* We have one */
+ ParseContext.ChildHive.KeyCell = RegistryHive->Hive.BaseBlock->RootCell;
+ }
+
+ /* Create the link node */
+ Status = ObOpenObjectByName(&ObjectAttributes,
+ CmpKeyObjectType,
+ KernelMode,
+ NULL,
+ KEY_READ | KEY_WRITE,
+ (PVOID)&ParseContext,
+ &KeyHandle);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Mark the hive as clean */
+ RegistryHive->Hive.DirtyFlag = FALSE;
+
+ /* ReactOS Hack: Keep alive */
+ Status = ObReferenceObjectByHandle(KeyHandle,
+ 0,
+ CmpKeyObjectType,
+ KernelMode,
+ (PVOID*)&KeyBody,
+ NULL);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Close the extra handle */
+ ZwClose(KeyHandle);
+ return STATUS_SUCCESS;
+}
+
+BOOLEAN
+NTAPI
+CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+ PVOID HiveBase;
+ ANSI_STRING LoadString;
+ PVOID Buffer;
+ ULONG Length;
+ NTSTATUS Status;
+ BOOLEAN Allocate;
+ UNICODE_STRING KeyName;
+ PCMHIVE SystemHive = NULL;
+ UNICODE_STRING HiveName = RTL_CONSTANT_STRING(L"SYSTEM");
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ PAGED_CODE();
+
+ /* Setup the ansi string */
+ RtlInitAnsiString(&LoadString, LoaderBlock->LoadOptions);
+
+ /* Allocate the unicode buffer */
+ Length = LoadString.Length * sizeof(WCHAR) + sizeof(UNICODE_NULL);
+ Buffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
+ if (!Buffer)
+ {
+ /* Fail */
+ KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 3, 1, (ULONG_PTR)LoaderBlock, 0);
+ }
+
+ /* Setup the unicode string */
+ RtlInitEmptyUnicodeString(&CmpLoadOptions, Buffer, (USHORT)Length);
+
+ /* Add the load options and null-terminate */
+ RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE);
+ CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL;
+ CmpLoadOptions.Length += sizeof(WCHAR);
+
+ /* Get the System Hive base address */
+ HiveBase = LoaderBlock->RegistryBase;
+ if (HiveBase)
+ {
+ /* Import it */
+ ((PHBASE_BLOCK)HiveBase)->Length = LoaderBlock->RegistryLength;
+ Status = CmpInitializeHive((PCMHIVE*)&SystemHive,
+ HINIT_MEMORY,
+ HIVE_NOLAZYFLUSH,
+ HFILE_TYPE_LOG,
+ HiveBase,
+ NULL,
+ NULL,
+ NULL,
+ &HiveName,
+ 2);
+ if (!NT_SUCCESS(Status)) return FALSE;
+
+ /* Set the hive filename */
+ RtlCreateUnicodeString(&SystemHive->FileFullPath,
+ L"\\SystemRoot\\System32\\Config\\SYSTEM");
+
+ /* We imported, no need to create a new hive */
+ Allocate = FALSE;
+
+ /* Manually set the hive as volatile, if in Live CD mode */
+ if (CmpShareSystemHives) SystemHive->Hive.HiveFlags = HIVE_VOLATILE;
+ }
+ else
+ {
+ /* Create it */
+ Status = CmpInitializeHive(&SystemHive,
+ HINIT_CREATE,
+ HIVE_NOLAZYFLUSH,
+ HFILE_TYPE_LOG,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &HiveName,
+ 0);
+ if (!NT_SUCCESS(Status)) return FALSE;
+
+ /* Set the hive filename */
+ RtlCreateUnicodeString(&SystemHive->FileFullPath,
+ L"\\SystemRoot\\System32\\Config\\SYSTEM");
+
+ /* Tell CmpLinkHiveToMaster to allocate a hive */
+ Allocate = TRUE;
+ }
+
+ /* Save the boot type */
+ CmpBootType = SystemHive->Hive.BaseBlock->BootType;
+
+ /* Are we in self-healing mode? */
+ if (!CmSelfHeal)
+ {
+ /* Disable self-healing internally and check if boot type wanted it */
+ CmpSelfHeal = FALSE;
+ if (CmpBootType & 4)
+ {
+ /* We're disabled, so bugcheck */
+ KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO,
+ 3,
+ 3,
+ (ULONG_PTR)SystemHive,
+ 0);
+ }
+ }
+
+ /* Create the default security descriptor */
+ SecurityDescriptor = CmpHiveRootSecurityDescriptor();
+
+ /* Attach it to the system key */
+ RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM");
+ Status = CmpLinkHiveToMaster(&KeyName,
+ NULL,
+ (PCMHIVE)SystemHive,
+ Allocate,
+ SecurityDescriptor);
+
+ /* Free the security descriptor */
+ ExFreePoolWithTag(SecurityDescriptor, TAG_CM);
+ if (!NT_SUCCESS(Status)) return FALSE;
+
+ /* Add the hive to the hive list */
+ CmpMachineHiveList[3].CmHive = (PCMHIVE)SystemHive;
+
+ /* Success! */
+ return TRUE;
+}
+
+NTSTATUS
+NTAPI
+CmpCreateObjectTypes(VOID)
+{
+ OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
+ UNICODE_STRING Name;
+ GENERIC_MAPPING CmpKeyMapping = {KEY_READ,
+ KEY_WRITE,
+ KEY_EXECUTE,
+ KEY_ALL_ACCESS};
+ PAGED_CODE();
+
+ /* Initialize the Key object type */
+ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
+ RtlInitUnicodeString(&Name, L"Key");
+ ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
+ ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY);
+ ObjectTypeInitializer.GenericMapping = CmpKeyMapping;
+ ObjectTypeInitializer.PoolType = PagedPool;
+ ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;
+ ObjectTypeInitializer.UseDefaultObject = TRUE;
+ ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject;
+ ObjectTypeInitializer.ParseProcedure = CmpParseKey;
+ ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod;
+ ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName;
+ ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
+ ObjectTypeInitializer.SecurityRequired = TRUE;
+
+ /* Create it */
+ return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType);
+}
+
+BOOLEAN
+NTAPI
+CmpCreateRootNode(IN PHHIVE Hive,
+ IN PCWSTR Name,
+ OUT PHCELL_INDEX Index)
+{
+ UNICODE_STRING KeyName;
+ PCM_KEY_NODE KeyCell;
+ LARGE_INTEGER SystemTime;
+ PAGED_CODE();
+
+ /* Initialize the node name and allocate it */
+ RtlInitUnicodeString(&KeyName, Name);
+ *Index = HvAllocateCell(Hive,
+ FIELD_OFFSET(CM_KEY_NODE, Name) +
+ CmpNameSize(Hive, &KeyName),
+ Stable,
+ HCELL_NIL);
+ if (*Index == HCELL_NIL) return FALSE;
+
+ /* Set the cell index and get the data */
+ Hive->BaseBlock->RootCell = *Index;
+ KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index);
+ if (!KeyCell) return FALSE;
+
+ /* Setup the cell */
+ KeyCell->Signature = (USHORT)CM_KEY_NODE_SIGNATURE;
+ KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE;
+ KeQuerySystemTime(&SystemTime);
+ KeyCell->LastWriteTime = SystemTime;
+ KeyCell->Parent = HCELL_NIL;
+ KeyCell->SubKeyCounts[Stable] = 0;
+ KeyCell->SubKeyCounts[Volatile] = 0;
+ KeyCell->SubKeyLists[Stable] = HCELL_NIL;
+ KeyCell->SubKeyLists[Volatile] = HCELL_NIL;
+ KeyCell->ValueList.Count = 0;
+ KeyCell->ValueList.List = HCELL_NIL;
+ KeyCell->Security = HCELL_NIL;
+ KeyCell->Class = HCELL_NIL;
+ KeyCell->ClassLength = 0;
+ KeyCell->MaxNameLen = 0;
+ KeyCell->MaxClassLen = 0;
+ KeyCell->MaxValueNameLen = 0;
+ KeyCell->MaxValueDataLen = 0;
+
+ /* Copy the name (this will also set the length) */
+ KeyCell->NameLength = CmpCopyName(Hive, (PWCHAR)KeyCell->Name, &KeyName);
+
+ /* Check if the name was compressed */
+ if (KeyCell->NameLength < KeyName.Length)
+ {
+ /* Set the flag */
+ KeyCell->Flags |= KEY_COMP_NAME;
+ }
+
+ /* Return success */
+ HvReleaseCell(Hive, *Index);
+ return TRUE;
+}
+
+BOOLEAN
+NTAPI
+CmpCreateRegistryRoot(VOID)
+{
+ UNICODE_STRING KeyName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PCM_KEY_BODY RootKey;
+ HCELL_INDEX RootIndex;
+ NTSTATUS Status;
+ PCM_KEY_NODE KeyCell;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ PCM_KEY_CONTROL_BLOCK Kcb;
+ PAGED_CODE();
+
+ /* Setup the root node */
+ if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex))
+ {
+ /* We failed */
+ return FALSE;
+ }
+
+ /* Create '\Registry' key. */
+ RtlInitUnicodeString(&KeyName, L"\\REGISTRY");
+ SecurityDescriptor = CmpHiveRootSecurityDescriptor();
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = ObCreateObject(KernelMode,
+ CmpKeyObjectType,
+ &ObjectAttributes,
+ KernelMode,
+ NULL,
+ sizeof(CM_KEY_BODY),
+ 0,
+ 0,
+ (PVOID*)&RootKey);
+ ExFreePoolWithTag(SecurityDescriptor, TAG_CM);
+ if (!NT_SUCCESS(Status)) return FALSE;
+
+ /* Sanity check, and get the key cell */
+ ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL);
+ KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex);
+ if (!KeyCell) return FALSE;
+
+ /* Create the KCB */
+ RtlInitUnicodeString(&KeyName, L"\\REGISTRY");
+ Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive,
+ RootIndex,
+ KeyCell,
+ NULL,
+ 0,
+ &KeyName);
+ if (!Kcb) return FALSE;
+
+ /* Initialize the object */
+ RootKey->KeyControlBlock = Kcb;
+ RootKey->Type = '20yk';
+ RootKey->NotifyBlock = NULL;
+ RootKey->ProcessID = PsGetCurrentProcessId();
+
+ /* Link with KCB */
+ EnlistKeyBodyWithKCB(RootKey, 0);
+
+ /* Insert the key into the namespace */
+ Status = ObInsertObject(RootKey,
+ NULL,
+ KEY_ALL_ACCESS,
+ 0,
+ NULL,
+ &CmpRegistryRootHandle);
+ if (!NT_SUCCESS(Status)) return FALSE;
+
+ /* Reference the key again so that we never lose it */
+ Status = ObReferenceObjectByHandle(CmpRegistryRootHandle,
+ KEY_READ,
+ NULL,
+ KernelMode,
+ (PVOID*)&RootKey,
+ NULL);
+ if (!NT_SUCCESS(Status)) return FALSE;
+
+ /* Completely sucessful */
+ return TRUE;
+}
+
+NTSTATUS
+NTAPI
+CmpGetRegistryPath(IN PWCHAR ConfigPath)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ HANDLE KeyHandle;
+ PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
+ UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
+ UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
+ ULONG BufferSize, ResultSize;
+
+ /* Check if we are booted in setup */
+ if (ExpInTextModeSetup)
+ {
+ /* Setup the object attributes */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ /* Open the key */
+ Status = ZwOpenKey(&KeyHandle,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Allocate the buffer */
+ BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
+ ValueInfo = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_CM);
+ if (!ValueInfo)
+ {
+ /* Fail */
+ ZwClose(KeyHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Query the value */
+ Status = ZwQueryValueKey(KeyHandle,
+ &ValueName,
+ KeyValuePartialInformation,
+ ValueInfo,
+ BufferSize,
+ &ResultSize);
+ ZwClose(KeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ ExFreePoolWithTag(ValueInfo, TAG_CM);
+ return Status;
+ }
+
+ /* Copy the config path and null-terminate it */
+ RtlCopyMemory(ConfigPath,
+ ValueInfo->Data,
+ ValueInfo->DataLength);
+ ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = UNICODE_NULL;
+ ExFreePoolWithTag(ValueInfo, TAG_CM);
+ }
+ else
+ {
+ /* Just use default path */
+ wcscpy(ConfigPath, L"\\SystemRoot");
+ }
+
+ /* Add registry path */
+ wcscat(ConfigPath, L"\\System32\\Config\\");
+
+ /* Done */
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+CmpLoadHiveThread(IN PVOID StartContext)
+{
+ WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH];
+ UNICODE_STRING TempName, FileName, RegName;
+ ULONG FileStart, RegStart, i, ErrorResponse, WorkerCount, Length;
+ ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize;
+ PCMHIVE CmHive;
+ HANDLE PrimaryHandle, LogHandle;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PVOID ErrorParameters;
+ PAGED_CODE();
+
+ /* Get the hive index, make sure it makes sense */
+ i = PtrToUlong(StartContext);
+ ASSERT(CmpMachineHiveList[i].Name != NULL);
+
+ /* We were started */
+ CmpMachineHiveList[i].ThreadStarted = TRUE;
+
+ /* Build the file name and registry name strings */
+ RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);
+ RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);
+
+ /* Now build the system root path */
+ CmpGetRegistryPath(ConfigPath);
+ RtlInitUnicodeString(&TempName, ConfigPath);
+ RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
+ FileStart = FileName.Length;
+
+ /* And build the registry root path */
+ RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
+ RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
+ RegStart = RegName.Length;
+
+ /* Build the base name */
+ RegName.Length = RegStart;
+ RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
+ RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
+
+ /* Check if this is a child of the root */
+ if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')
+ {
+ /* Then setup the whole name */
+ RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
+ RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
+ }
+
+ /* Now add the rest of the file name */
+ RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
+ FileName.Length = FileStart;
+ RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
+ if (!CmpMachineHiveList[i].CmHive)
+ {
+ /* We need to allocate a new hive structure */
+ CmpMachineHiveList[i].Allocate = TRUE;
+
+ /* Load the hive file */
+ Status = CmpInitHiveFromFile(&FileName,
+ CmpMachineHiveList[i].HHiveFlags,
+ &CmHive,
+ &CmpMachineHiveList[i].Allocate,
+ 0);
+ if (!(NT_SUCCESS(Status)) ||
+ (!(CmHive->FileHandles[HFILE_TYPE_LOG]) && !(CmpMiniNTBoot))) // HACK
+ {
+ /* We failed or couldn't get a log file, raise a hard error */
+ ErrorParameters = &FileName;
+ NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
+ 1,
+ 1,
+ (PULONG_PTR)&ErrorParameters,
+ OptionOk,
+ &ErrorResponse);
+ }
+
+ /* Set the hive flags and newly allocated hive pointer */
+ CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags;
+ CmpMachineHiveList[i].CmHive2 = CmHive;
+ }
+ else
+ {
+ /* We already have a hive, is it volatile? */
+ CmHive = CmpMachineHiveList[i].CmHive;
+ if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE))
+ {
+ /* It's now, open the hive file and log */
+ Status = CmpOpenHiveFiles(&FileName,
+ L".LOG",
+ &PrimaryHandle,
+ &LogHandle,
+ &PrimaryDisposition,
+ &SecondaryDisposition,
+ TRUE,
+ TRUE,
+ FALSE,
+ &ClusterSize);
+ if (!(NT_SUCCESS(Status)) || !(LogHandle))
+ {
+ /* Couldn't open the hive or its log file, raise a hard error */
+ ErrorParameters = &FileName;
+ NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
+ 1,
+ 1,
+ (PULONG_PTR)&ErrorParameters,
+ OptionOk,
+ &ErrorResponse);
+
+ /* And bugcheck for posterity's sake */
+ KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status);
+ }
+
+ /* Save the file handles. This should remove our sync hacks */
+ CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle;
+ CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;
+
+ /* Allow lazy flushing since the handles are there -- remove sync hacks */
+ //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
+ CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH;
+
+ /* Get the real size of the hive */
+ Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE;
+
+ /* Check if the cluster size doesn't match */
+ if (CmHive->Hive.Cluster != ClusterSize) ASSERT(FALSE);
+
+ /* Set the file size */
+ //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
+ {
+ /* This shouldn't fail */
+ //ASSERT(FALSE);
+ }
+
+ /* Another thing we don't support is NTLDR-recovery */
+ if (CmHive->Hive.BaseBlock->BootRecover) ASSERT(FALSE);
+
+ /* Finally, set our allocated hive to the same hive we've had */
+ CmpMachineHiveList[i].CmHive2 = CmHive;
+ ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2);
+ }
+ }
+
+ /* We're done */
+ CmpMachineHiveList[i].ThreadFinished = TRUE;
+
+ /* Check if we're the last worker */
+ WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement);
+ if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES)
+ {
+ /* Signal the event */
+ KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE);
+ }
+
+ /* Kill the thread */
+ PsTerminateSystemThread(Status);
+}
+
+VOID
+NTAPI
+CmpInitializeHiveList(IN USHORT Flag)
+{
+ WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH];
+ UNICODE_STRING TempName, FileName, RegName;
+ HANDLE Thread;
+ NTSTATUS Status;
+ ULONG FileStart, RegStart, i;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ PAGED_CODE();
+
+ /* Allow writing for now */
+ CmpNoWrite = FALSE;
+
+ /* Build the file name and registry name strings */
+ RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);
+ RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);
+
+ /* Now build the system root path */
+ CmpGetRegistryPath(ConfigPath);
+ RtlInitUnicodeString(&TempName, ConfigPath);
+ RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
+ FileStart = FileName.Length;
+
+ /* And build the registry root path */
+ RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
+ RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
+ RegStart = RegName.Length;
+
+ /* Setup the event to synchronize workers */
+ KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE);
+
+ /* Enter special boot condition */
+ CmpSpecialBootCondition = TRUE;
+
+ /* Create the SD for the root hives */
+ SecurityDescriptor = CmpHiveRootSecurityDescriptor();
+
+ /* Loop every hive we care about */
+ for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
+ {
+ /* Make sure the list is setup */
+ ASSERT(CmpMachineHiveList[i].Name != NULL);
+
+ /* Create a thread to handle this hive */
+ Status = PsCreateSystemThread(&Thread,
+ THREAD_ALL_ACCESS,
+ NULL,
+ 0,
+ NULL,
+ CmpLoadHiveThread,
+ UlongToPtr(i));
+ if (NT_SUCCESS(Status))
+ {
+ /* We don't care about the handle -- the thread self-terminates */
+ ZwClose(Thread);
+ }
+ else
+ {
+ /* Can't imagine this happening */
+ KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status);
+ }
+ }
+
+ /* Make sure we've reached the end of the list */
+ ASSERT(CmpMachineHiveList[i].Name == NULL);
+
+ /* Wait for hive loading to finish */
+ KeWaitForSingleObject(&CmpLoadWorkerEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ /* Exit the special boot condition and make sure all workers completed */
+ CmpSpecialBootCondition = FALSE;
+ ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES);
+
+ /* Loop hives again */
+ for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
+ {
+ /* Make sure the thread ran and finished */
+ ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE);
+ ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE);
+
+ /* Check if this was a new hive */
+ if (!CmpMachineHiveList[i].CmHive)
+ {
+ /* Make sure we allocated something */
+ ASSERT(CmpMachineHiveList[i].CmHive2 != NULL);
+
+ /* Build the base name */
+ RegName.Length = RegStart;
+ RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
+ RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
+
+ /* Check if this is a child of the root */
+ if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')
+ {
+ /* Then setup the whole name */
+ RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
+ RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
+ }
+
+ /* Now link the hive to its master */
+ Status = CmpLinkHiveToMaster(&RegName,
+ NULL,
+ CmpMachineHiveList[i].CmHive2,
+ CmpMachineHiveList[i].Allocate,
+ SecurityDescriptor);
+ if (Status != STATUS_SUCCESS)
+ {
+ /* Linking needs to work */
+ KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName);
+ }
+
+ /* Check if we had to allocate a new hive */
+ if (CmpMachineHiveList[i].Allocate)
+ {
+ /* Sync the new hive */
+ //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
+ }
+ }
+
+ /* Check if we created a new hive */
+ if (CmpMachineHiveList[i].CmHive2)
+ {
+ /* TODO: Add to HiveList key */
+ }
+ }
+
+ /* Get rid of the SD */
+ ExFreePoolWithTag(SecurityDescriptor, TAG_CM);
+
+ /* FIXME: Link SECURITY to SAM */
+
+ /* FIXME: Link S-1-5-18 to .Default */
+}
+
+BOOLEAN
+NTAPI
+CmInitSystem1(VOID)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING KeyName;
+ HANDLE KeyHandle;
+ NTSTATUS Status;
+ PCMHIVE HardwareHive;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ PAGED_CODE();
+
+ /* Check if this is PE-boot */
+ if (InitIsWinPEMode)
+ {
+ /* Set registry to PE mode */
+ CmpMiniNTBoot = TRUE;
+ CmpShareSystemHives = TRUE;
+ }
+
+ /* Initialize the hive list and lock */
+ InitializeListHead(&CmpHiveListHead);
+ ExInitializePushLock((PVOID)&CmpHiveListHeadLock);
+ ExInitializePushLock((PVOID)&CmpLoadHiveLock);
+
+ /* Initialize registry lock */
+ ExInitializeResourceLite(&CmpRegistryLock);
+
+ /* Initialize the cache */
+ CmpInitializeCache();
+
+ /* Initialize allocation and delayed dereferencing */
+ CmpInitCmPrivateAlloc();
+ CmpInitCmPrivateDelayAlloc();
+ CmpInitDelayDerefKCBEngine();
+
+ /* Initialize callbacks */
+ CmpInitCallback();
+
+ /* Initialize self healing */
+ KeInitializeGuardedMutex(&CmpSelfHealQueueLock);
+ InitializeListHead(&CmpSelfHealQueueListHead);
+
+ /* Save the current process and lock the registry */
+ CmpSystemProcess = PsGetCurrentProcess();
+
+ /* Create the key object types */
+ Status = CmpCreateObjectTypes();
+ if (!NT_SUCCESS(Status))
+ {
+ /* Bugcheck */
+ KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0);
+ }
+
+ /* Build the master hive */
+ Status = CmpInitializeHive((PCMHIVE*)&CmiVolatileHive,
+ HINIT_CREATE,
+ HIVE_VOLATILE,
+ HFILE_TYPE_PRIMARY,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Bugcheck */
+ KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0);
+ }
+
+ /* Create the \REGISTRY key node */
+ if (!CmpCreateRegistryRoot())
+ {
+ /* Bugcheck */
+ KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0);
+ }
+
+ /* Create the default security descriptor */
+ SecurityDescriptor = CmpHiveRootSecurityDescriptor();
+
+ /* Create '\Registry\Machine' key. */
+ RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ SecurityDescriptor);
+ Status = NtCreateKey(&KeyHandle,
+ KEY_READ | KEY_WRITE,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ 0,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Bugcheck */
+ KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0);
+ }
+
+ /* Close the handle */
+ NtClose(KeyHandle);
+
+ /* Create '\Registry\User' key. */
+ RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ SecurityDescriptor);
+ Status = NtCreateKey(&KeyHandle,
+ KEY_READ | KEY_WRITE,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ 0,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Bugcheck */
+ KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0);
+ }
+
+ /* Close the handle */
+ NtClose(KeyHandle);
+
+ /* Initialize the system hive */
+ if (!CmpInitializeSystemHive(KeLoaderBlock))
+ {
+ /* Bugcheck */
+ KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0);
+ }
+
+ /* Create the 'CurrentControlSet' link. */
+ Status = CmpCreateControlSet(KeLoaderBlock);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Bugcheck */
+ KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0);
+ }
+
+ /* Create the hardware hive */
+ Status = CmpInitializeHive((PCMHIVE*)&HardwareHive,
+ HINIT_CREATE,
+ HIVE_VOLATILE,
+ HFILE_TYPE_PRIMARY,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Bugcheck */
+ KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0);
+ }
+
+ /* Add the hive to the hive list */
+ CmpMachineHiveList[0].CmHive = (PCMHIVE)HardwareHive;
+
+ /* Attach it to the machine key */
+ RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE");
+ Status = CmpLinkHiveToMaster(&KeyName,
+ NULL,
+ (PCMHIVE)HardwareHive,
+ TRUE,
+ SecurityDescriptor);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Bugcheck */
+ KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0);
+ }
+
+ /* FIXME: Add to HiveList key */
+
+ /* Free the security descriptor */
+ ExFreePoolWithTag(SecurityDescriptor, TAG_CM);
+
+ /* Fill out the Hardware key with the ARC Data from the Loader */
+ Status = CmpInitializeHardwareConfiguration(KeLoaderBlock);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Bugcheck */
+ KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0);
+ }
+
+ /* Initialize machine-dependent information into the registry */
+ Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Bugcheck */
+ KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0);
+ }
+
+ /* Initialize volatile registry settings */
+ Status = CmpSetSystemValues(KeLoaderBlock);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Bugcheck */
+ KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0);
+ }
+
+ /* Free the load options */
+ ExFreePoolWithTag(CmpLoadOptions.Buffer, TAG_CM);
+
+ /* If we got here, all went well */
+ return TRUE;
+}
+
+VOID
+NTAPI
+CmpLockRegistryExclusive(VOID)
+{
+ /* Enter a critical region and lock the registry */
+ KeEnterCriticalRegion();
+ ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
+
+ /* Sanity check */
+ ASSERT(CmpFlushStarveWriters == 0);
+ RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller);
+}
+
+VOID
+NTAPI
+CmpLockRegistry(VOID)
+{
+ /* Enter a critical region */
+ KeEnterCriticalRegion();
+
+ /* Check if we have to starve writers */
+ if (CmpFlushStarveWriters)
+ {
+ /* Starve exlusive waiters */
+ ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE);
+ }
+ else
+ {
+ /* Just grab the lock */
+ ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE);
+ }
+}
+
+BOOLEAN
+NTAPI
+CmpTestRegistryLock(VOID)
+{
+ /* Test the lock */
+ return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE;
+}
+
+BOOLEAN
+NTAPI
+CmpTestRegistryLockExclusive(VOID)
+{
+ /* Test the lock */
+ return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE;
+}
+
+VOID
+NTAPI
+CmpUnlockRegistry(VOID)
+{
+ /* Sanity check */
+ CMP_ASSERT_REGISTRY_LOCK();
+
+ /* Check if we should flush the registry */
+ if (CmpFlushOnLockRelease)
+ {
+ /* The registry should be exclusively locked for this */
+ CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
+
+ /* Flush the registry */
+ CmpDoFlushAll(TRUE);
+ CmpFlushOnLockRelease = FALSE;
+ }
+
+ /* Release the lock and leave the critical region */
+ ExReleaseResourceLite(&CmpRegistryLock);
+ KeLeaveCriticalRegion();
+}
+
+VOID
+NTAPI
+CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1,
+ IN ULONG ConvKey2)
+{
+ ULONG Index1, Index2;
+
+ /* Sanity check */
+ CMP_ASSERT_REGISTRY_LOCK();
+
+ /* Get hash indexes */
+ Index1 = GET_HASH_INDEX(ConvKey1);
+ Index2 = GET_HASH_INDEX(ConvKey2);
+
+ /* See which one is highest */
+ if (Index1 < Index2)
+ {
+ /* Grab them in the proper order */
+ CmpAcquireKcbLockExclusiveByKey(ConvKey1);
+ CmpAcquireKcbLockExclusiveByKey(ConvKey2);
+ }
+ else
+ {
+ /* Grab the second one first, then the first */
+ CmpAcquireKcbLockExclusiveByKey(ConvKey2);
+ if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1);
+ }
+}
+
+VOID
+NTAPI
+CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1,
+ IN ULONG ConvKey2)
+{
+ ULONG Index1, Index2;
+
+ /* Sanity check */
+ CMP_ASSERT_REGISTRY_LOCK();
+
+ /* Get hash indexes */
+ Index1 = GET_HASH_INDEX(ConvKey1);
+ Index2 = GET_HASH_INDEX(ConvKey2);
+ ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2).Owner == KeGetCurrentThread()) ||
+ (CmpTestRegistryLockExclusive()));
+
+ /* See which one is highest */
+ if (Index1 < Index2)
+ {
+ /* Grab them in the proper order */
+ ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) ||
+ (CmpTestRegistryLockExclusive()));
+ CmpReleaseKcbLockByKey(ConvKey2);
+ CmpReleaseKcbLockByKey(ConvKey1);
+ }
+ else
+ {
+ /* Release the first one first, then the second */
+ if (Index1 != Index2)
+ {
+ ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) ||
+ (CmpTestRegistryLockExclusive()));
+ CmpReleaseKcbLockByKey(ConvKey1);
+ }
+ CmpReleaseKcbLockByKey(ConvKey2);
+ }
+}
+
+VOID
+NTAPI
+CmShutdownSystem(VOID)
+{
+ /* Kill the workers and flush all hives */
+ if (!CmFirstTime) CmpShutdownWorkers();
+ CmpDoFlushAll(TRUE);
+}