X-Git-Url: http://git.jankratochvil.net/?a=blobdiff_plain;f=ntoskrnl%2Fcm%2Fregfile.c;h=392b4c424631ecc38aaf8d13b56dc4ea7b38f3e6;hb=a3df8bf1429570e0bd6c6428f6ed80073578cf4b;hp=a03290afd979c387a9154a6368e6b81b47d37299;hpb=7c0db166f81fbe8c8b913d7f26048e337d383605;p=reactos.git diff --git a/ntoskrnl/cm/regfile.c b/ntoskrnl/cm/regfile.c index a03290a..392b4c4 100644 --- a/ntoskrnl/cm/regfile.c +++ b/ntoskrnl/cm/regfile.c @@ -7,13 +7,12 @@ */ #include -#include #include #include #include #include -#include #include +#include #include #define NDEBUG @@ -47,8 +46,8 @@ CmiCreateDefaultHiveHeader(PHIVE_HEADER Header) Header->BlockId = REG_HIVE_ID; Header->UpdateCounter1 = 0; Header->UpdateCounter2 = 0; - Header->DateModified.dwLowDateTime = 0; - Header->DateModified.dwHighDateTime = 0; + Header->DateModified.u.LowPart = 0; + Header->DateModified.u.HighPart = 0; Header->Unused3 = 1; Header->Unused4 = 3; Header->Unused5 = 0; @@ -67,8 +66,8 @@ CmiCreateDefaultBinCell(PHBIN BinCell) assert(BinCell); RtlZeroMemory(BinCell, sizeof(HBIN)); BinCell->BlockId = REG_BIN_ID; - BinCell->DateModified.dwLowDateTime = 0; - BinCell->DateModified.dwHighDateTime = 0; + BinCell->DateModified.u.LowPart = 0; + BinCell->DateModified.u.HighPart = 0; BinCell->BlockSize = REG_BLOCK_SIZE; } @@ -80,8 +79,8 @@ CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell) RtlZeroMemory(RootKeyCell, sizeof(KEY_CELL)); RootKeyCell->CellSize = -sizeof(KEY_CELL); RootKeyCell->Id = REG_KEY_CELL_ID; - RootKeyCell->Type = REG_ROOT_KEY_CELL_TYPE; - NtQuerySystemTime((PTIME) &RootKeyCell->LastWriteTime); + RootKeyCell->Flags = REG_KEY_ROOT_CELL | REG_KEY_NAME_PACKED; + NtQuerySystemTime(&RootKeyCell->LastWriteTime); RootKeyCell->ParentKeyOffset = 0; RootKeyCell->NumberOfSubKeys = 0; RootKeyCell->HashTableOffset = -1; @@ -147,13 +146,7 @@ CmiVerifyKeyCell(PKEY_CELL KeyCell) assert(KeyCell->Id == REG_KEY_CELL_ID); } - if ((KeyCell->Type != REG_KEY_CELL_TYPE) - && (KeyCell->Type != REG_ROOT_KEY_CELL_TYPE)) - { - DbgPrint("Type is %.08x (should be %.08x or %.08x)\n", - KeyCell->Type, REG_KEY_CELL_TYPE, REG_ROOT_KEY_CELL_TYPE); - assert(FALSE); - } + //KeyCell->Flags; //KeyCell->LastWriteTime; @@ -207,11 +200,11 @@ CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell) CmiVerifyKeyCell(RootKeyCell); - if (RootKeyCell->Type != REG_ROOT_KEY_CELL_TYPE) + if (!(RootKeyCell->Flags & REG_KEY_ROOT_CELL)) { - DbgPrint("Type is %.08x (should be %.08x)\n", - RootKeyCell->Type, REG_ROOT_KEY_CELL_TYPE); - assert(RootKeyCell->Type == REG_ROOT_KEY_CELL_TYPE); + DbgPrint("Flags is %.08x (should be %.08x)\n", + RootKeyCell->Flags, REG_KEY_ROOT_CELL | REG_KEY_NAME_PACKED); + assert(!(RootKeyCell->Flags & (REG_KEY_ROOT_CELL | REG_KEY_NAME_PACKED))); } } @@ -364,64 +357,6 @@ CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive) } -#if 0 -static NTSTATUS -CmiPopulateHive(HANDLE FileHandle) -{ - IO_STATUS_BLOCK IoStatusBlock; - LARGE_INTEGER FileOffset; - PCELL_HEADER FreeCell; - NTSTATUS Status; - PHBIN BinCell; - PCHAR tBuf; - ULONG i; - - tBuf = (PCHAR) ExAllocatePool(NonPagedPool, REG_BLOCK_SIZE); - if (tBuf == NULL) - return STATUS_INSUFFICIENT_RESOURCES; - - BinCell = (PHBIN) tBuf; - FreeCell = (PCELL_HEADER) (tBuf + REG_HBIN_DATA_OFFSET); - - CmiCreateDefaultBinCell(BinCell); - - // The whole block is free - FreeCell->CellSize = REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET; - - // Add free blocks so we don't need to expand - // the file for a while - for (i = 1; i < 50; i++) - { - // Block offset of this bin - BinCell->BlockOffset = i * REG_BLOCK_SIZE; - - FileOffset.u.HighPart = 0; - FileOffset.u.LowPart = (i + 1) * REG_BLOCK_SIZE; - - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - tBuf, - REG_BLOCK_SIZE, - &FileOffset, - NULL); - assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status)); - if (!NT_SUCCESS(Status)) - { - ExFreePool(tBuf); - return Status; - } - } - - ExFreePool(tBuf); - - return Status; -} -#endif - - static NTSTATUS CmiCreateNewRegFile(HANDLE FileHandle) { @@ -474,13 +409,6 @@ CmiCreateNewRegFile(HANDLE FileHandle) return(Status); } -#if 0 - if (NT_SUCCESS(Status)) - { - CmiPopulateHive(FileHandle); - } -#endif - Status = NtFlushBuffersFile(FileHandle, &IoStatusBlock); @@ -599,7 +527,7 @@ CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive) { /* 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); + KEBUGCHECK(CONFIG_LIST_FAILED); } Status = STATUS_SUCCESS; @@ -642,7 +570,7 @@ CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive) HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2) { DPRINT("Hive file and log file are inconsistent!\n"); - KeBugCheck(CONFIG_LIST_FAILED); + KEBUGCHECK(CONFIG_LIST_FAILED); } /* Log file damaged but hive is okay */ @@ -743,27 +671,196 @@ ByeBye: #endif +NTSTATUS +CmiImportHiveBins(PREGISTRY_HIVE Hive, + PUCHAR ChunkPtr) +{ + BLOCK_OFFSET BlockOffset; + ULONG BlockIndex; + PHBIN Bin; + ULONG j; + + BlockIndex = 0; + BlockOffset = 0; + while (BlockIndex < Hive->BlockListSize) + { + Bin = (PHBIN)((ULONG_PTR)ChunkPtr + BlockOffset); + + if (Bin->BlockId != REG_BIN_ID) + { + DPRINT1 ("Bad BlockId %x, offset %x\n", Bin->BlockId, BlockOffset); + return STATUS_REGISTRY_CORRUPT; + } + + assertmsg((Bin->BlockSize % 4096) == 0, + ("BlockSize (0x%.08x) must be multiple of 4K\n", + Bin->BlockSize)); + + /* Allocate the hive block */ + Hive->BlockList[BlockIndex] = ExAllocatePool (PagedPool, + Bin->BlockSize); + if (Hive->BlockList[BlockIndex] == NULL) + { + DPRINT1 ("ExAllocatePool() failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Import the Bin */ + RtlCopyMemory (Hive->BlockList[BlockIndex], + Bin, + Bin->BlockSize); + + if (Bin->BlockSize > 4096) + { + for (j = 1; j < Bin->BlockSize / 4096; j++) + { + Hive->BlockList[BlockIndex + j] = Hive->BlockList[BlockIndex]; + } + } + + BlockIndex += Bin->BlockSize / 4096; + BlockOffset += Bin->BlockSize; + } + + return STATUS_SUCCESS; +} + + +VOID +CmiFreeHiveBins (PREGISTRY_HIVE Hive) +{ + ULONG i; + PHBIN Bin; + + Bin = NULL; + for (i = 0; i < Hive->BlockListSize; i++) + { + if (Hive->BlockList[i] == NULL) + continue; + + if (Hive->BlockList[i] != Bin) + { + Bin = Hive->BlockList[i]; + ExFreePool (Hive->BlockList[i]); + } + Hive->BlockList[i] = NULL; + } +} + + +NTSTATUS +CmiCreateHiveFreeCellList(PREGISTRY_HIVE Hive) +{ + BLOCK_OFFSET BlockOffset; + PCELL_HEADER FreeBlock; + ULONG BlockIndex; + ULONG FreeOffset; + PHBIN Bin; + NTSTATUS Status; + + /* Initialize the free cell list */ + Hive->FreeListSize = 0; + Hive->FreeListMax = 0; + Hive->FreeList = NULL; + Hive->FreeListOffset = NULL; + + BlockOffset = 0; + BlockIndex = 0; + while (BlockIndex < Hive->BlockListSize) + { + Bin = Hive->BlockList[BlockIndex]; + + /* Search free blocks and add to list */ + FreeOffset = REG_HBIN_DATA_OFFSET; + while (FreeOffset < Bin->BlockSize) + { + FreeBlock = (PCELL_HEADER) ((ULONG_PTR) Bin + FreeOffset); + if (FreeBlock->CellSize > 0) + { + Status = CmiAddFree(Hive, + FreeBlock, + Bin->BlockOffset + FreeOffset, + FALSE); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + FreeOffset += FreeBlock->CellSize; + } + else + { + FreeOffset -= FreeBlock->CellSize; + } + } + + BlockIndex += Bin->BlockSize / 4096; + BlockOffset += Bin->BlockSize; + } + + return STATUS_SUCCESS; +} + + +VOID +CmiFreeHiveFreeCellList(PREGISTRY_HIVE Hive) +{ + ExFreePool (Hive->FreeList); + ExFreePool (Hive->FreeListOffset); + + Hive->FreeListSize = 0; + Hive->FreeListMax = 0; + Hive->FreeList = NULL; + Hive->FreeListOffset = NULL; +} + + +NTSTATUS +CmiCreateHiveBitmap(PREGISTRY_HIVE Hive) +{ + ULONG BitmapSize; + + /* Calculate bitmap size in bytes (always a multiple of 32 bits) */ + BitmapSize = ROUND_UP(Hive->BlockListSize, sizeof(ULONG) * 8) / 8; + DPRINT("Hive->BlockListSize: %lu\n", Hive->BlockListSize); + DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8); + + /* Allocate bitmap */ + Hive->BitmapBuffer = (PULONG)ExAllocatePool(PagedPool, + BitmapSize); + if (Hive->BitmapBuffer == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlInitializeBitMap(&Hive->DirtyBitMap, + Hive->BitmapBuffer, + BitmapSize * 8); + + /* Initialize bitmap */ + RtlClearAllBits(&Hive->DirtyBitMap); + Hive->HiveDirty = FALSE; + + return STATUS_SUCCESS; +} + + static NTSTATUS -CmiInitNonVolatileRegistryHive(PREGISTRY_HIVE RegistryHive, - PWSTR Filename, - BOOLEAN CreateNew) +CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive, + PWSTR Filename) { OBJECT_ATTRIBUTES ObjectAttributes; - FILE_STANDARD_INFORMATION fsi; - PCELL_HEADER FreeBlock; - LARGE_INTEGER FileOffset; - BLOCK_OFFSET BlockOffset; ULONG CreateDisposition; IO_STATUS_BLOCK IoSB; HANDLE FileHandle; - ULONG FreeOffset; + HANDLE SectionHandle; + PUCHAR ViewBase; + ULONG ViewSize; NTSTATUS Status; - PHBIN tmpBin; - ULONG i, j; - ULONG BitmapSize; - DPRINT("CmiInitNonVolatileRegistryHive(%p, %S, %d) called\n", - RegistryHive, Filename, CreateNew); + DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) called\n", + RegistryHive, Filename); /* Duplicate Filename */ Status = RtlCreateUnicodeString(&RegistryHive->HiveFileName, @@ -808,21 +905,7 @@ CmiInitNonVolatileRegistryHive(PREGISTRY_HIVE RegistryHive, NULL, NULL); - /* - * Note: - * This is a workaround to prevent a BSOD because of missing registry hives. - * The workaround is only useful for developers. An implementation for the - * ordinary user must bail out on missing registry hives because they are - * essential to booting and configuring the OS. - */ -#if 0 - if (CreateNew == TRUE) - CreateDisposition = FILE_OPEN_IF; - else - CreateDisposition = FILE_OPEN; -#endif CreateDisposition = FILE_OPEN_IF; - Status = NtCreateFile(&FileHandle, FILE_ALL_ACCESS, &ObjectAttributes, @@ -842,10 +925,6 @@ CmiInitNonVolatileRegistryHive(PREGISTRY_HIVE RegistryHive, return(Status); } - /* Note: Another workaround! See the note above! */ -#if 0 - if ((CreateNew) && (IoSB.Information == FILE_CREATED)) -#endif if (IoSB.Information != FILE_OPENED) { Status = CmiCreateNewRegFile(FileHandle); @@ -859,289 +938,415 @@ CmiInitNonVolatileRegistryHive(PREGISTRY_HIVE RegistryHive, } } - /* Read hive header */ - FileOffset.u.HighPart = 0; - FileOffset.u.LowPart = 0; - DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle, sizeof(HIVE_HEADER), RegistryHive->HiveHeader); - Status = NtReadFile(FileHandle, - 0, - 0, - 0, - &IoSB, - RegistryHive->HiveHeader, - sizeof(HIVE_HEADER), - &FileOffset, - 0); - assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status)); + /* Create the hive section */ + Status = NtCreateSection(&SectionHandle, + SECTION_ALL_ACCESS, + NULL, + NULL, + PAGE_READWRITE, + SEC_COMMIT, + FileHandle); + NtClose(FileHandle); if (!NT_SUCCESS(Status)) { - DPRINT("NtReadFile() failed (Status %lx)\n", Status); - NtClose(FileHandle); + DPRINT1("NtCreateSection() failed (Status %lx)\n", Status); RtlFreeUnicodeString(&RegistryHive->HiveFileName); RtlFreeUnicodeString(&RegistryHive->LogFileName); - return Status; + return(Status); } - /* Read update counter */ - RegistryHive->UpdateCounter = RegistryHive->HiveHeader->UpdateCounter1; - - Status = NtQueryInformationFile(FileHandle, - &IoSB, - &fsi, - sizeof(fsi), - FileStandardInformation); - assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status)); - if (!NT_SUCCESS(Status) || fsi.EndOfFile.u.LowPart == 0) + /* Map the hive file */ + ViewBase = NULL; + ViewSize = 0; + Status = NtMapViewOfSection(SectionHandle, + NtCurrentProcess(), + (PVOID*)&ViewBase, + 0, + ViewSize, + NULL, + &ViewSize, + 0, + MEM_COMMIT, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) { - DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status); - NtClose(FileHandle); + DPRINT1("MmMapViewInSystemSpace() failed (Status %lx)\n", Status); + NtClose(SectionHandle); RtlFreeUnicodeString(&RegistryHive->HiveFileName); RtlFreeUnicodeString(&RegistryHive->LogFileName); - return Status; + return(Status); } + DPRINT("ViewBase %p ViewSize %lx\n", ViewBase, ViewSize); - RegistryHive->FileSize = fsi.EndOfFile.u.LowPart; + /* Copy hive header and initalize hive */ + RtlCopyMemory (RegistryHive->HiveHeader, + ViewBase, + sizeof(HIVE_HEADER)); + RegistryHive->FileSize = ViewSize; RegistryHive->BlockListSize = (RegistryHive->FileSize / 4096) - 1; + RegistryHive->UpdateCounter = RegistryHive->HiveHeader->UpdateCounter1; - DPRINT("Space needed for block list describing hive: 0x%x\n", - sizeof(PHBIN *) * RegistryHive->BlockListSize); - + /* Allocate hive block list */ RegistryHive->BlockList = ExAllocatePool(NonPagedPool, sizeof(PHBIN *) * RegistryHive->BlockListSize); - if (RegistryHive->BlockList == NULL) { - ExFreePool(RegistryHive->BlockList); - NtClose(FileHandle); + DPRINT1("Failed to allocate the hive block list\n"); + NtUnmapViewOfSection(NtCurrentProcess(), + ViewBase); + NtClose(SectionHandle); RtlFreeUnicodeString(&RegistryHive->HiveFileName); RtlFreeUnicodeString(&RegistryHive->LogFileName); - DPRINT("CmiInitNonVolatileRegistryHive() - Failed 6.\n"); return STATUS_INSUFFICIENT_RESOURCES; } - RegistryHive->BlockList[0] = ExAllocatePool(PagedPool, - RegistryHive->FileSize - 4096); - if (RegistryHive->BlockList[0] == NULL) + /* Import the hive bins */ + Status = CmiImportHiveBins (RegistryHive, + ViewBase + 4096); + if (!NT_SUCCESS(Status)) { ExFreePool(RegistryHive->BlockList); - NtClose(FileHandle); + NtUnmapViewOfSection(NtCurrentProcess(), + ViewBase); + NtClose(SectionHandle); RtlFreeUnicodeString(&RegistryHive->HiveFileName); RtlFreeUnicodeString(&RegistryHive->LogFileName); - DPRINT("CmiInitNonVolatileRegistryHive() - Failed 8.\n"); - return STATUS_INSUFFICIENT_RESOURCES; + return Status; } - FileOffset.u.HighPart = 0; - FileOffset.u.LowPart = 4096; - - DPRINT(" Attempting to NtReadFile(%d) for %d bytes into %p\n", - FileHandle, RegistryHive->FileSize - 4096, (PVOID)RegistryHive->BlockList[0]); - Status = NtReadFile(FileHandle, - 0, - 0, - 0, - &IoSB, - (PVOID) RegistryHive->BlockList[0], - RegistryHive->FileSize - 4096, - &FileOffset, - 0); - - assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status)); - - NtClose(FileHandle); + /* Unmap and dereference the hive section */ + NtUnmapViewOfSection(NtCurrentProcess(), + ViewBase); + NtClose(SectionHandle); - RegistryHive->FreeListSize = 0; - RegistryHive->FreeListMax = 0; - RegistryHive->FreeList = NULL; + /* Initialize the free cell list */ + Status = CmiCreateHiveFreeCellList (RegistryHive); + if (!NT_SUCCESS(Status)) + { + CmiFreeHiveBins(RegistryHive); + ExFreePool(RegistryHive->BlockList); + RtlFreeUnicodeString(&RegistryHive->HiveFileName); + RtlFreeUnicodeString(&RegistryHive->LogFileName); + return Status; + } - BlockOffset = 0; - for (i = 0; i < RegistryHive->BlockListSize; i++) + /* Create the block bitmap */ + Status = CmiCreateHiveBitmap (RegistryHive); + if (!NT_SUCCESS(Status)) { - RegistryHive->BlockList[i] = (PHBIN) (((ULONG_PTR) RegistryHive->BlockList[0]) + BlockOffset); - tmpBin = (PHBIN) (((ULONG_PTR) RegistryHive->BlockList[i])); - if (tmpBin->BlockId != REG_BIN_ID) - { - DPRINT("Bad BlockId %x, offset %x\n", tmpBin->BlockId, BlockOffset); - //KeBugCheck(0); - return STATUS_INSUFFICIENT_RESOURCES; - } + CmiFreeHiveFreeCellList(RegistryHive); + CmiFreeHiveBins(RegistryHive); + ExFreePool(RegistryHive->BlockList); + RtlFreeUnicodeString(&RegistryHive->HiveFileName); + RtlFreeUnicodeString(&RegistryHive->LogFileName); + return Status; + } - assertmsg((tmpBin->BlockSize % 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin->BlockSize)); + DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n", + RegistryHive, Filename); - if (tmpBin->BlockSize > 4096) - { - for (j = 1; j < tmpBin->BlockSize / 4096; j++) - { - RegistryHive->BlockList[i + j] = RegistryHive->BlockList[i]; - } - i = i + j - 1; - } + return(STATUS_SUCCESS); +} - /* Search free blocks and add to list */ - FreeOffset = REG_HBIN_DATA_OFFSET; - while (FreeOffset < tmpBin->BlockSize) - { - FreeBlock = (PCELL_HEADER) ((ULONG_PTR) RegistryHive->BlockList[i] + FreeOffset); - if (FreeBlock->CellSize > 0) - { - Status = CmiAddFree(RegistryHive, - FreeBlock, - RegistryHive->BlockList[i]->BlockOffset + FreeOffset, - FALSE); - if (!NT_SUCCESS(Status)) - { - /* FIXME: */ - assert(FALSE); - } +NTSTATUS +CmiCreateVolatileHive(PREGISTRY_HIVE *RegistryHive) +{ + PKEY_CELL RootKeyCell; + PREGISTRY_HIVE Hive; - FreeOffset += FreeBlock->CellSize; - } - else - { - FreeOffset -= FreeBlock->CellSize; - } - } - BlockOffset += tmpBin->BlockSize; - } + *RegistryHive = NULL; - /* - * Create block bitmap and clear all bits - */ - /* Calculate bitmap size in bytes (always a multiple of 32 bits) */ - BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8; - DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize); - DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8); + Hive = ExAllocatePool (NonPagedPool, + sizeof(REGISTRY_HIVE)); + if (Hive == NULL) + return STATUS_INSUFFICIENT_RESOURCES; - /* Allocate bitmap */ - RegistryHive->BitmapBuffer = (PULONG)ExAllocatePool(PagedPool, - BitmapSize); - RtlInitializeBitMap(&RegistryHive->DirtyBitMap, - RegistryHive->BitmapBuffer, - BitmapSize * 8); + RtlZeroMemory (Hive, + sizeof(REGISTRY_HIVE)); - /* Initialize bitmap */ - RtlClearAllBits(&RegistryHive->DirtyBitMap); - RegistryHive->HiveDirty = FALSE; + DPRINT("Hive %x\n", Hive); - DPRINT("CmiInitNonVolatileRegistryHive(%p, %S, %d) - Finished.\n", - RegistryHive, Filename, CreateNew); + Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool (NonPagedPool, + sizeof(HIVE_HEADER)); + if (Hive->HiveHeader == NULL) + { + ExFreePool (Hive); + return STATUS_INSUFFICIENT_RESOURCES; + } - return(STATUS_SUCCESS); -} + Hive->Flags = (HIVE_NO_FILE | HIVE_POINTER); + CmiCreateDefaultHiveHeader (Hive->HiveHeader); -static NTSTATUS -CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive) -{ - PKEY_CELL RootKeyCell; + RootKeyCell = (PKEY_CELL)ExAllocatePool (NonPagedPool, + sizeof(KEY_CELL)); + if (RootKeyCell == NULL) + { + ExFreePool(Hive->HiveHeader); + ExFreePool(Hive); + return STATUS_INSUFFICIENT_RESOURCES; + } - RegistryHive->Flags |= (HIVE_VOLATILE | HIVE_POINTER); + CmiCreateDefaultRootKeyCell (RootKeyCell); + Hive->HiveHeader->RootKeyCell = (BLOCK_OFFSET)RootKeyCell; - CmiCreateDefaultHiveHeader(RegistryHive->HiveHeader); + ExInitializeResourceLite (&Hive->HiveResource); - RootKeyCell = (PKEY_CELL) ExAllocatePool(NonPagedPool, sizeof(KEY_CELL)); + /* Acquire hive list lock exclusively */ + ExAcquireResourceExclusiveLite (&CmiHiveListLock, + TRUE); - if (RootKeyCell == NULL) - return STATUS_INSUFFICIENT_RESOURCES; + /* Add the new hive to the hive list */ + InsertTailList (&CmiHiveListHead, + &Hive->HiveList); - CmiCreateDefaultRootKeyCell(RootKeyCell); + /* Release hive list lock */ + ExReleaseResourceLite (&CmiHiveListLock); - RegistryHive->HiveHeader->RootKeyCell = (BLOCK_OFFSET) RootKeyCell; + VERIFY_REGISTRY_HIVE (Hive); + + *RegistryHive = Hive; return STATUS_SUCCESS; } NTSTATUS -CmiCreateRegistryHive(PWSTR Filename, - PREGISTRY_HIVE *RegistryHive, - BOOLEAN CreateNew) +CmiCreateTempHive(PREGISTRY_HIVE *RegistryHive) { + PHBIN BinCell; + PCELL_HEADER FreeCell; PREGISTRY_HIVE Hive; NTSTATUS Status; - DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename); + DPRINT ("CmiCreateTempHive() called\n"); *RegistryHive = NULL; - Hive = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_HIVE)); + Hive = ExAllocatePool (NonPagedPool, + sizeof(REGISTRY_HIVE)); if (Hive == NULL) - return(STATUS_INSUFFICIENT_RESOURCES); - - DPRINT("Hive %x\n", Hive); - - RtlZeroMemory(Hive, sizeof(REGISTRY_HIVE)); + { + DPRINT1 ("Failed to allocate registry hive block\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory (Hive, + sizeof(REGISTRY_HIVE)); - Hive->HiveHeader = (PHIVE_HEADER) - ExAllocatePool(NonPagedPool, sizeof(HIVE_HEADER)); + DPRINT ("Hive %x\n", Hive); + Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool (NonPagedPool, + REG_BLOCK_SIZE); if (Hive->HiveHeader == NULL) { - ExFreePool(Hive); - return(STATUS_INSUFFICIENT_RESOURCES); + DPRINT1 ("Failed to allocate hive header block\n"); + ExFreePool (Hive); + return STATUS_INSUFFICIENT_RESOURCES; } + RtlZeroMemory (Hive->HiveHeader, + REG_BLOCK_SIZE); + + DPRINT ("HiveHeader %x\n", Hive->HiveHeader); + + Hive->Flags = HIVE_NO_FILE; - if (Filename != NULL) + RtlInitUnicodeString (&Hive->HiveFileName, + NULL); + RtlInitUnicodeString (&Hive->LogFileName, + NULL); + + CmiCreateDefaultHiveHeader (Hive->HiveHeader); + + /* Allocate hive block list */ + Hive->BlockList = ExAllocatePool (NonPagedPool, + sizeof(PHBIN *)); + if (Hive->BlockList == NULL) { - Status = CmiInitNonVolatileRegistryHive(Hive, Filename, CreateNew); + DPRINT1 ("Failed to allocate hive block list\n"); + ExFreePool(Hive->HiveHeader); + ExFreePool(Hive); + return STATUS_INSUFFICIENT_RESOURCES; } - else + + /* Allocate first Bin */ + Hive->BlockList[0] = ExAllocatePool (NonPagedPool, + REG_BLOCK_SIZE); + if (Hive->BlockList[0] == NULL) { - Status = CmiInitVolatileRegistryHive(Hive); + DPRINT1 ("Failed to allocate first bin\n"); + ExFreePool(Hive->BlockList); + ExFreePool(Hive->HiveHeader); + ExFreePool(Hive); + return STATUS_INSUFFICIENT_RESOURCES; } - if (!NT_SUCCESS(Status)) + Hive->FileSize = 2* REG_BLOCK_SIZE; + Hive->BlockListSize = 1; + Hive->UpdateCounter = Hive->HiveHeader->UpdateCounter1; + + + BinCell = (PHBIN)Hive->BlockList[0]; + FreeCell = (PCELL_HEADER)((ULONG_PTR)BinCell + REG_HBIN_DATA_OFFSET); + + CmiCreateDefaultBinCell (BinCell); + + /* First block */ + BinCell->BlockOffset = 0; + + /* Offset to root key block */ + Hive->HiveHeader->RootKeyCell = -1; + + /* The rest of the block is free */ + FreeCell->CellSize = REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET; + + /* Create the free cell list */ + Status = CmiCreateHiveFreeCellList (Hive); + if (Hive->BlockList[0] == NULL) { + DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status); + ExFreePool(Hive->BlockList[0]); + ExFreePool(Hive->BlockList); ExFreePool(Hive->HiveHeader); ExFreePool(Hive); - return(Status); + return Status; } - ExInitializeResourceLite(&Hive->HiveResource); + + ExInitializeResourceLite (&Hive->HiveResource); /* Acquire hive list lock exclusively */ - ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE); + ExAcquireResourceExclusiveLite (&CmiHiveListLock, + TRUE); /* Add the new hive to the hive list */ - InsertTailList(&CmiHiveListHead, &Hive->HiveList); + InsertTailList (&CmiHiveListHead, + &Hive->HiveList); /* Release hive list lock */ - ExReleaseResourceLite(&CmiHiveListLock); + ExReleaseResourceLite (&CmiHiveListLock); - VERIFY_REGISTRY_HIVE(Hive); + VERIFY_REGISTRY_HIVE (Hive); *RegistryHive = Hive; - DPRINT("CmiCreateRegistryHive(Filename %S) - Finished.\n", Filename); + return STATUS_SUCCESS; +} - return(STATUS_SUCCESS); + +NTSTATUS +CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes, + IN PUNICODE_STRING FileName, + IN ULONG Flags) +{ + PREGISTRY_HIVE Hive; + NTSTATUS Status; + + DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName); + + if (Flags & ~REG_NO_LAZY_FLUSH) + return STATUS_INVALID_PARAMETER; + + Hive = ExAllocatePool (NonPagedPool, + sizeof(REGISTRY_HIVE)); + if (Hive == NULL) + { + DPRINT1 ("Failed to allocate hive header.\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory (Hive, + sizeof(REGISTRY_HIVE)); + + DPRINT ("Hive %x\n", Hive); + Hive->Flags = (Flags & REG_NO_LAZY_FLUSH) ? HIVE_NO_SYNCH : 0; + + Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool(NonPagedPool, + sizeof(HIVE_HEADER)); + if (Hive->HiveHeader == NULL) + { + DPRINT1 ("Failed to allocate hive header.\n"); + ExFreePool (Hive); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = CmiInitNonVolatileRegistryHive (Hive, + FileName->Buffer); + if (!NT_SUCCESS (Status)) + { + DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status); + ExFreePool (Hive->HiveHeader); + ExFreePool (Hive); + return Status; + } + + ExInitializeResourceLite (&Hive->HiveResource); + + /* Add the new hive to the hive list */ + ExAcquireResourceExclusiveLite (&CmiHiveListLock, + TRUE); + InsertTailList (&CmiHiveListHead, + &Hive->HiveList); + ExReleaseResourceLite (&CmiHiveListLock); + + + VERIFY_REGISTRY_HIVE(Hive); + + + Status = CmiConnectHive (KeyObjectAttributes, + Hive); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status); +// CmiRemoveRegistryHive (Hive); + } + + DPRINT ("CmiLoadHive() done\n"); + + return Status; } NTSTATUS CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive) { + if (RegistryHive->Flags & HIVE_POINTER) + return STATUS_UNSUCCESSFUL; + /* Acquire hive list lock exclusively */ - ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE); + ExAcquireResourceExclusiveLite (&CmiHiveListLock, + TRUE); /* Remove hive from hive list */ - RemoveEntryList(&RegistryHive->HiveList); + RemoveEntryList (&RegistryHive->HiveList); /* Release hive list lock */ - ExReleaseResourceLite(&CmiHiveListLock); + ExReleaseResourceLite (&CmiHiveListLock); + + /* Release file names */ + RtlFreeUnicodeString (&RegistryHive->HiveFileName); + RtlFreeUnicodeString (&RegistryHive->LogFileName); + /* Release hive bitmap */ + ExFreePool (RegistryHive->BitmapBuffer); - /* FIXME: Remove attached keys and values */ + /* Release free cell list */ + ExFreePool (RegistryHive->FreeList); + ExFreePool (RegistryHive->FreeListOffset); + /* Release hive resource */ + ExDeleteResource (&RegistryHive->HiveResource); + + /* Release bins and bin list */ + CmiFreeHiveBins (RegistryHive); + ExFreePool (RegistryHive->BlockList); /* Release hive header */ - ExFreePool(RegistryHive->HiveHeader); + ExFreePool (RegistryHive->HiveHeader); /* Release hive */ - ExFreePool(RegistryHive); + ExFreePool (RegistryHive); - return(STATUS_SUCCESS); + return STATUS_SUCCESS; } @@ -1737,7 +1942,7 @@ CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive) &RegistryHive->LogFileName); /* Update hive header modification time */ - NtQuerySystemTime((PTIME)&RegistryHive->HiveHeader->DateModified); + NtQuerySystemTime(&RegistryHive->HiveHeader->DateModified); /* Start log update */ Status = CmiStartLogUpdate(RegistryHive); @@ -1793,40 +1998,78 @@ CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive) ULONG -CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive, - PKEY_CELL KeyCell) +CmiGetMaxNameLength(PKEY_OBJECT KeyObject) { PHASH_TABLE_CELL HashBlock; + PKEY_OBJECT CurKey; PKEY_CELL CurSubKeyCell; + PKEY_CELL KeyCell; ULONG MaxName; + ULONG NameSize; ULONG i; + VERIFY_KEY_OBJECT(KeyObject); + + KeyCell = KeyObject->KeyCell; VERIFY_KEY_CELL(KeyCell); MaxName = 0; - HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL); + HashBlock = CmiGetBlock(KeyObject->RegistryHive, + KeyCell->HashTableOffset, + NULL); if (HashBlock == NULL) { DPRINT("CmiGetBlock() failed\n"); - return 0; - } - - for (i = 0; i < HashBlock->HashTableSize; i++) + } + else { - if (HashBlock->Table[i].KeyOffset != 0) - { - CurSubKeyCell = CmiGetBlock(RegistryHive, - HashBlock->Table[i].KeyOffset, - NULL); - if (CurSubKeyCell == NULL) + for (i = 0; i < HashBlock->HashTableSize; i++) + { + if (HashBlock->Table[i].KeyOffset != 0) { - DPRINT("CmiGetBlock() failed\n"); - return 0; + CurSubKeyCell = CmiGetBlock(KeyObject->RegistryHive, + HashBlock->Table[i].KeyOffset, + NULL); + if (CurSubKeyCell == NULL) + { + DPRINT("CmiGetBlock() failed\n"); + continue; + } + NameSize = CurSubKeyCell->NameSize; + if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED) + { + NameSize *= sizeof(WCHAR); + } + if (MaxName < NameSize) + { + MaxName = NameSize; + } } - - if (MaxName < CurSubKeyCell->NameSize) + } + } + if (KeyObject->RegistryHive != CmiVolatileHive) + { + DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys); + for (i = 0; i < KeyObject->NumberOfSubKeys; i++) + { + CurKey = KeyObject->SubKeys[i]; + if (CurKey->RegistryHive == CmiVolatileHive) { - MaxName = CurSubKeyCell->NameSize; + CurSubKeyCell = CurKey->KeyCell; + if (CurSubKeyCell == NULL) + { + DPRINT("CmiGetBlock() failed\n"); + continue; + } + NameSize = CurSubKeyCell->NameSize; + if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED) + { + NameSize *= sizeof(WCHAR); + } + if (MaxName < NameSize) + { + MaxName = NameSize; + } } } } @@ -1836,40 +2079,68 @@ CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive, ULONG -CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive, - PKEY_CELL KeyCell) +CmiGetMaxClassLength(PKEY_OBJECT KeyObject) { PHASH_TABLE_CELL HashBlock; + PKEY_OBJECT CurKey; PKEY_CELL CurSubKeyCell; + PKEY_CELL KeyCell; ULONG MaxClass; ULONG i; + VERIFY_KEY_OBJECT(KeyObject); + + KeyCell = KeyObject->KeyCell; VERIFY_KEY_CELL(KeyCell); MaxClass = 0; - HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL); + HashBlock = CmiGetBlock(KeyObject->RegistryHive, + KeyCell->HashTableOffset, + NULL); if (HashBlock == NULL) { DPRINT("CmiGetBlock() failed\n"); - return 0; } - - for (i = 0; i < HashBlock->HashTableSize; i++) + else { - if (HashBlock->Table[i].KeyOffset != 0) - { - CurSubKeyCell = CmiGetBlock(RegistryHive, - HashBlock->Table[i].KeyOffset, - NULL); - if (CurSubKeyCell == NULL) + for (i = 0; i < HashBlock->HashTableSize; i++) + { + if (HashBlock->Table[i].KeyOffset != 0) { - DPRINT("CmiGetBlock() failed\n"); - return 0; + CurSubKeyCell = CmiGetBlock(KeyObject->RegistryHive, + HashBlock->Table[i].KeyOffset, + NULL); + if (CurSubKeyCell == NULL) + { + DPRINT("CmiGetBlock() failed\n"); + continue; + } + + if (MaxClass < CurSubKeyCell->ClassSize) + { + MaxClass = CurSubKeyCell->ClassSize; + } } - - if (MaxClass < CurSubKeyCell->ClassSize) + } + } + if (KeyObject->RegistryHive != CmiVolatileHive) + { + DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys); + for (i = 0; i < KeyObject->NumberOfSubKeys; i++) + { + CurKey = KeyObject->SubKeys[i]; + if (CurKey->RegistryHive == CmiVolatileHive) { - MaxClass = CurSubKeyCell->ClassSize; + CurSubKeyCell = CurKey->KeyCell; + if (CurSubKeyCell == NULL) + { + DPRINT("CmiGetBlock() failed\n"); + continue; + } + if (MaxClass < CurSubKeyCell->ClassSize) + { + MaxClass = CurSubKeyCell->ClassSize; + } } } } @@ -1885,6 +2156,7 @@ CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive, PVALUE_LIST_CELL ValueListCell; PVALUE_CELL CurValueCell; ULONG MaxValueName; + ULONG Size; ULONG i; VERIFY_KEY_CELL(KeyCell); @@ -1909,10 +2181,17 @@ CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive, DPRINT("CmiGetBlock() failed\n"); } - if (CurValueCell != NULL && - MaxValueName < CurValueCell->NameSize) + if (CurValueCell != NULL) { - MaxValueName = CurValueCell->NameSize; + Size = CurValueCell->NameSize; + if (CurValueCell->Flags & REG_VALUE_NAME_PACKED) + { + Size *= sizeof(WCHAR); + } + if (MaxValueName < Size) + { + MaxValueName = Size; + } } } @@ -1958,18 +2237,17 @@ CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive, IN PKEY_CELL KeyCell, OUT PKEY_CELL *SubKeyCell, OUT BLOCK_OFFSET *BlockOffset, - IN PCHAR KeyName, + IN PUNICODE_STRING KeyName, IN ACCESS_MASK DesiredAccess, IN ULONG Attributes) { PHASH_TABLE_CELL HashBlock; PKEY_CELL CurSubKeyCell; - USHORT KeyLength; ULONG i; VERIFY_KEY_CELL(KeyCell); - //DPRINT("Scanning for sub key %s\n", KeyName); + DPRINT("Scanning for sub key %wZ\n", KeyName); assert(RegistryHive); @@ -1989,14 +2267,14 @@ CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive, return STATUS_UNSUCCESSFUL; } - KeyLength = strlen(KeyName); for (i = 0; (i < KeyCell->NumberOfSubKeys) && (i < HashBlock->HashTableSize); i++) { if (Attributes & OBJ_CASE_INSENSITIVE) { - if ((HashBlock->Table[i].KeyOffset != 0) && - (HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1) && - (_strnicmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4) == 0)) + if (HashBlock->Table[i].KeyOffset != 0 && + HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1 && + (HashBlock->Table[i].HashValue == 0 || + CmiCompareHashI(KeyName, (PCHAR)&HashBlock->Table[i].HashValue))) { CurSubKeyCell = CmiGetBlock(RegistryHive, HashBlock->Table[i].KeyOffset, @@ -2007,20 +2285,20 @@ CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive, return STATUS_UNSUCCESSFUL; } - if ((CurSubKeyCell->NameSize == KeyLength) - && (_strnicmp(KeyName, CurSubKeyCell->Name, KeyLength) == 0)) - { - *SubKeyCell = CurSubKeyCell; - *BlockOffset = HashBlock->Table[i].KeyOffset; - break; - } - } + if (CmiCompareKeyNamesI(KeyName, CurSubKeyCell)) + { + *SubKeyCell = CurSubKeyCell; + *BlockOffset = HashBlock->Table[i].KeyOffset; + break; + } + } } else { if (HashBlock->Table[i].KeyOffset != 0 && HashBlock->Table[i].KeyOffset != (ULONG_PTR) -1 && - !strncmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4)) + (HashBlock->Table[i].HashValue == 0 || + CmiCompareHash(KeyName, (PCHAR)&HashBlock->Table[i].HashValue))) { CurSubKeyCell = CmiGetBlock(RegistryHive, HashBlock->Table[i].KeyOffset, @@ -2031,14 +2309,13 @@ CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive, return STATUS_UNSUCCESSFUL; } - if (CurSubKeyCell->NameSize == KeyLength - && !_strnicmp(KeyName, CurSubKeyCell->Name, KeyLength)) - { - *SubKeyCell = CurSubKeyCell; - *BlockOffset = HashBlock->Table[i].KeyOffset; - break; - } - } + if (CmiCompareKeyNames(KeyName, CurSubKeyCell)) + { + *SubKeyCell = CurSubKeyCell; + *BlockOffset = HashBlock->Table[i].KeyOffset; + break; + } + } } } @@ -2050,8 +2327,7 @@ NTSTATUS CmiAddSubKey(PREGISTRY_HIVE RegistryHive, PKEY_OBJECT Parent, PKEY_OBJECT SubKey, - PWSTR NewSubKeyName, - USHORT NewSubKeyNameSize, + PUNICODE_STRING SubKeyName, ULONG TitleIndex, PUNICODE_STRING Class, ULONG CreateOptions) @@ -2059,25 +2335,50 @@ CmiAddSubKey(PREGISTRY_HIVE RegistryHive, PHASH_TABLE_CELL NewHashBlock; PHASH_TABLE_CELL HashBlock; BLOCK_OFFSET NKBOffset; - PKEY_CELL NewKeyCell; + PKEY_CELL NewKeyCell; ULONG NewBlockSize; PKEY_CELL KeyCell; NTSTATUS Status; USHORT NameSize; + PWSTR NamePtr; + BOOLEAN Packable; + ULONG i; KeyCell = Parent->KeyCell; VERIFY_KEY_CELL(KeyCell); - if (NewSubKeyName[0] == L'\\') + /* Skip leading backslash */ + if (SubKeyName->Buffer[0] == L'\\') { - NewSubKeyName++; - NameSize = NewSubKeyNameSize / 2 - 1; + NamePtr = &SubKeyName->Buffer[1]; + NameSize = SubKeyName->Length - sizeof(WCHAR); } else { - NameSize = NewSubKeyNameSize / 2; + NamePtr = SubKeyName->Buffer; + NameSize = SubKeyName->Length; + } + + /* Check whether key name can be packed */ + Packable = TRUE; + for (i = 0; i < NameSize / sizeof(WCHAR); i++) + { + if (NamePtr[i] & 0xFF00) + { + Packable = FALSE; + break; + } + } + + /* Adjust name size */ + if (Packable) + { + NameSize = NameSize / sizeof(WCHAR); } + + DPRINT("Key %S Length %lu %s\n", NamePtr, NameSize, (Packable)?"True":"False"); + Status = STATUS_SUCCESS; NewBlockSize = sizeof(KEY_CELL) + NameSize; @@ -2092,18 +2393,33 @@ CmiAddSubKey(PREGISTRY_HIVE RegistryHive, else { NewKeyCell->Id = REG_KEY_CELL_ID; - NewKeyCell->Type = REG_KEY_CELL_TYPE; - ZwQuerySystemTime((PTIME) &NewKeyCell->LastWriteTime); + NewKeyCell->Flags = 0; + NtQuerySystemTime(&NewKeyCell->LastWriteTime); NewKeyCell->ParentKeyOffset = -1; NewKeyCell->NumberOfSubKeys = 0; NewKeyCell->HashTableOffset = -1; NewKeyCell->NumberOfValues = 0; NewKeyCell->ValuesOffset = -1; NewKeyCell->SecurityKeyOffset = -1; - NewKeyCell->NameSize = NameSize; - wcstombs(NewKeyCell->Name, NewSubKeyName, NameSize); NewKeyCell->ClassNameOffset = -1; + /* Pack the key name */ + NewKeyCell->NameSize = NameSize; + if (Packable) + { + NewKeyCell->Flags |= REG_KEY_NAME_PACKED; + for (i = 0; i < NameSize; i++) + { + NewKeyCell->Name[i] = (CHAR)(NamePtr[i] & 0x00FF); + } + } + else + { + RtlCopyMemory(NewKeyCell->Name, + NamePtr, + NameSize); + } + VERIFY_KEY_CELL(NewKeyCell); if (Class) @@ -2112,10 +2428,12 @@ CmiAddSubKey(PREGISTRY_HIVE RegistryHive, NewKeyCell->ClassSize = Class->Length + sizeof(WCHAR); Status = CmiAllocateBlock(RegistryHive, - (PVOID) &pClass, + (PVOID)&pClass, NewKeyCell->ClassSize, &NewKeyCell->ClassNameOffset); - wcsncpy((PWSTR) pClass->Data, Class->Buffer, Class->Length); + wcsncpy((PWSTR)pClass->Data, + Class->Buffer, + Class->Length); ((PWSTR) (pClass->Data))[Class->Length] = 0; } } @@ -2147,7 +2465,9 @@ CmiAddSubKey(PREGISTRY_HIVE RegistryHive, } else { - HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL); + HashBlock = CmiGetBlock(RegistryHive, + KeyCell->HashTableOffset, + NULL); if (HashBlock == NULL) { DPRINT("CmiGetBlock() failed\n"); @@ -2273,7 +2593,7 @@ CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive, if (ParentKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1) { DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset) - HashBlock = CmiGetBlock(RegistryHive, + HashBlock = CmiGetBlock(ParentKey->RegistryHive, ParentKey->KeyCell->HashTableOffset, NULL); if (HashBlock == NULL) @@ -2284,10 +2604,10 @@ CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive, DPRINT("ParentKey HashBlock %p\n", HashBlock) if (HashBlock != NULL) { - CmiRemoveKeyFromHashTable(RegistryHive, + CmiRemoveKeyFromHashTable(ParentKey->RegistryHive, HashBlock, SubKey->BlockOffset); - CmiMarkBlockDirty(RegistryHive, + CmiMarkBlockDirty(ParentKey->RegistryHive, ParentKey->KeyCell->HashTableOffset); } } @@ -2324,7 +2644,7 @@ CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive, if (ParentKey->KeyCell->NumberOfSubKeys == 0) { DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset) - HashBlock = CmiGetBlock(RegistryHive, + HashBlock = CmiGetBlock(ParentKey->RegistryHive, ParentKey->KeyCell->HashTableOffset, NULL); if (HashBlock == NULL) @@ -2335,15 +2655,15 @@ CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive, DPRINT("ParentKey HashBlock %p\n", HashBlock) if (HashBlock != NULL) { - CmiDestroyBlock(RegistryHive, + CmiDestroyBlock(ParentKey->RegistryHive, HashBlock, ParentKey->KeyCell->HashTableOffset); ParentKey->KeyCell->HashTableOffset = -1; } } - NtQuerySystemTime((PTIME)&ParentKey->KeyCell->LastWriteTime); - CmiMarkBlockDirty(RegistryHive, + NtQuerySystemTime(&ParentKey->KeyCell->LastWriteTime); + CmiMarkBlockDirty(ParentKey->RegistryHive, ParentKey->BlockOffset); } @@ -2685,7 +3005,13 @@ CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive, if (HashBlock->Table[i].KeyOffset == 0) { HashBlock->Table[i].KeyOffset = NKBOffset; - RtlCopyMemory(&HashBlock->Table[i].HashValue, NewKeyCell->Name, 4); + HashBlock->Table[i].HashValue = 0; + if (NewKeyCell->Flags & REG_KEY_NAME_PACKED) + { + RtlCopyMemory(&HashBlock->Table[i].HashValue, + NewKeyCell->Name, + min(NewKeyCell->NameSize, 4)); + } return STATUS_SUCCESS; } } @@ -2706,7 +3032,7 @@ CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive, if (HashBlock->Table[i].KeyOffset == NKBOffset) { HashBlock->Table[i].KeyOffset = 0; - RtlZeroMemory(&HashBlock->Table[i].HashValue, 4); + HashBlock->Table[i].HashValue = 0; return STATUS_SUCCESS; } } @@ -2801,17 +3127,17 @@ CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive, } /* Update time of heap */ - if (!IsVolatileHive(RegistryHive)) - NtQuerySystemTime((PTIME) &pBin->DateModified); + if (!IsNoFileHive(RegistryHive)) + NtQuerySystemTime(&pBin->DateModified); } /* Destroy the value cell */ Status = CmiDestroyBlock(RegistryHive, ValueCell, VBOffset); /* Update time of heap */ - if (!IsVolatileHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin)) + if (!IsNoFileHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin)) { - NtQuerySystemTime((PTIME) &pBin->DateModified); + NtQuerySystemTime(&pBin->DateModified); } return Status; @@ -2838,7 +3164,7 @@ CmiAddBin(PREGISTRY_HIVE RegistryHive, RegistryHive->FileSize += REG_BLOCK_SIZE; tmpBin->BlockSize = REG_BLOCK_SIZE; tmpBin->Unused1 = 0; - ZwQuerySystemTime((PTIME) &tmpBin->DateModified); + ZwQuerySystemTime(&tmpBin->DateModified); tmpBin->Unused2 = 0; /* Increase size of list of blocks */ @@ -2867,7 +3193,7 @@ CmiAddBin(PREGISTRY_HIVE RegistryHive, tmpBlock->CellSize = (REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET); /* Grow bitmap if necessary */ - if (IsVolatileHive(RegistryHive) && + if (IsNoFileHive(RegistryHive) && (RegistryHive->BlockListSize % (sizeof(ULONG) * 8) == 0)) { PULONG BitmapBuffer; @@ -2962,7 +3288,7 @@ CmiAllocateBlock(PREGISTRY_HIVE RegistryHive, if (Temp) { - NtQuerySystemTime((PTIME) &pBin->DateModified); + NtQuerySystemTime(&pBin->DateModified); CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]); } @@ -3048,8 +3374,8 @@ CmiDestroyBlock(PREGISTRY_HIVE RegistryHive, CmiAddFree(RegistryHive, Block, Offset, TRUE); /* Update time of heap */ - if (!IsVolatileHive(RegistryHive) && CmiGetBlock(RegistryHive, Offset,&pBin)) - NtQuerySystemTime((PTIME) &pBin->DateModified); + if (!IsNoFileHive(RegistryHive) && CmiGetBlock(RegistryHive, Offset,&pBin)) + NtQuerySystemTime(&pBin->DateModified); CmiMarkBlockDirty(RegistryHive, Offset); } @@ -3307,7 +3633,7 @@ CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive, ULONG BlockNumber; ULONG BlockCount; - if (IsVolatileHive(RegistryHive)) + if (IsNoFileHive(RegistryHive)) return; DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG)BlockOffset); @@ -3345,7 +3671,7 @@ CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive, ULONG BlockCount; PHBIN Bin; - if (IsVolatileHive(RegistryHive)) + if (IsNoFileHive(RegistryHive)) return; DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG)BinOffset); @@ -3377,17 +3703,17 @@ CmiGetPackedNameLength(IN PUNICODE_STRING Name, if (Packable != NULL) *Packable = TRUE; - for (i = 0; i < Name->Length; i++) + for (i = 0; i < Name->Length / sizeof(WCHAR); i++) { - if (Name->Buffer[i] > 0xFF) + if (Name->Buffer[i] & 0xFF00) { if (Packable != NULL) *Packable = FALSE; - return(Name->Length); + return Name->Length; } } - return(Name->Length / sizeof(WCHAR)); + return (Name->Length / sizeof(WCHAR)); } @@ -3440,4 +3766,432 @@ CmiCopyPackedName(PWCHAR NameBuffer, NameBuffer[i] = (WCHAR)PackedNameBuffer[i]; } + +BOOLEAN +CmiCompareHash(PUNICODE_STRING KeyName, + PCHAR HashString) +{ + CHAR Buffer[4]; + + Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0; + Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0; + Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0; + Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0; + + return (strncmp(Buffer, HashString, 4) == 0); +} + + +BOOLEAN +CmiCompareHashI(PUNICODE_STRING KeyName, + PCHAR HashString) +{ + CHAR Buffer[4]; + + Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0; + Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0; + Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0; + Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0; + + return (_strnicmp(Buffer, HashString, 4) == 0); +} + + +BOOLEAN +CmiCompareKeyNames(PUNICODE_STRING KeyName, + PKEY_CELL KeyCell) +{ + PWCHAR UnicodeName; + USHORT i; + + DPRINT("Flags: %hx\n", KeyCell->Flags); + + if (KeyCell->Flags & REG_KEY_NAME_PACKED) + { + if (KeyName->Length != KeyCell->NameSize * sizeof(WCHAR)) + return FALSE; + + for (i = 0; i < KeyCell->NameSize; i++) + { + if (KeyName->Buffer[i] != (WCHAR)KeyCell->Name[i]) + return FALSE; + } + } + else + { + if (KeyName->Length != KeyCell->NameSize) + return FALSE; + + UnicodeName = (PWCHAR)KeyCell->Name; + for (i = 0; i < KeyCell->NameSize / sizeof(WCHAR); i++) + { + if (KeyName->Buffer[i] != UnicodeName[i]) + return FALSE; + } + } + + return TRUE; +} + + +BOOLEAN +CmiCompareKeyNamesI(PUNICODE_STRING KeyName, + PKEY_CELL KeyCell) +{ + PWCHAR UnicodeName; + USHORT i; + + DPRINT("Flags: %hx\n", KeyCell->Flags); + + if (KeyCell->Flags & REG_KEY_NAME_PACKED) + { + if (KeyName->Length != KeyCell->NameSize * sizeof(WCHAR)) + return FALSE; + + for (i = 0; i < KeyCell->NameSize; i++) + { + if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) != + RtlUpcaseUnicodeChar((WCHAR)KeyCell->Name[i])) + return FALSE; + } + } + else + { + if (KeyName->Length != KeyCell->NameSize) + return FALSE; + + UnicodeName = (PWCHAR)KeyCell->Name; + for (i = 0; i < KeyCell->NameSize / sizeof(WCHAR); i++) + { + if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) != + RtlUpcaseUnicodeChar(UnicodeName[i])) + return FALSE; + } + } + + return TRUE; +} + + +NTSTATUS +CmiCopyKey (PREGISTRY_HIVE DstHive, + PKEY_CELL DstKeyCell, + PREGISTRY_HIVE SrcHive, + PKEY_CELL SrcKeyCell) +{ + PKEY_CELL NewKeyCell; + ULONG NewKeyCellSize; + BLOCK_OFFSET NewKeyCellOffset; + PHASH_TABLE_CELL NewHashTableCell; + ULONG NewHashTableSize; + BLOCK_OFFSET NewHashTableOffset; + ULONG i; + NTSTATUS Status; + + DPRINT ("CmiCopyKey() called\n"); + + if (DstKeyCell == NULL) + { + /* Allocate and copy key cell */ + NewKeyCellSize = sizeof(KEY_CELL) + SrcKeyCell->NameSize; + Status = CmiAllocateBlock (DstHive, + (PVOID) &NewKeyCell, + NewKeyCellSize, + &NewKeyCellOffset); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status); + return Status; + } + if (NewKeyCell == NULL) + { + DPRINT1 ("Failed to allocate a key cell\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory (NewKeyCell, + SrcKeyCell, + NewKeyCellSize); + + DstHive->HiveHeader->RootKeyCell = NewKeyCellOffset; + + /* Copy class name */ + if (SrcKeyCell->ClassNameOffset != (BLOCK_OFFSET) -1) + { + PDATA_CELL SrcClassNameCell; + PDATA_CELL NewClassNameCell; + BLOCK_OFFSET NewClassNameOffset; + + SrcClassNameCell = CmiGetBlock (SrcHive, SrcKeyCell->ClassNameOffset, NULL), + + NewKeyCell->ClassSize = SrcKeyCell->ClassSize; + Status = CmiAllocateBlock (DstHive, + (PVOID)&NewClassNameCell, + NewKeyCell->ClassSize, + &NewClassNameOffset); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status); + return Status; + } + + RtlCopyMemory (NewClassNameCell, + SrcClassNameCell, + NewKeyCell->ClassSize); + NewKeyCell->ClassNameOffset = NewClassNameOffset; + } + } + else + { + NewKeyCell = DstKeyCell; + } + + /* Allocate hash table */ + if (SrcKeyCell->NumberOfSubKeys > 0) + { + NewHashTableSize = ROUND_UP(SrcKeyCell->NumberOfSubKeys + 1, 4) - 1; + Status = CmiAllocateHashTableBlock (DstHive, + &NewHashTableCell, + &NewHashTableOffset, + NewHashTableSize); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status); + return Status; + } + NewKeyCell->HashTableOffset = NewHashTableOffset; + } + + /* Allocate and copy value list and values */ + if (SrcKeyCell->NumberOfValues != 0) + { + PVALUE_LIST_CELL NewValueListCell; + PVALUE_LIST_CELL SrcValueListCell; + PVALUE_CELL NewValueCell; + PVALUE_CELL SrcValueCell; + PDATA_CELL SrcValueDataCell; + PDATA_CELL NewValueDataCell; + BLOCK_OFFSET ValueCellOffset; + BLOCK_OFFSET ValueDataCellOffset; + ULONG NewValueListCellSize; + ULONG NewValueCellSize; + + + NewValueListCellSize = + ROUND_UP(SrcKeyCell->NumberOfValues, 4) * sizeof(BLOCK_OFFSET); + Status = CmiAllocateBlock (DstHive, + (PVOID)&NewValueListCell, + NewValueListCellSize, + &NewKeyCell->ValuesOffset); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status); + return Status; + } + + RtlZeroMemory (NewValueListCell, + NewValueListCellSize); + + /* Copy values */ + SrcValueListCell = CmiGetBlock (SrcHive, SrcKeyCell->ValuesOffset, NULL); + for (i = 0; i < SrcKeyCell->NumberOfValues; i++) + { + /* Copy value cell */ + SrcValueCell = CmiGetBlock (SrcHive, SrcValueListCell->Values[i], NULL); + + NewValueCellSize = sizeof(VALUE_CELL) + SrcValueCell->NameSize; + Status = CmiAllocateBlock (DstHive, + (PVOID*) &NewValueCell, + NewValueCellSize, + &ValueCellOffset); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status); + return Status; + } + + NewValueListCell->Values[i] = ValueCellOffset; + RtlCopyMemory (NewValueCell, + SrcValueCell, + NewValueCellSize); + + /* Copy value data cell */ + if (SrcValueCell->DataSize > (LONG) sizeof(PVOID)) + { + SrcValueDataCell = CmiGetBlock (SrcHive, SrcValueCell->DataOffset, NULL); + + Status = CmiAllocateBlock (DstHive, + (PVOID*) &NewValueDataCell, + SrcValueCell->DataSize, + &ValueDataCellOffset); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status); + return Status; + } + RtlCopyMemory (NewValueDataCell, + SrcValueDataCell, + SrcValueCell->DataSize); + NewValueCell->DataOffset = ValueDataCellOffset; + } + } + } + + /* Copy subkeys */ + if (SrcKeyCell->NumberOfSubKeys > 0) + { + PHASH_TABLE_CELL SrcHashTableCell; + PKEY_CELL SrcSubKeyCell; + PKEY_CELL NewSubKeyCell; + ULONG NewSubKeyCellSize; + BLOCK_OFFSET NewSubKeyCellOffset; + PHASH_RECORD SrcHashRecord; + + SrcHashTableCell = CmiGetBlock (SrcHive, + SrcKeyCell->HashTableOffset, + NULL); + + for (i = 0; i < SrcKeyCell->NumberOfSubKeys; i++) + { + SrcHashRecord = &SrcHashTableCell->Table[i]; + SrcSubKeyCell = CmiGetBlock (SrcHive, SrcHashRecord->KeyOffset, NULL); + + /* Allocate and copy key cell */ + NewSubKeyCellSize = sizeof(KEY_CELL) + SrcSubKeyCell->NameSize; + Status = CmiAllocateBlock (DstHive, + (PVOID)&NewSubKeyCell, + NewSubKeyCellSize, + &NewSubKeyCellOffset); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status); + return Status; + } + if (NewKeyCell == NULL) + { + DPRINT1 ("Failed to allocate a sub key cell\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + NewHashTableCell->Table[i].KeyOffset = NewSubKeyCellOffset; + NewHashTableCell->Table[i].HashValue = SrcHashRecord->HashValue; + + RtlCopyMemory (NewSubKeyCell, + SrcSubKeyCell, + NewSubKeyCellSize); + + /* Copy class name */ + if (SrcSubKeyCell->ClassNameOffset != (BLOCK_OFFSET) -1) + { + PDATA_CELL SrcClassNameCell; + PDATA_CELL NewClassNameCell; + BLOCK_OFFSET NewClassNameOffset; + + SrcClassNameCell = CmiGetBlock (SrcHive, + SrcSubKeyCell->ClassNameOffset, + NULL), + + NewSubKeyCell->ClassSize = SrcSubKeyCell->ClassSize; + Status = CmiAllocateBlock (DstHive, + (PVOID)&NewClassNameCell, + NewSubKeyCell->ClassSize, + &NewClassNameOffset); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status); + return Status; + } + + NewSubKeyCell->ClassNameOffset = NewClassNameOffset; + RtlCopyMemory (NewClassNameCell, + SrcClassNameCell, + NewSubKeyCell->ClassSize); + } + + /* Copy subkey data and subkeys */ + Status = CmiCopyKey (DstHive, + NewSubKeyCell, + SrcHive, + SrcSubKeyCell); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status); + return Status; + } + } + } + + return STATUS_SUCCESS; +} + + +NTSTATUS +CmiSaveTempHive (PREGISTRY_HIVE Hive, + HANDLE FileHandle) +{ + IO_STATUS_BLOCK IoStatusBlock; + LARGE_INTEGER FileOffset; + ULONG BlockIndex; + PVOID BlockPtr; + NTSTATUS Status; + + DPRINT ("CmiSaveTempHive() called\n"); + + Hive->HiveHeader->Checksum = CmiCalcChecksum ((PULONG)Hive->HiveHeader); + + /* Write hive block */ + FileOffset.QuadPart = 0ULL; + Status = NtWriteFile (FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Hive->HiveHeader, + sizeof(HIVE_HEADER), + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status); + return Status; + } + + DPRINT ("Saving %lu blocks\n", Hive->BlockListSize); + for (BlockIndex = 0; BlockIndex < Hive->BlockListSize; BlockIndex++) + { + BlockPtr = Hive->BlockList[BlockIndex]; + DPRINT ("BlockPtr %p\n", BlockPtr); + + FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096ULL; + DPRINT ("File offset %I64x\n", FileOffset.QuadPart); + + /* Write hive block */ + Status = NtWriteFile (FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + BlockPtr, + REG_BLOCK_SIZE, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status); + return Status; + } + } + + Status = NtFlushBuffersFile (FileHandle, + &IoStatusBlock); + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status); + } + + DPRINT ("CmiSaveTempHive() done\n"); + + return Status; +} + /* EOF */