diff --git a/reactos/ntoskrnl/cm/regfile.c b/reactos/ntoskrnl/cm/regfile.c index 6ec8914af16..3b63ce5c521 100644 --- a/reactos/ntoskrnl/cm/regfile.c +++ b/reactos/ntoskrnl/cm/regfile.c @@ -15,9 +15,7 @@ #include #include "cm.h" - -/* uncomment to enable hive checks (incomplete and probably buggy) */ -//#define HIVE_CHECK +#include "..\config\cm.h" /* LOCAL MACROS *************************************************************/ @@ -165,276 +163,6 @@ CmiCreateNewRegFile(HANDLE FileHandle) return(Status); } - -#ifdef HIVE_CHECK - -static ULONG -CmiCalcChecksum(PULONG Buffer) -{ - ULONG Sum = 0; - ULONG i; - - for (i = 0; i < 127; i++) - Sum ^= Buffer[i]; - if (Sum == (ULONG)-1) - Sum = (ULONG)-2; - if (Sum == 0) - Sum = 1; - - return(Sum); -} - -static NTSTATUS -CmiCheckAndFixHive(PEREGISTRY_HIVE RegistryHive) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - FILE_STANDARD_INFORMATION fsi; - IO_STATUS_BLOCK IoStatusBlock; - HANDLE HiveHandle = INVALID_HANDLE_VALUE; - HANDLE LogHandle = INVALID_HANDLE_VALUE; - PHBASE_BLOCK HiveHeader = NULL; - PHBASE_BLOCK LogHeader = NULL; - LARGE_INTEGER FileOffset; - ULONG FileSize; - ULONG BufferSize; - ULONG BitmapSize; - RTL_BITMAP BlockBitMap; - NTSTATUS Status; - - DPRINT("CmiCheckAndFixHive() called\n"); - - /* Try to open the hive file */ - InitializeObjectAttributes(&ObjectAttributes, - &RegistryHive->HiveFileName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = ZwCreateFile(&HiveHandle, - FILE_READ_DATA | FILE_READ_ATTRIBUTES, - &ObjectAttributes, - &IoStatusBlock, - NULL, - FILE_ATTRIBUTE_NORMAL, - 0, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, - NULL, - 0); - if (Status == STATUS_OBJECT_NAME_NOT_FOUND) - { - return(STATUS_SUCCESS); - } - if (!NT_SUCCESS(Status)) - { - DPRINT("ZwCreateFile() failed (Status %lx)\n", Status); - return(Status); - } - - /* Try to open the log file */ - InitializeObjectAttributes(&ObjectAttributes, - &RegistryHive->LogFileName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = ZwCreateFile(&LogHandle, - FILE_READ_DATA | FILE_READ_ATTRIBUTES, - &ObjectAttributes, - &IoStatusBlock, - NULL, - FILE_ATTRIBUTE_NORMAL, - 0, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, - NULL, - 0); - if (Status == STATUS_OBJECT_NAME_NOT_FOUND) - { - LogHandle = INVALID_HANDLE_VALUE; - } - else if (!NT_SUCCESS(Status)) - { - DPRINT("ZwCreateFile() failed (Status %lx)\n", Status); - ZwClose(HiveHandle); - return(Status); - } - - /* Allocate hive header */ - HiveHeader = ExAllocatePool(PagedPool, - sizeof(HBASE_BLOCK)); - if (HiveHeader == NULL) - { - DPRINT("ExAllocatePool() failed\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto ByeBye; - } - - /* Read hive base block */ - FileOffset.QuadPart = 0ULL; - Status = ZwReadFile(HiveHandle, - 0, - 0, - 0, - &IoStatusBlock, - HiveHeader, - sizeof(HBASE_BLOCK), - &FileOffset, - 0); - if (!NT_SUCCESS(Status)) - { - DPRINT("ZwReadFile() failed (Status %lx)\n", Status); - goto ByeBye; - } - - if (LogHandle == INVALID_HANDLE_VALUE) - { - if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) || - HiveHeader->Sequence1 != HiveHeader->Sequence2) - { - /* There is no way to fix the hive without log file - BSOD! */ - DPRINT("Hive header inconsistent and no log file available!\n"); - KEBUGCHECK(CONFIG_LIST_FAILED); - } - - Status = STATUS_SUCCESS; - goto ByeBye; - } - else - { - /* Allocate hive header */ - LogHeader = ExAllocatePool(PagedPool, - HV_LOG_HEADER_SIZE); - if (LogHeader == NULL) - { - DPRINT("ExAllocatePool() failed\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto ByeBye; - } - - /* Read log file header */ - FileOffset.QuadPart = 0ULL; - Status = ZwReadFile(LogHandle, - 0, - 0, - 0, - &IoStatusBlock, - LogHeader, - HV_LOG_HEADER_SIZE, - &FileOffset, - 0); - if (!NT_SUCCESS(Status)) - { - DPRINT("ZwReadFile() failed (Status %lx)\n", Status); - goto ByeBye; - } - - /* Check log file header integrity */ - if (LogHeader->Checksum != CmiCalcChecksum((PULONG)LogHeader) || - LogHeader->Sequence1 != LogHeader->Sequence2) - { - if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) || - HiveHeader->Sequence1 != HiveHeader->Sequence2) - { - DPRINT("Hive file and log file are inconsistent!\n"); - KEBUGCHECK(CONFIG_LIST_FAILED); - } - - /* Log file damaged but hive is okay */ - Status = STATUS_SUCCESS; - goto ByeBye; - } - - if (HiveHeader->Sequence1 == HiveHeader->Sequence2 && - HiveHeader->Sequence1 == LogHeader->Sequence1) - { - /* Hive and log file are up-to-date */ - Status = STATUS_SUCCESS; - goto ByeBye; - } - - /* - * Hive needs an update! - */ - - /* Get file size */ - Status = ZwQueryInformationFile(LogHandle, - &IoStatusBlock, - &fsi, - sizeof(fsi), - FileStandardInformation); - if (!NT_SUCCESS(Status)) - { - DPRINT("ZwQueryInformationFile() failed (Status %lx)\n", Status); - goto ByeBye; - } - FileSize = fsi.EndOfFile.u.LowPart; - - /* Calculate bitmap and block size */ - BitmapSize = ROUND_UP((FileSize / HV_BLOCK_SIZE) - 1, sizeof(ULONG) * 8) / 8; - BufferSize = HV_LOG_HEADER_SIZE + sizeof(ULONG) + BitmapSize; - BufferSize = ROUND_UP(BufferSize, HV_BLOCK_SIZE); - - /* Reallocate log header block */ - ExFreePool(LogHeader); - LogHeader = ExAllocatePool(PagedPool, - BufferSize); - if (LogHeader == NULL) - { - DPRINT("ExAllocatePool() failed\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto ByeBye; - } - - /* Read log file header */ - FileOffset.QuadPart = 0ULL; - Status = ZwReadFile(LogHandle, - 0, - 0, - 0, - &IoStatusBlock, - LogHeader, - BufferSize, - &FileOffset, - 0); - if (!NT_SUCCESS(Status)) - { - DPRINT("ZwReadFile() failed (Status %lx)\n", Status); - goto ByeBye; - } - - /* Initialize bitmap */ - RtlInitializeBitMap(&BlockBitMap, - (PVOID)((ULONG_PTR)LogHeader + HV_BLOCK_SIZE + sizeof(ULONG)), - BitmapSize * 8); - - /* FIXME: Update dirty blocks */ - - - /* FIXME: Update hive header */ - - - Status = STATUS_SUCCESS; - } - - - /* Clean up the mess */ -ByeBye: - if (HiveHeader != NULL) - ExFreePool(HiveHeader); - - if (LogHeader != NULL) - ExFreePool(LogHeader); - - if (LogHandle != INVALID_HANDLE_VALUE) - ZwClose(LogHandle); - - ZwClose(HiveHandle); - - return(Status); -} -#endif - static NTSTATUS CmiInitNonVolatileRegistryHive (PEREGISTRY_HIVE RegistryHive, PWSTR Filename) @@ -477,18 +205,6 @@ CmiInitNonVolatileRegistryHive (PEREGISTRY_HIVE RegistryHive, wcscat(RegistryHive->LogFileName.Buffer, L".log"); -#ifdef HIVE_CHECK - /* Check and eventually fix a hive */ - Status = CmiCheckAndFixHive(RegistryHive); - if (!NT_SUCCESS(Status)) - { - RtlFreeUnicodeString(&RegistryHive->HiveFileName); - RtlFreeUnicodeString(&RegistryHive->LogFileName); - DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status); - return(Status); - } -#endif - InitializeObjectAttributes(&ObjectAttributes, &RegistryHive->HiveFileName, OBJ_CASE_INSENSITIVE, @@ -603,71 +319,143 @@ CmiInitNonVolatileRegistryHive (PEREGISTRY_HIVE RegistryHive, return STATUS_SUCCESS; } - -NTSTATUS -CmiCreateTempHive(PEREGISTRY_HIVE *RegistryHive) +ULONG +NTAPI +CmCheckRegistry(IN PEREGISTRY_HIVE RegistryHive, + IN ULONG Flags) { - PEREGISTRY_HIVE Hive; - NTSTATUS Status; - - *RegistryHive = NULL; - - Hive = ExAllocatePool (NonPagedPool, - sizeof(EREGISTRY_HIVE)); - if (Hive == NULL) - return STATUS_INSUFFICIENT_RESOURCES; - - RtlZeroMemory (Hive, - sizeof(EREGISTRY_HIVE)); - - DPRINT("Hive 0x%p\n", Hive); - - Status = HvInitialize(&Hive->Hive, HV_OPERATION_CREATE_HIVE, 0, 0, 0, 0, - CmpAllocate, CmpFree, - CmpFileRead, CmpFileWrite, CmpFileSetSize, - CmpFileFlush, NULL); - if (!NT_SUCCESS(Status)) - { - ExFreePool (Hive); - return Status; - } - - if (!CmCreateRootNode (&Hive->Hive, L"")) - { - HvFree (&Hive->Hive); - ExFreePool (Hive); - return STATUS_INSUFFICIENT_RESOURCES; - } - - Hive->Flags = HIVE_NO_FILE; - - /* Acquire hive list lock exclusively */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite (&CmiRegistryLock, TRUE); - - /* Add the new hive to the hive list */ - InsertTailList (&CmiHiveListHead, - &Hive->HiveList); - - /* Release hive list lock */ - ExReleaseResourceLite (&CmiRegistryLock); - KeLeaveCriticalRegion(); - - VERIFY_REGISTRY_HIVE (Hive); - - *RegistryHive = Hive; - - return STATUS_SUCCESS; + /* FIXME: HACK! */ + return 0; } - NTSTATUS -CmiCreateVolatileHive(PEREGISTRY_HIVE *RegistryHive) +NTAPI +CmpInitializeHive(OUT PEREGISTRY_HIVE *RegistryHive, + IN ULONG OperationType, + IN ULONG HiveFlags, + IN ULONG FileType, + IN PVOID HiveData OPTIONAL, + IN HANDLE Primary, + IN HANDLE Log, + IN HANDLE External, + IN PUNICODE_STRING FileName OPTIONAL, + IN ULONG CheckFlags) { - DPRINT ("CmiCreateVolatileHive() called\n"); - return CmiCreateTempHive(RegistryHive); -} + PEREGISTRY_HIVE Hive; + IO_STATUS_BLOCK IoStatusBlock; + FILE_FS_SIZE_INFORMATION FileSizeInformation; + NTSTATUS Status; + ULONG Cluster; + /* Assume failure */ + *RegistryHive = NULL; + + /* + * The following are invalid: + * An external hive that is also internal. + * A log hive that's not a primary hive too. + * A volatile hive that's linked to permanent storage. + * An in-memory initialization without hive data. + * A log hive that's not linked to a correct file type. + */ + if (((External) && ((Primary) || (Log))) || + ((Log) && !(Primary)) || + ((HiveFlags & HIVE_VOLATILE) && ((Primary) || (External) || (Log))) || + ((OperationType == HINIT_MEMORY) && (!HiveData)) || + ((Log) && (FileType != HFILE_TYPE_LOG))) + { + /* Fail the request */ + return STATUS_INVALID_PARAMETER; + } + + /* Check if this is a primary hive */ + if (Primary) + { + /* Get the cluster size */ + Status = ZwQueryVolumeInformationFile(Primary, + &IoStatusBlock, + &FileSizeInformation, + sizeof(FILE_FS_SIZE_INFORMATION), + FileFsSizeInformation); + if (!NT_SUCCESS(Status)) return Status; + + /* Make sure it's not larger then the block size */ + if (FileSizeInformation.BytesPerSector > HBLOCK_SIZE) + { + /* Fail */ + return STATUS_REGISTRY_IO_FAILED; + } + + /* Otherwise, calculate the cluster */ + Cluster = FileSizeInformation.BytesPerSector / HSECTOR_SIZE; + Cluster = max(1, Cluster); + } + else + { + /* Otherwise use cluster 1 */ + Cluster = 1; + } + + /* Allocate and clear the hive */ + Hive = ExAllocatePoolWithTag(NonPagedPool, sizeof(EREGISTRY_HIVE), TAG_CM); + if (!Hive) return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(Hive, sizeof(EREGISTRY_HIVE)); + + /* Initialize it */ + Status = HvInitialize(&Hive->Hive, + OperationType, + HiveFlags, + FileType, + (ULONG_PTR)HiveData, + Cluster, + CmpAllocate, + CmpFree, + CmpFileRead, + CmpFileWrite, + CmpFileSetSize, + CmpFileFlush, + FileName); + if (!NT_SUCCESS(Status)) + { + /* Clear allocations and fail */ + ExFreePool(Hive); + return Status; + } + + /* Set flag */ + Hive->Flags = HIVE_NO_FILE; + + /* Check if we should verify the registry */ + if ((OperationType == HINIT_FILE) || + (OperationType == HINIT_MEMORY) || + (OperationType == HINIT_MEMORY_INPLACE) || + (OperationType == HINIT_MAPFILE)) + { + /* Verify integrity */ + if (CmCheckRegistry(Hive, TRUE)) + { + /* Free all alocations */ + ExFreePool(Hive); + return STATUS_REGISTRY_CORRUPT; + } + } + + /* Acquire hive list lock exclusively */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE); + + /* Add the new hive to the hive list */ + InsertTailList(&CmiHiveListHead, &Hive->HiveList); + + /* Release hive list lock */ + ExReleaseResourceLite(&CmiRegistryLock); + KeLeaveCriticalRegion(); + + /* Return the hive and success */ + VERIFY_REGISTRY_HIVE(Hive); + *RegistryHive = Hive; + return STATUS_SUCCESS; +} NTSTATUS CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes, diff --git a/reactos/ntoskrnl/cm/registry.c b/reactos/ntoskrnl/cm/registry.c index 31fa65c8d66..d47a1f6b98f 100644 --- a/reactos/ntoskrnl/cm/registry.c +++ b/reactos/ntoskrnl/cm/registry.c @@ -19,6 +19,7 @@ #include #include "cm.h" +#include "..\config\cm.h" #if defined (ALLOC_PRAGMA) #pragma alloc_text(INIT, CmInitSystem1) @@ -78,6 +79,30 @@ NTSTATUS NTAPI CmpInitializeMachineDependentConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock); +NTSTATUS +NTAPI +CmpInitializeHive(PEREGISTRY_HIVE *RegistryHive, + ULONG OperationType, + ULONG HiveFlags, + ULONG FileType, + PVOID HiveData OPTIONAL, + HANDLE Primary, + HANDLE Log, + HANDLE External, + PUNICODE_STRING FileName OPTIONAL, + ULONG CheckFlags); + +USHORT +NTAPI +CmpCopyName(IN PHHIVE Hive, + IN PWCHAR Destination, + IN PUNICODE_STRING Source); + +USHORT +NTAPI +CmpNameSize(IN PHHIVE Hive, + IN PUNICODE_STRING Name); + static VOID STDCALL CmiHiveSyncDpcRoutine(PKDPC Dpc, PVOID DeferredContext, @@ -303,6 +328,61 @@ CmpCreateObjectTypes(VOID) return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmiKeyType); } +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), + HvStable); // FIXME: , HCELL_NIL); + if (*Index == HCELL_NIL) return FALSE; + + /* Set the cell index and get the data */ + Hive->HiveHeader->RootCell = *Index; + KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index); + if (!KeyCell) return FALSE; + + /* Setup the cell */ + KeyCell->Id = (USHORT)CM_KEY_NODE_SIGNATURE;; + KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE; + KeQuerySystemTime(&SystemTime); + KeyCell->LastWriteTime = SystemTime; + KeyCell->Parent = HCELL_NIL; + KeyCell->SubKeyCounts[HvStable] = 0; + KeyCell->SubKeyCounts[HvVolatile] = 0; + KeyCell->SubKeyLists[HvStable] = HCELL_NIL; + KeyCell->SubKeyLists[HvVolatile] = HCELL_NIL; + KeyCell->ValueList.Count = 0; + KeyCell->ValueList.List = HCELL_NIL; + KeyCell->SecurityKeyOffset = HCELL_NIL; + KeyCell->ClassNameOffset = HCELL_NIL; + KeyCell->ClassSize = 0; + + /* Copy the name (this will also set the length) */ + KeyCell->NameSize = CmpCopyName(Hive, (PWCHAR)KeyCell->Name, &KeyName); + + /* Check if the name was compressed */ + if (KeyCell->NameSize < KeyName.Length) + { + /* Set the flag */ + KeyCell->Flags |= KEY_COMP_NAME; + } + + /* Return success */ + HvReleaseCell(Hive, *Index); + return TRUE; +} + BOOLEAN NTAPI CmpCreateRegistryRoot(VOID) @@ -311,7 +391,16 @@ CmpCreateRegistryRoot(VOID) OBJECT_ATTRIBUTES ObjectAttributes; PKEY_OBJECT RootKey; HANDLE RootKeyHandle; + HCELL_INDEX RootIndex; NTSTATUS Status; + PAGED_CODE(); + + /* Setup the root node */ + if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex)) + { + /* We failed */ + return FALSE; + } /* Create '\Registry' key. */ RtlInitUnicodeString(&KeyName, REG_ROOT_KEY_NAME); @@ -333,8 +422,8 @@ CmpCreateRegistryRoot(VOID) /* Setup the root key */ RootKey->RegistryHive = CmiVolatileHive; - RootKey->KeyCellOffset = CmiVolatileHive->Hive.HiveHeader->RootCell; - RootKey->KeyCell = HvGetCell(&CmiVolatileHive->Hive, RootKey->KeyCellOffset); + RootKey->KeyCellOffset = RootIndex; + RootKey->KeyCell = HvGetCell(&CmiVolatileHive->Hive, RootIndex); RootKey->ParentKey = RootKey; RootKey->Flags = 0; RootKey->SubKeyCounts = 0; @@ -421,8 +510,17 @@ CmInitSystem1(VOID) KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0); } - /* Build volatile registry store */ - Status = CmiCreateVolatileHive(&CmiVolatileHive); + /* Build the master hive */ + Status = CmpInitializeHive(&CmiVolatileHive, + HINIT_CREATE, + HIVE_VOLATILE, + HFILE_TYPE_PRIMARY, + NULL, + NULL, + NULL, + NULL, + NULL, + 0); if (!NT_SUCCESS(Status)) { /* Bugcheck */ @@ -433,7 +531,7 @@ CmInitSystem1(VOID) if (!CmpCreateRegistryRoot()) { /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 4, 0, 0); + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0); } /* Create '\Registry\Machine' key. */ diff --git a/reactos/ntoskrnl/config/cm.h b/reactos/ntoskrnl/config/cm.h index f01d55acdfb..5be366caf07 100644 --- a/reactos/ntoskrnl/config/cm.h +++ b/reactos/ntoskrnl/config/cm.h @@ -84,7 +84,7 @@ // // Cell Masks // -#define HCELL_NIL 0 +#define HCELL_NIL -1 #define HCELL_CACHED 1 // @@ -158,6 +158,8 @@ #define CM_DELAYS_PER_PAGE \ PAGE_SIZE / sizeof(CM_DELAYED_CLOSE_ENTRY) +#ifndef __INCLUDE_CM_H + // // Key Hash // @@ -984,3 +986,5 @@ extern BOOLEAN ExpInTextModeSetup; // Inlined functions // #include "cm_x.h" + +#endif diff --git a/reactos/ntoskrnl/config/cmname.c b/reactos/ntoskrnl/config/cmname.c index 7affc6f6a83..81801c29261 100644 --- a/reactos/ntoskrnl/config/cmname.c +++ b/reactos/ntoskrnl/config/cmname.c @@ -17,6 +17,62 @@ /* FUNCTIONS *****************************************************************/ +USHORT +NTAPI +CmpCopyName(IN PHHIVE Hive, + IN PWCHAR Destination, + IN PUNICODE_STRING Source) +{ + ULONG i; + + /* Check for old hives */ + if (Hive->Version == 1) + { + /* Just copy the source directly */ + RtlCopyMemory(Destination, Source->Buffer, Source->Length); + return Source->Length; + } + + /* For new versions, check for compressed name */ + for (i = 0; i < (Source->Length / sizeof(WCHAR)); i++) + { + /* Check if the name is non compressed */ + if (Source->Buffer[i] > (UCHAR)-1) + { + /* Do the copy */ + RtlCopyMemory(Destination, Source->Buffer, Source->Length); + return Source->Length; + } + + /* Copy this character */ + Destination[i] = Source->Buffer[i]; + } + + /* Compressed name, return length */ + return Source->Length / sizeof(WCHAR); +} + +USHORT +NTAPI +CmpNameSize(IN PHHIVE Hive, + IN PUNICODE_STRING Name) +{ + ULONG i; + + /* For old hives, just retun the length */ + if (Hive->Version == 1) return Name->Length; + + /* For new versions, check for compressed name */ + for (i = 0; i < (Name->Length / sizeof(WCHAR)); i++) + { + /* Check if the name is non compressed */ + if (Name->Buffer[i] > (UCHAR)-1) return Name->Length; + } + + /* Compressed name, return length */ + return Name->Length / sizeof(WCHAR); +} + LONG NTAPI CmpCompareCompressedName(IN PUNICODE_STRING SearchName,