2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/regfile.c
5 * PURPOSE: Registry file manipulation routines
11 #include <internal/ob.h>
14 #include <internal/registry.h>
15 #include <ntos/minmax.h>
16 #include <reactos/bugcodes.h>
19 #include <internal/debug.h>
24 /* uncomment to enable hive checks (incomplete and probably buggy) */
27 /* LOCAL MACROS *************************************************************/
29 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
30 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
32 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
34 BOOLEAN CmiDoVerify = FALSE;
37 CmiCalcChecksum(PULONG Buffer);
39 /* FUNCTIONS ****************************************************************/
42 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header)
45 RtlZeroMemory(Header, sizeof(HIVE_HEADER));
46 Header->BlockId = REG_HIVE_ID;
47 Header->UpdateCounter1 = 0;
48 Header->UpdateCounter2 = 0;
49 Header->DateModified.u.LowPart = 0;
50 Header->DateModified.u.HighPart = 0;
56 Header->RootKeyCell = 0;
57 Header->BlockSize = REG_BLOCK_SIZE;
64 CmiCreateDefaultBinCell(PHBIN BinCell)
67 RtlZeroMemory(BinCell, sizeof(HBIN));
68 BinCell->BlockId = REG_BIN_ID;
69 BinCell->DateModified.u.LowPart = 0;
70 BinCell->DateModified.u.HighPart = 0;
71 BinCell->BlockSize = REG_BLOCK_SIZE;
76 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell)
79 RtlZeroMemory(RootKeyCell, sizeof(KEY_CELL));
80 RootKeyCell->CellSize = -sizeof(KEY_CELL);
81 RootKeyCell->Id = REG_KEY_CELL_ID;
82 RootKeyCell->Flags = REG_KEY_ROOT_CELL | REG_KEY_NAME_PACKED;
83 NtQuerySystemTime(&RootKeyCell->LastWriteTime);
84 RootKeyCell->ParentKeyOffset = 0;
85 RootKeyCell->NumberOfSubKeys = 0;
86 RootKeyCell->HashTableOffset = -1;
87 RootKeyCell->NumberOfValues = 0;
88 RootKeyCell->ValuesOffset = -1;
89 RootKeyCell->SecurityKeyOffset = 0;
90 RootKeyCell->ClassNameOffset = -1;
91 RootKeyCell->NameSize = 0;
92 RootKeyCell->ClassSize = 0;
97 CmiVerifyBinCell(PHBIN BinCell)
104 if (BinCell->BlockId != REG_BIN_ID)
106 DbgPrint("BlockId is %.08x (should be %.08x)\n",
107 BinCell->BlockId, REG_BIN_ID);
108 assert(BinCell->BlockId == REG_BIN_ID);
111 //BinCell->DateModified.dwLowDateTime
113 //BinCell->DateModified.dwHighDateTime
116 if (BinCell->BlockSize != REG_BLOCK_SIZE)
118 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
119 BinCell->BlockSize, REG_BLOCK_SIZE);
120 assert(BinCell->BlockSize == REG_BLOCK_SIZE);
128 CmiVerifyKeyCell(PKEY_CELL KeyCell)
135 if (KeyCell->CellSize == 0)
137 DbgPrint("CellSize is %d (must not be 0)\n",
139 assert(KeyCell->CellSize != 0);
142 if (KeyCell->Id != REG_KEY_CELL_ID)
144 DbgPrint("Id is %.08x (should be %.08x)\n",
145 KeyCell->Id, REG_KEY_CELL_ID);
146 assert(KeyCell->Id == REG_KEY_CELL_ID);
151 //KeyCell->LastWriteTime;
153 if (KeyCell->ParentKeyOffset < 0)
155 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
156 KeyCell->ParentKeyOffset);
157 assert(KeyCell->ParentKeyOffset >= 0);
160 if (KeyCell->NumberOfSubKeys < 0)
162 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
163 KeyCell->NumberOfSubKeys);
164 assert(KeyCell->NumberOfSubKeys >= 0);
167 //KeyCell->HashTableOffset;
169 if (KeyCell->NumberOfValues < 0)
171 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
172 KeyCell->NumberOfValues);
173 assert(KeyCell->NumberOfValues >= 0);
176 //KeyCell->ValuesOffset = -1;
178 if (KeyCell->SecurityKeyOffset < 0)
180 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
181 KeyCell->SecurityKeyOffset);
182 assert(KeyCell->SecurityKeyOffset >= 0);
185 //KeyCell->ClassNameOffset = -1;
196 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell)
201 CmiVerifyKeyCell(RootKeyCell);
203 if (!(RootKeyCell->Flags & REG_KEY_ROOT_CELL))
205 DbgPrint("Flags is %.08x (should be %.08x)\n",
206 RootKeyCell->Flags, REG_KEY_ROOT_CELL | REG_KEY_NAME_PACKED);
207 assert(!(RootKeyCell->Flags & (REG_KEY_ROOT_CELL | REG_KEY_NAME_PACKED)));
215 CmiVerifyValueCell(PVALUE_CELL ValueCell)
222 if (ValueCell->CellSize == 0)
224 DbgPrint("CellSize is %d (must not be 0)\n",
225 ValueCell->CellSize);
226 assert(ValueCell->CellSize != 0);
229 if (ValueCell->Id != REG_VALUE_CELL_ID)
231 DbgPrint("Id is %.08x (should be %.08x)\n",
232 ValueCell->Id, REG_VALUE_CELL_ID);
233 assert(ValueCell->Id == REG_VALUE_CELL_ID);
236 //ValueCell->NameSize;
237 //ValueCell->LONG DataSize;
238 //ValueCell->DataOffset;
239 //ValueCell->ULONG DataType;
240 //ValueCell->USHORT Flags;
241 //ValueCell->USHORT Unused1;
242 //ValueCell->UCHAR Name[0];
248 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell)
253 if (ValueListCell->CellSize == 0)
255 DbgPrint("CellSize is %d (must not be 0)\n",
256 ValueListCell->CellSize);
257 assert(ValueListCell->CellSize != 0);
265 CmiVerifyKeyObject(PKEY_OBJECT KeyObject)
270 if (KeyObject->RegistryHive == NULL)
272 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
273 KeyObject->RegistryHive);
274 assert(KeyObject->RegistryHive != NULL);
277 if (KeyObject->KeyCell == NULL)
279 DbgPrint("KeyCell is NULL (must not be NULL)\n",
281 assert(KeyObject->KeyCell != NULL);
284 if (KeyObject->ParentKey == NULL)
286 DbgPrint("ParentKey is NULL (must not be NULL)\n",
287 KeyObject->ParentKey);
288 assert(KeyObject->ParentKey != NULL);
296 CmiVerifyHiveHeader(PHIVE_HEADER Header)
301 if (Header->BlockId != REG_HIVE_ID)
303 DbgPrint("BlockId is %.08x (must be %.08x)\n",
306 assert(Header->BlockId == REG_HIVE_ID);
309 if (Header->Unused3 != 1)
311 DbgPrint("Unused3 is %.08x (must be 1)\n",
313 assert(Header->Unused3 == 1);
316 if (Header->Unused4 != 3)
318 DbgPrint("Unused4 is %.08x (must be 3)\n",
320 assert(Header->Unused4 == 3);
323 if (Header->Unused5 != 0)
325 DbgPrint("Unused5 is %.08x (must be 0)\n",
327 assert(Header->Unused5 == 0);
330 if (Header->Unused6 != 1)
332 DbgPrint("Unused6 is %.08x (must be 1)\n",
334 assert(Header->Unused6 == 1);
337 if (Header->Unused7 != 1)
339 DbgPrint("Unused7 is %.08x (must be 1)\n",
341 assert(Header->Unused7 == 1);
349 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive)
354 CmiVerifyHiveHeader(RegistryHive->HiveHeader);
361 CmiCreateNewRegFile(HANDLE FileHandle)
363 IO_STATUS_BLOCK IoStatusBlock;
364 PCELL_HEADER FreeCell;
365 PHIVE_HEADER HiveHeader;
366 PKEY_CELL RootKeyCell;
371 Buffer = (PCHAR) ExAllocatePool(NonPagedPool, 2 * REG_BLOCK_SIZE);
373 return STATUS_INSUFFICIENT_RESOURCES;
375 HiveHeader = (PHIVE_HEADER)Buffer;
376 BinCell = (PHBIN)((ULONG_PTR)Buffer + REG_BLOCK_SIZE);
377 RootKeyCell = (PKEY_CELL)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET);
378 FreeCell = (PCELL_HEADER)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
380 CmiCreateDefaultHiveHeader(HiveHeader);
381 CmiCreateDefaultBinCell(BinCell);
382 CmiCreateDefaultRootKeyCell(RootKeyCell);
385 BinCell->BlockOffset = 0;
387 /* Offset to root key block */
388 HiveHeader->RootKeyCell = REG_HBIN_DATA_OFFSET;
390 /* The rest of the block is free */
391 FreeCell->CellSize = REG_BLOCK_SIZE - (REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
393 Status = NtWriteFile(FileHandle,
405 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
407 if (!NT_SUCCESS(Status))
412 Status = NtFlushBuffersFile(FileHandle,
421 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive)
423 OBJECT_ATTRIBUTES ObjectAttributes;
424 FILE_STANDARD_INFORMATION fsi;
425 IO_STATUS_BLOCK IoStatusBlock;
426 HANDLE HiveHandle = INVALID_HANDLE_VALUE;
427 HANDLE LogHandle = INVALID_HANDLE_VALUE;
428 PHIVE_HEADER HiveHeader = NULL;
429 PHIVE_HEADER LogHeader = NULL;
430 LARGE_INTEGER FileOffset;
434 RTL_BITMAP BlockBitMap;
437 DPRINT("CmiCheckAndFixHive() called\n");
439 /* Try to open the hive file */
440 InitializeObjectAttributes(&ObjectAttributes,
441 &RegistryHive->HiveFileName,
446 Status = NtCreateFile(&HiveHandle,
447 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
451 FILE_ATTRIBUTE_NORMAL,
454 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
457 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
459 return(STATUS_SUCCESS);
461 if (!NT_SUCCESS(Status))
463 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
467 /* Try to open the log file */
468 InitializeObjectAttributes(&ObjectAttributes,
469 &RegistryHive->LogFileName,
474 Status = NtCreateFile(&LogHandle,
475 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
479 FILE_ATTRIBUTE_NORMAL,
482 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
485 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
487 LogHandle = INVALID_HANDLE_VALUE;
489 else if (!NT_SUCCESS(Status))
491 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
496 /* Allocate hive header */
497 HiveHeader = ExAllocatePool(PagedPool,
498 sizeof(HIVE_HEADER));
499 if (HiveHeader == NULL)
501 DPRINT("ExAllocatePool() failed\n");
502 Status = STATUS_INSUFFICIENT_RESOURCES;
506 /* Read hive base block */
507 FileOffset.QuadPart = 0ULL;
508 Status = NtReadFile(HiveHandle,
517 if (!NT_SUCCESS(Status))
519 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
523 if (LogHandle == INVALID_HANDLE_VALUE)
525 if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) ||
526 HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2)
528 /* There is no way to fix the hive without log file - BSOD! */
529 DPRINT("Hive header inconsistent and no log file available!\n");
530 KEBUGCHECK(CONFIG_LIST_FAILED);
533 Status = STATUS_SUCCESS;
538 /* Allocate hive header */
539 LogHeader = ExAllocatePool(PagedPool,
540 sizeof(HIVE_HEADER));
541 if (LogHeader == NULL)
543 DPRINT("ExAllocatePool() failed\n");
544 Status = STATUS_INSUFFICIENT_RESOURCES;
548 /* Read log file header */
549 FileOffset.QuadPart = 0ULL;
550 Status = NtReadFile(LogHandle,
559 if (!NT_SUCCESS(Status))
561 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
565 /* Check log file header integrity */
566 if (LogHeader->Checksum != CmiCalcChecksum((PULONG)LogHeader) ||
567 LogHeader->UpdateCounter1 != LogHeader->UpdateCounter2)
569 if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) ||
570 HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2)
572 DPRINT("Hive file and log file are inconsistent!\n");
573 KEBUGCHECK(CONFIG_LIST_FAILED);
576 /* Log file damaged but hive is okay */
577 Status = STATUS_SUCCESS;
581 if (HiveHeader->UpdateCounter1 == HiveHeader->UpdateCounter2 &&
582 HiveHeader->UpdateCounter1 == LogHeader->UpdateCounter1)
584 /* Hive and log file are up-to-date */
585 Status = STATUS_SUCCESS;
590 * Hive needs an update!
594 Status = NtQueryInformationFile(LogHandle,
598 FileStandardInformation);
599 if (!NT_SUCCESS(Status))
601 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
604 FileSize = fsi.EndOfFile.u.LowPart;
606 /* Calculate bitmap and block size */
607 BitmapSize = ROUND_UP((FileSize / 4096) - 1, sizeof(ULONG) * 8) / 8;
608 BufferSize = sizeof(HIVE_HEADER) +
611 BufferSize = ROUND_UP(BufferSize, 4096);
613 /* Reallocate log header block */
614 ExFreePool(LogHeader);
615 LogHeader = ExAllocatePool(PagedPool,
617 if (LogHeader == NULL)
619 DPRINT("ExAllocatePool() failed\n");
620 Status = STATUS_INSUFFICIENT_RESOURCES;
624 /* Read log file header */
625 FileOffset.QuadPart = 0ULL;
626 Status = NtReadFile(LogHandle,
635 if (!NT_SUCCESS(Status))
637 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
641 /* Initialize bitmap */
642 RtlInitializeBitMap(&BlockBitMap,
643 (PVOID)((ULONG)LogHeader + 4096 + sizeof(ULONG)),
646 /* FIXME: Update dirty blocks */
649 /* FIXME: Update hive header */
652 Status = STATUS_SUCCESS;
656 /* Clean up the mess */
658 if (HiveHeader != NULL)
659 ExFreePool(HiveHeader);
661 if (LogHeader != NULL)
662 ExFreePool(LogHeader);
664 if (LogHandle != INVALID_HANDLE_VALUE)
675 CmiImportHiveBins(PREGISTRY_HIVE Hive,
678 BLOCK_OFFSET BlockOffset;
685 while (BlockIndex < Hive->BlockListSize)
687 Bin = (PHBIN)((ULONG_PTR)ChunkPtr + BlockOffset);
689 if (Bin->BlockId != REG_BIN_ID)
691 DPRINT1 ("Bad BlockId %x, offset %x\n", Bin->BlockId, BlockOffset);
692 return STATUS_REGISTRY_CORRUPT;
695 assertmsg((Bin->BlockSize % 4096) == 0,
696 ("BlockSize (0x%.08x) must be multiple of 4K\n",
699 /* Allocate the hive block */
700 Hive->BlockList[BlockIndex] = ExAllocatePool (PagedPool,
702 if (Hive->BlockList[BlockIndex] == NULL)
704 DPRINT1 ("ExAllocatePool() failed\n");
705 return STATUS_INSUFFICIENT_RESOURCES;
709 RtlCopyMemory (Hive->BlockList[BlockIndex],
713 if (Bin->BlockSize > 4096)
715 for (j = 1; j < Bin->BlockSize / 4096; j++)
717 Hive->BlockList[BlockIndex + j] = Hive->BlockList[BlockIndex];
721 BlockIndex += Bin->BlockSize / 4096;
722 BlockOffset += Bin->BlockSize;
725 return STATUS_SUCCESS;
730 CmiFreeHiveBins (PREGISTRY_HIVE Hive)
736 for (i = 0; i < Hive->BlockListSize; i++)
738 if (Hive->BlockList[i] == NULL)
741 if (Hive->BlockList[i] != Bin)
743 Bin = Hive->BlockList[i];
744 ExFreePool (Hive->BlockList[i]);
746 Hive->BlockList[i] = NULL;
752 CmiCreateHiveFreeCellList(PREGISTRY_HIVE Hive)
754 BLOCK_OFFSET BlockOffset;
755 PCELL_HEADER FreeBlock;
761 /* Initialize the free cell list */
762 Hive->FreeListSize = 0;
763 Hive->FreeListMax = 0;
764 Hive->FreeList = NULL;
765 Hive->FreeListOffset = NULL;
769 while (BlockIndex < Hive->BlockListSize)
771 Bin = Hive->BlockList[BlockIndex];
773 /* Search free blocks and add to list */
774 FreeOffset = REG_HBIN_DATA_OFFSET;
775 while (FreeOffset < Bin->BlockSize)
777 FreeBlock = (PCELL_HEADER) ((ULONG_PTR) Bin + FreeOffset);
778 if (FreeBlock->CellSize > 0)
780 Status = CmiAddFree(Hive,
782 Bin->BlockOffset + FreeOffset,
785 if (!NT_SUCCESS(Status))
790 FreeOffset += FreeBlock->CellSize;
794 FreeOffset -= FreeBlock->CellSize;
798 BlockIndex += Bin->BlockSize / 4096;
799 BlockOffset += Bin->BlockSize;
802 return STATUS_SUCCESS;
807 CmiFreeHiveFreeCellList(PREGISTRY_HIVE Hive)
809 ExFreePool (Hive->FreeList);
810 ExFreePool (Hive->FreeListOffset);
812 Hive->FreeListSize = 0;
813 Hive->FreeListMax = 0;
814 Hive->FreeList = NULL;
815 Hive->FreeListOffset = NULL;
820 CmiCreateHiveBitmap(PREGISTRY_HIVE Hive)
824 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
825 BitmapSize = ROUND_UP(Hive->BlockListSize, sizeof(ULONG) * 8) / 8;
826 DPRINT("Hive->BlockListSize: %lu\n", Hive->BlockListSize);
827 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
829 /* Allocate bitmap */
830 Hive->BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
832 if (Hive->BitmapBuffer == NULL)
834 return STATUS_INSUFFICIENT_RESOURCES;
837 RtlInitializeBitMap(&Hive->DirtyBitMap,
841 /* Initialize bitmap */
842 RtlClearAllBits(&Hive->DirtyBitMap);
843 Hive->HiveDirty = FALSE;
845 return STATUS_SUCCESS;
850 CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive,
853 OBJECT_ATTRIBUTES ObjectAttributes;
854 ULONG CreateDisposition;
855 IO_STATUS_BLOCK IoSB;
857 HANDLE SectionHandle;
862 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) called\n",
863 RegistryHive, Filename);
865 /* Duplicate Filename */
866 Status = RtlCreateUnicodeString(&RegistryHive->HiveFileName,
868 if (!NT_SUCCESS(Status))
870 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status);
874 /* Create log file name */
875 RegistryHive->LogFileName.Length = (wcslen(Filename) + 4) * sizeof(WCHAR);
876 RegistryHive->LogFileName.MaximumLength = RegistryHive->LogFileName.Length + sizeof(WCHAR);
877 RegistryHive->LogFileName.Buffer = ExAllocatePool(NonPagedPool,
878 RegistryHive->LogFileName.MaximumLength);
879 if (RegistryHive->LogFileName.Buffer == NULL)
881 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
882 DPRINT("ExAllocatePool() failed\n");
883 return(STATUS_INSUFFICIENT_RESOURCES);
885 wcscpy(RegistryHive->LogFileName.Buffer,
887 wcscat(RegistryHive->LogFileName.Buffer,
891 /* Check and eventually fix a hive */
892 Status = CmiCheckAndFixHive(RegistryHive);
893 if (!NT_SUCCESS(Status))
895 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
896 RtlFreeUnicodeString(&RegistryHive->LogFileName);
897 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status);
902 InitializeObjectAttributes(&ObjectAttributes,
903 &RegistryHive->HiveFileName,
908 CreateDisposition = FILE_OPEN_IF;
909 Status = NtCreateFile(&FileHandle,
914 FILE_ATTRIBUTE_NORMAL,
917 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
920 if (!NT_SUCCESS(Status))
922 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
923 RtlFreeUnicodeString(&RegistryHive->LogFileName);
924 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
928 if (IoSB.Information != FILE_OPENED)
930 Status = CmiCreateNewRegFile(FileHandle);
931 if (!NT_SUCCESS(Status))
933 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status);
935 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
936 RtlFreeUnicodeString(&RegistryHive->LogFileName);
941 /* Create the hive section */
942 Status = NtCreateSection(&SectionHandle,
950 if (!NT_SUCCESS(Status))
952 DPRINT1("NtCreateSection() failed (Status %lx)\n", Status);
953 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
954 RtlFreeUnicodeString(&RegistryHive->LogFileName);
958 /* Map the hive file */
961 Status = NtMapViewOfSection(SectionHandle,
971 if (!NT_SUCCESS(Status))
973 DPRINT1("MmMapViewInSystemSpace() failed (Status %lx)\n", Status);
974 NtClose(SectionHandle);
975 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
976 RtlFreeUnicodeString(&RegistryHive->LogFileName);
979 DPRINT("ViewBase %p ViewSize %lx\n", ViewBase, ViewSize);
981 /* Copy hive header and initalize hive */
982 RtlCopyMemory (RegistryHive->HiveHeader,
984 sizeof(HIVE_HEADER));
985 RegistryHive->FileSize = ViewSize;
986 RegistryHive->BlockListSize = (RegistryHive->FileSize / 4096) - 1;
987 RegistryHive->UpdateCounter = RegistryHive->HiveHeader->UpdateCounter1;
989 /* Allocate hive block list */
990 RegistryHive->BlockList = ExAllocatePool(NonPagedPool,
991 sizeof(PHBIN *) * RegistryHive->BlockListSize);
992 if (RegistryHive->BlockList == NULL)
994 DPRINT1("Failed to allocate the hive block list\n");
995 NtUnmapViewOfSection(NtCurrentProcess(),
997 NtClose(SectionHandle);
998 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
999 RtlFreeUnicodeString(&RegistryHive->LogFileName);
1000 return STATUS_INSUFFICIENT_RESOURCES;
1003 /* Import the hive bins */
1004 Status = CmiImportHiveBins (RegistryHive,
1006 if (!NT_SUCCESS(Status))
1008 ExFreePool(RegistryHive->BlockList);
1009 NtUnmapViewOfSection(NtCurrentProcess(),
1011 NtClose(SectionHandle);
1012 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
1013 RtlFreeUnicodeString(&RegistryHive->LogFileName);
1017 /* Unmap and dereference the hive section */
1018 NtUnmapViewOfSection(NtCurrentProcess(),
1020 NtClose(SectionHandle);
1022 /* Initialize the free cell list */
1023 Status = CmiCreateHiveFreeCellList (RegistryHive);
1024 if (!NT_SUCCESS(Status))
1026 CmiFreeHiveBins(RegistryHive);
1027 ExFreePool(RegistryHive->BlockList);
1028 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
1029 RtlFreeUnicodeString(&RegistryHive->LogFileName);
1033 /* Create the block bitmap */
1034 Status = CmiCreateHiveBitmap (RegistryHive);
1035 if (!NT_SUCCESS(Status))
1037 CmiFreeHiveFreeCellList(RegistryHive);
1038 CmiFreeHiveBins(RegistryHive);
1039 ExFreePool(RegistryHive->BlockList);
1040 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
1041 RtlFreeUnicodeString(&RegistryHive->LogFileName);
1045 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n",
1046 RegistryHive, Filename);
1048 return(STATUS_SUCCESS);
1053 CmiCreateVolatileHive(PREGISTRY_HIVE *RegistryHive)
1055 PKEY_CELL RootKeyCell;
1056 PREGISTRY_HIVE Hive;
1058 *RegistryHive = NULL;
1060 Hive = ExAllocatePool (NonPagedPool,
1061 sizeof(REGISTRY_HIVE));
1063 return STATUS_INSUFFICIENT_RESOURCES;
1065 RtlZeroMemory (Hive,
1066 sizeof(REGISTRY_HIVE));
1068 DPRINT("Hive %x\n", Hive);
1070 Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool (NonPagedPool,
1071 sizeof(HIVE_HEADER));
1072 if (Hive->HiveHeader == NULL)
1075 return STATUS_INSUFFICIENT_RESOURCES;
1078 Hive->Flags = (HIVE_NO_FILE | HIVE_POINTER);
1080 CmiCreateDefaultHiveHeader (Hive->HiveHeader);
1082 RootKeyCell = (PKEY_CELL)ExAllocatePool (NonPagedPool,
1084 if (RootKeyCell == NULL)
1086 ExFreePool(Hive->HiveHeader);
1088 return STATUS_INSUFFICIENT_RESOURCES;
1091 CmiCreateDefaultRootKeyCell (RootKeyCell);
1092 Hive->HiveHeader->RootKeyCell = (BLOCK_OFFSET)RootKeyCell;
1094 ExInitializeResourceLite (&Hive->HiveResource);
1096 /* Acquire hive list lock exclusively */
1097 ExAcquireResourceExclusiveLite (&CmiHiveListLock,
1100 /* Add the new hive to the hive list */
1101 InsertTailList (&CmiHiveListHead,
1104 /* Release hive list lock */
1105 ExReleaseResourceLite (&CmiHiveListLock);
1107 VERIFY_REGISTRY_HIVE (Hive);
1109 *RegistryHive = Hive;
1111 return STATUS_SUCCESS;
1116 CmiCreateTempHive(PREGISTRY_HIVE *RegistryHive)
1119 PCELL_HEADER FreeCell;
1120 PREGISTRY_HIVE Hive;
1123 DPRINT ("CmiCreateTempHive() called\n");
1125 *RegistryHive = NULL;
1127 Hive = ExAllocatePool (NonPagedPool,
1128 sizeof(REGISTRY_HIVE));
1131 DPRINT1 ("Failed to allocate registry hive block\n");
1132 return STATUS_INSUFFICIENT_RESOURCES;
1134 RtlZeroMemory (Hive,
1135 sizeof(REGISTRY_HIVE));
1137 DPRINT ("Hive %x\n", Hive);
1139 Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool (NonPagedPool,
1141 if (Hive->HiveHeader == NULL)
1143 DPRINT1 ("Failed to allocate hive header block\n");
1145 return STATUS_INSUFFICIENT_RESOURCES;
1147 RtlZeroMemory (Hive->HiveHeader,
1150 DPRINT ("HiveHeader %x\n", Hive->HiveHeader);
1152 Hive->Flags = HIVE_NO_FILE;
1154 RtlInitUnicodeString (&Hive->HiveFileName,
1156 RtlInitUnicodeString (&Hive->LogFileName,
1159 CmiCreateDefaultHiveHeader (Hive->HiveHeader);
1161 /* Allocate hive block list */
1162 Hive->BlockList = ExAllocatePool (NonPagedPool,
1164 if (Hive->BlockList == NULL)
1166 DPRINT1 ("Failed to allocate hive block list\n");
1167 ExFreePool(Hive->HiveHeader);
1169 return STATUS_INSUFFICIENT_RESOURCES;
1172 /* Allocate first Bin */
1173 Hive->BlockList[0] = ExAllocatePool (NonPagedPool,
1175 if (Hive->BlockList[0] == NULL)
1177 DPRINT1 ("Failed to allocate first bin\n");
1178 ExFreePool(Hive->BlockList);
1179 ExFreePool(Hive->HiveHeader);
1181 return STATUS_INSUFFICIENT_RESOURCES;
1184 Hive->FileSize = 2* REG_BLOCK_SIZE;
1185 Hive->BlockListSize = 1;
1186 Hive->UpdateCounter = Hive->HiveHeader->UpdateCounter1;
1189 BinCell = (PHBIN)Hive->BlockList[0];
1190 FreeCell = (PCELL_HEADER)((ULONG_PTR)BinCell + REG_HBIN_DATA_OFFSET);
1192 CmiCreateDefaultBinCell (BinCell);
1195 BinCell->BlockOffset = 0;
1197 /* Offset to root key block */
1198 Hive->HiveHeader->RootKeyCell = -1;
1200 /* The rest of the block is free */
1201 FreeCell->CellSize = REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET;
1203 /* Create the free cell list */
1204 Status = CmiCreateHiveFreeCellList (Hive);
1205 if (Hive->BlockList[0] == NULL)
1207 DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status);
1208 ExFreePool(Hive->BlockList[0]);
1209 ExFreePool(Hive->BlockList);
1210 ExFreePool(Hive->HiveHeader);
1216 ExInitializeResourceLite (&Hive->HiveResource);
1218 /* Acquire hive list lock exclusively */
1219 ExAcquireResourceExclusiveLite (&CmiHiveListLock,
1222 /* Add the new hive to the hive list */
1223 InsertTailList (&CmiHiveListHead,
1226 /* Release hive list lock */
1227 ExReleaseResourceLite (&CmiHiveListLock);
1229 VERIFY_REGISTRY_HIVE (Hive);
1231 *RegistryHive = Hive;
1233 return STATUS_SUCCESS;
1238 CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1239 IN PUNICODE_STRING FileName,
1242 PREGISTRY_HIVE Hive;
1245 DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName);
1247 if (Flags & ~REG_NO_LAZY_FLUSH)
1248 return STATUS_INVALID_PARAMETER;
1250 Hive = ExAllocatePool (NonPagedPool,
1251 sizeof(REGISTRY_HIVE));
1254 DPRINT1 ("Failed to allocate hive header.\n");
1255 return STATUS_INSUFFICIENT_RESOURCES;
1257 RtlZeroMemory (Hive,
1258 sizeof(REGISTRY_HIVE));
1260 DPRINT ("Hive %x\n", Hive);
1261 Hive->Flags = (Flags & REG_NO_LAZY_FLUSH) ? HIVE_NO_SYNCH : 0;
1263 Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool(NonPagedPool,
1264 sizeof(HIVE_HEADER));
1265 if (Hive->HiveHeader == NULL)
1267 DPRINT1 ("Failed to allocate hive header.\n");
1269 return STATUS_INSUFFICIENT_RESOURCES;
1272 Status = CmiInitNonVolatileRegistryHive (Hive,
1274 if (!NT_SUCCESS (Status))
1276 DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status);
1277 ExFreePool (Hive->HiveHeader);
1282 ExInitializeResourceLite (&Hive->HiveResource);
1284 /* Add the new hive to the hive list */
1285 ExAcquireResourceExclusiveLite (&CmiHiveListLock,
1287 InsertTailList (&CmiHiveListHead,
1289 ExReleaseResourceLite (&CmiHiveListLock);
1292 VERIFY_REGISTRY_HIVE(Hive);
1295 Status = CmiConnectHive (KeyObjectAttributes,
1297 if (!NT_SUCCESS(Status))
1299 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status);
1300 // CmiRemoveRegistryHive (Hive);
1303 DPRINT ("CmiLoadHive() done\n");
1310 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive)
1312 if (RegistryHive->Flags & HIVE_POINTER)
1313 return STATUS_UNSUCCESSFUL;
1315 /* Acquire hive list lock exclusively */
1316 ExAcquireResourceExclusiveLite (&CmiHiveListLock,
1319 /* Remove hive from hive list */
1320 RemoveEntryList (&RegistryHive->HiveList);
1322 /* Release hive list lock */
1323 ExReleaseResourceLite (&CmiHiveListLock);
1325 /* Release file names */
1326 RtlFreeUnicodeString (&RegistryHive->HiveFileName);
1327 RtlFreeUnicodeString (&RegistryHive->LogFileName);
1329 /* Release hive bitmap */
1330 ExFreePool (RegistryHive->BitmapBuffer);
1332 /* Release free cell list */
1333 ExFreePool (RegistryHive->FreeList);
1334 ExFreePool (RegistryHive->FreeListOffset);
1336 /* Release hive resource */
1337 ExDeleteResource (&RegistryHive->HiveResource);
1339 /* Release bins and bin list */
1340 CmiFreeHiveBins (RegistryHive);
1341 ExFreePool (RegistryHive->BlockList);
1343 /* Release hive header */
1344 ExFreePool (RegistryHive->HiveHeader);
1347 ExFreePool (RegistryHive);
1349 return STATUS_SUCCESS;
1354 CmiCalcChecksum(PULONG Buffer)
1359 for (i = 0; i < 127; i++)
1367 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive)
1369 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1370 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1371 OBJECT_ATTRIBUTES ObjectAttributes;
1372 IO_STATUS_BLOCK IoStatusBlock;
1374 LARGE_INTEGER FileOffset;
1383 DPRINT("CmiStartLogUpdate() called\n");
1385 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1386 BufferSize = sizeof(HIVE_HEADER) +
1389 BufferSize = ROUND_UP(BufferSize, 4096);
1391 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1393 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool, BufferSize);
1396 DPRINT("ExAllocatePool() failed\n");
1397 return(STATUS_INSUFFICIENT_RESOURCES);
1400 /* Open log file for writing */
1401 InitializeObjectAttributes(&ObjectAttributes,
1402 &RegistryHive->LogFileName,
1407 Status = NtCreateFile(&FileHandle,
1412 FILE_ATTRIBUTE_NORMAL,
1415 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1418 if (!NT_SUCCESS(Status))
1420 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1425 /* Update firt update counter and checksum */
1426 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1427 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1429 /* Copy hive header */
1430 RtlCopyMemory(Buffer,
1431 RegistryHive->HiveHeader,
1432 sizeof(HIVE_HEADER));
1433 Ptr = Buffer + sizeof(HIVE_HEADER);
1440 RegistryHive->DirtyBitMap.Buffer,
1443 /* Write hive block and block bitmap */
1444 FileOffset.QuadPart = 0ULL;
1445 Status = NtWriteFile(FileHandle,
1454 if (!NT_SUCCESS(Status))
1456 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1457 NtClose(FileHandle);
1463 /* Write dirty blocks */
1464 FileOffset.QuadPart = (ULONGLONG)BufferSize;
1468 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1471 if ((BlockIndex == (ULONG)-1) ||
1472 (BlockIndex >= RegistryHive->BlockListSize))
1474 DPRINT("No more set bits\n");
1475 Status = STATUS_SUCCESS;
1479 DPRINT("Block %lu is dirty\n", BlockIndex);
1481 BlockPtr = RegistryHive->BlockList[BlockIndex];
1482 DPRINT("BlockPtr %p\n", BlockPtr);
1483 DPRINT("File offset %I64x\n", FileOffset.QuadPart);
1485 /* Write hive block */
1486 Status = NtWriteFile(FileHandle,
1495 if (!NT_SUCCESS(Status))
1497 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1498 NtClose(FileHandle);
1503 FileOffset.QuadPart += 4096ULL;
1506 /* Truncate log file */
1507 EndOfFileInfo.EndOfFile.QuadPart = FileOffset.QuadPart;
1508 Status = NtSetInformationFile(FileHandle,
1511 sizeof(FILE_END_OF_FILE_INFORMATION),
1512 FileEndOfFileInformation);
1513 if (!NT_SUCCESS(Status))
1515 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1516 NtClose(FileHandle);
1520 FileAllocationInfo.AllocationSize.QuadPart = FileOffset.QuadPart;
1521 Status = NtSetInformationFile(FileHandle,
1523 &FileAllocationInfo,
1524 sizeof(FILE_ALLOCATION_INFORMATION),
1525 FileAllocationInformation);
1526 if (!NT_SUCCESS(Status))
1528 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1529 NtClose(FileHandle);
1533 /* Flush the log file */
1534 Status = NtFlushBuffersFile(FileHandle,
1536 if (!NT_SUCCESS(Status))
1538 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1541 NtClose(FileHandle);
1548 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive)
1550 OBJECT_ATTRIBUTES ObjectAttributes;
1551 IO_STATUS_BLOCK IoStatusBlock;
1553 LARGE_INTEGER FileOffset;
1560 DPRINT("CmiFinishLogUpdate() called\n");
1562 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1563 BufferSize = sizeof(HIVE_HEADER) +
1566 BufferSize = ROUND_UP(BufferSize, 4096);
1568 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1570 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool, BufferSize);
1573 DPRINT("ExAllocatePool() failed\n");
1574 return(STATUS_INSUFFICIENT_RESOURCES);
1577 /* Open log file for writing */
1578 InitializeObjectAttributes(&ObjectAttributes,
1579 &RegistryHive->LogFileName,
1584 Status = NtCreateFile(&FileHandle,
1589 FILE_ATTRIBUTE_NORMAL,
1592 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1595 if (!NT_SUCCESS(Status))
1597 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1602 /* Update first and second update counter and checksum */
1603 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1604 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1605 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1607 /* Copy hive header */
1608 RtlCopyMemory(Buffer,
1609 RegistryHive->HiveHeader,
1610 sizeof(HIVE_HEADER));
1611 Ptr = Buffer + sizeof(HIVE_HEADER);
1613 /* Write empty block bitmap */
1621 /* Write hive block and block bitmap */
1622 FileOffset.QuadPart = 0ULL;
1623 Status = NtWriteFile(FileHandle,
1632 if (!NT_SUCCESS(Status))
1634 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1635 NtClose(FileHandle);
1642 /* Flush the log file */
1643 Status = NtFlushBuffersFile(FileHandle,
1645 if (!NT_SUCCESS(Status))
1647 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1650 NtClose(FileHandle);
1657 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive)
1659 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1660 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1661 OBJECT_ATTRIBUTES ObjectAttributes;
1662 IO_STATUS_BLOCK IoStatusBlock;
1668 DPRINT("CmiCleanupLogUpdate() called\n");
1670 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1671 BufferSize = sizeof(HIVE_HEADER) +
1674 BufferSize = ROUND_UP(BufferSize, 4096);
1676 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1678 /* Open log file for writing */
1679 InitializeObjectAttributes(&ObjectAttributes,
1680 &RegistryHive->LogFileName,
1685 Status = NtCreateFile(&FileHandle,
1690 FILE_ATTRIBUTE_NORMAL,
1693 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1696 if (!NT_SUCCESS(Status))
1698 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1702 /* Truncate log file */
1703 EndOfFileInfo.EndOfFile.QuadPart = (ULONGLONG)BufferSize;
1704 Status = NtSetInformationFile(FileHandle,
1707 sizeof(FILE_END_OF_FILE_INFORMATION),
1708 FileEndOfFileInformation);
1709 if (!NT_SUCCESS(Status))
1711 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1712 NtClose(FileHandle);
1716 FileAllocationInfo.AllocationSize.QuadPart = (ULONGLONG)BufferSize;
1717 Status = NtSetInformationFile(FileHandle,
1719 &FileAllocationInfo,
1720 sizeof(FILE_ALLOCATION_INFORMATION),
1721 FileAllocationInformation);
1722 if (!NT_SUCCESS(Status))
1724 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1725 NtClose(FileHandle);
1729 /* Flush the log file */
1730 Status = NtFlushBuffersFile(FileHandle,
1732 if (!NT_SUCCESS(Status))
1734 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1737 NtClose(FileHandle);
1744 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive)
1746 OBJECT_ATTRIBUTES ObjectAttributes;
1747 IO_STATUS_BLOCK IoStatusBlock;
1749 LARGE_INTEGER FileOffset;
1754 DPRINT("CmiStartHiveUpdate() called\n");
1756 /* Open hive for writing */
1757 InitializeObjectAttributes(&ObjectAttributes,
1758 &RegistryHive->HiveFileName,
1763 Status = NtCreateFile(&FileHandle,
1768 FILE_ATTRIBUTE_NORMAL,
1771 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1774 if (!NT_SUCCESS(Status))
1776 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1780 /* Update firt update counter and checksum */
1781 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1782 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1784 /* Write hive block */
1785 FileOffset.QuadPart = 0ULL;
1786 Status = NtWriteFile(FileHandle,
1791 RegistryHive->HiveHeader,
1792 sizeof(HIVE_HEADER),
1795 if (!NT_SUCCESS(Status))
1797 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1798 NtClose(FileHandle);
1805 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1808 if ((BlockIndex == (ULONG)-1) ||
1809 (BlockIndex >= RegistryHive->BlockListSize))
1811 DPRINT("No more set bits\n");
1812 Status = STATUS_SUCCESS;
1816 DPRINT("Block %lu is dirty\n", BlockIndex);
1818 BlockPtr = RegistryHive->BlockList[BlockIndex];
1819 DPRINT("BlockPtr %p\n", BlockPtr);
1821 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096ULL;
1822 DPRINT("File offset %I64x\n", FileOffset.QuadPart);
1824 /* Write hive block */
1825 Status = NtWriteFile(FileHandle,
1834 if (!NT_SUCCESS(Status))
1836 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1837 NtClose(FileHandle);
1844 Status = NtFlushBuffersFile(FileHandle,
1846 if (!NT_SUCCESS(Status))
1848 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1851 NtClose(FileHandle);
1858 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive)
1860 OBJECT_ATTRIBUTES ObjectAttributes;
1861 IO_STATUS_BLOCK IoStatusBlock;
1862 LARGE_INTEGER FileOffset;
1866 DPRINT("CmiFinishHiveUpdate() called\n");
1868 InitializeObjectAttributes(&ObjectAttributes,
1869 &RegistryHive->HiveFileName,
1874 Status = NtCreateFile(&FileHandle,
1879 FILE_ATTRIBUTE_NORMAL,
1882 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1885 if (!NT_SUCCESS(Status))
1887 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1891 /* Update second update counter and checksum */
1892 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1893 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1894 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1896 /* Write hive block */
1897 FileOffset.QuadPart = 0ULL;
1898 Status = NtWriteFile(FileHandle,
1903 RegistryHive->HiveHeader,
1904 sizeof(HIVE_HEADER),
1907 if (!NT_SUCCESS(Status))
1909 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1910 NtClose(FileHandle);
1914 Status = NtFlushBuffersFile(FileHandle,
1916 if (!NT_SUCCESS(Status))
1918 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1921 NtClose(FileHandle);
1928 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
1932 DPRINT("CmiFlushRegistryHive() called\n");
1934 if (RegistryHive->HiveDirty == FALSE)
1936 return(STATUS_SUCCESS);
1939 DPRINT("Hive '%wZ' is dirty\n",
1940 &RegistryHive->HiveFileName);
1941 DPRINT("Log file: '%wZ'\n",
1942 &RegistryHive->LogFileName);
1944 /* Update hive header modification time */
1945 NtQuerySystemTime(&RegistryHive->HiveHeader->DateModified);
1947 /* Start log update */
1948 Status = CmiStartLogUpdate(RegistryHive);
1949 if (!NT_SUCCESS(Status))
1951 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status);
1955 /* Finish log update */
1956 Status = CmiFinishLogUpdate(RegistryHive);
1957 if (!NT_SUCCESS(Status))
1959 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
1963 /* Start hive update */
1964 Status = CmiStartHiveUpdate(RegistryHive);
1965 if (!NT_SUCCESS(Status))
1967 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status);
1971 /* Finish the hive update */
1972 Status = CmiFinishHiveUpdate(RegistryHive);
1973 if (!NT_SUCCESS(Status))
1975 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status);
1979 /* Cleanup log update */
1980 Status = CmiCleanupLogUpdate(RegistryHive);
1981 if (!NT_SUCCESS(Status))
1983 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
1987 /* Increment hive update counter */
1988 RegistryHive->UpdateCounter++;
1990 /* Clear dirty bitmap and dirty flag */
1991 RtlClearAllBits(&RegistryHive->DirtyBitMap);
1992 RegistryHive->HiveDirty = FALSE;
1994 DPRINT("CmiFlushRegistryHive() done\n");
1996 return(STATUS_SUCCESS);
2001 CmiGetMaxNameLength(PKEY_OBJECT KeyObject)
2003 PHASH_TABLE_CELL HashBlock;
2005 PKEY_CELL CurSubKeyCell;
2011 VERIFY_KEY_OBJECT(KeyObject);
2013 KeyCell = KeyObject->KeyCell;
2014 VERIFY_KEY_CELL(KeyCell);
2017 HashBlock = CmiGetBlock(KeyObject->RegistryHive,
2018 KeyCell->HashTableOffset,
2020 if (HashBlock == NULL)
2022 DPRINT("CmiGetBlock() failed\n");
2026 for (i = 0; i < HashBlock->HashTableSize; i++)
2028 if (HashBlock->Table[i].KeyOffset != 0)
2030 CurSubKeyCell = CmiGetBlock(KeyObject->RegistryHive,
2031 HashBlock->Table[i].KeyOffset,
2033 if (CurSubKeyCell == NULL)
2035 DPRINT("CmiGetBlock() failed\n");
2038 NameSize = CurSubKeyCell->NameSize;
2039 if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED)
2041 NameSize *= sizeof(WCHAR);
2043 if (MaxName < NameSize)
2050 if (KeyObject->RegistryHive != CmiVolatileHive)
2052 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys);
2053 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
2055 CurKey = KeyObject->SubKeys[i];
2056 if (CurKey->RegistryHive == CmiVolatileHive)
2058 CurSubKeyCell = CurKey->KeyCell;
2059 if (CurSubKeyCell == NULL)
2061 DPRINT("CmiGetBlock() failed\n");
2064 NameSize = CurSubKeyCell->NameSize;
2065 if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED)
2067 NameSize *= sizeof(WCHAR);
2069 if (MaxName < NameSize)
2082 CmiGetMaxClassLength(PKEY_OBJECT KeyObject)
2084 PHASH_TABLE_CELL HashBlock;
2086 PKEY_CELL CurSubKeyCell;
2091 VERIFY_KEY_OBJECT(KeyObject);
2093 KeyCell = KeyObject->KeyCell;
2094 VERIFY_KEY_CELL(KeyCell);
2097 HashBlock = CmiGetBlock(KeyObject->RegistryHive,
2098 KeyCell->HashTableOffset,
2100 if (HashBlock == NULL)
2102 DPRINT("CmiGetBlock() failed\n");
2106 for (i = 0; i < HashBlock->HashTableSize; i++)
2108 if (HashBlock->Table[i].KeyOffset != 0)
2110 CurSubKeyCell = CmiGetBlock(KeyObject->RegistryHive,
2111 HashBlock->Table[i].KeyOffset,
2113 if (CurSubKeyCell == NULL)
2115 DPRINT("CmiGetBlock() failed\n");
2119 if (MaxClass < CurSubKeyCell->ClassSize)
2121 MaxClass = CurSubKeyCell->ClassSize;
2126 if (KeyObject->RegistryHive != CmiVolatileHive)
2128 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys);
2129 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
2131 CurKey = KeyObject->SubKeys[i];
2132 if (CurKey->RegistryHive == CmiVolatileHive)
2134 CurSubKeyCell = CurKey->KeyCell;
2135 if (CurSubKeyCell == NULL)
2137 DPRINT("CmiGetBlock() failed\n");
2140 if (MaxClass < CurSubKeyCell->ClassSize)
2142 MaxClass = CurSubKeyCell->ClassSize;
2153 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive,
2156 PVALUE_LIST_CELL ValueListCell;
2157 PVALUE_CELL CurValueCell;
2162 VERIFY_KEY_CELL(KeyCell);
2165 ValueListCell = CmiGetBlock(RegistryHive,
2166 KeyCell->ValuesOffset,
2168 if (ValueListCell == NULL)
2170 DPRINT("CmiGetBlock() failed\n");
2174 for (i = 0; i < KeyCell->NumberOfValues; i++)
2176 CurValueCell = CmiGetBlock (RegistryHive,
2177 ValueListCell->Values[i],
2179 if (CurValueCell == NULL)
2181 DPRINT("CmiGetBlock() failed\n");
2184 if (CurValueCell != NULL)
2186 Size = CurValueCell->NameSize;
2187 if (CurValueCell->Flags & REG_VALUE_NAME_PACKED)
2189 Size *= sizeof(WCHAR);
2191 if (MaxValueName < Size)
2193 MaxValueName = Size;
2198 return MaxValueName;
2203 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive,
2206 PVALUE_LIST_CELL ValueListCell;
2207 PVALUE_CELL CurValueCell;
2211 VERIFY_KEY_CELL(KeyCell);
2214 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2215 if (ValueListCell == NULL)
2220 for (i = 0; i < KeyCell->NumberOfValues; i++)
2222 CurValueCell = CmiGetBlock(RegistryHive,
2223 ValueListCell->Values[i],NULL);
2224 if ((CurValueCell != NULL) &&
2225 (MaxValueData < (CurValueCell->DataSize & LONG_MAX)))
2227 MaxValueData = CurValueCell->DataSize & LONG_MAX;
2231 return MaxValueData;
2236 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
2237 IN PKEY_CELL KeyCell,
2238 OUT PKEY_CELL *SubKeyCell,
2239 OUT BLOCK_OFFSET *BlockOffset,
2240 IN PUNICODE_STRING KeyName,
2241 IN ACCESS_MASK DesiredAccess,
2242 IN ULONG Attributes)
2244 PHASH_TABLE_CELL HashBlock;
2245 PKEY_CELL CurSubKeyCell;
2248 VERIFY_KEY_CELL(KeyCell);
2250 DPRINT("Scanning for sub key %wZ\n", KeyName);
2252 assert(RegistryHive);
2256 /* The key does not have any subkeys */
2257 if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
2259 return STATUS_SUCCESS;
2262 /* Get hash table */
2263 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
2264 if (HashBlock == NULL)
2266 DPRINT("CmiGetBlock() failed\n");
2267 return STATUS_UNSUCCESSFUL;
2270 for (i = 0; (i < KeyCell->NumberOfSubKeys) && (i < HashBlock->HashTableSize); i++)
2272 if (Attributes & OBJ_CASE_INSENSITIVE)
2274 if (HashBlock->Table[i].KeyOffset != 0 &&
2275 HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1 &&
2276 (HashBlock->Table[i].HashValue == 0 ||
2277 CmiCompareHashI(KeyName, (PCHAR)&HashBlock->Table[i].HashValue)))
2279 CurSubKeyCell = CmiGetBlock(RegistryHive,
2280 HashBlock->Table[i].KeyOffset,
2282 if (CurSubKeyCell == NULL)
2284 DPRINT("CmiGetBlock() failed\n");
2285 return STATUS_UNSUCCESSFUL;
2288 if (CmiCompareKeyNamesI(KeyName, CurSubKeyCell))
2290 *SubKeyCell = CurSubKeyCell;
2291 *BlockOffset = HashBlock->Table[i].KeyOffset;
2298 if (HashBlock->Table[i].KeyOffset != 0 &&
2299 HashBlock->Table[i].KeyOffset != (ULONG_PTR) -1 &&
2300 (HashBlock->Table[i].HashValue == 0 ||
2301 CmiCompareHash(KeyName, (PCHAR)&HashBlock->Table[i].HashValue)))
2303 CurSubKeyCell = CmiGetBlock(RegistryHive,
2304 HashBlock->Table[i].KeyOffset,
2306 if (CurSubKeyCell == NULL)
2308 DPRINT("CmiGetBlock() failed\n");
2309 return STATUS_UNSUCCESSFUL;
2312 if (CmiCompareKeyNames(KeyName, CurSubKeyCell))
2314 *SubKeyCell = CurSubKeyCell;
2315 *BlockOffset = HashBlock->Table[i].KeyOffset;
2322 return STATUS_SUCCESS;
2327 CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
2330 PUNICODE_STRING SubKeyName,
2332 PUNICODE_STRING Class,
2333 ULONG CreateOptions)
2335 PHASH_TABLE_CELL NewHashBlock;
2336 PHASH_TABLE_CELL HashBlock;
2337 BLOCK_OFFSET NKBOffset;
2338 PKEY_CELL NewKeyCell;
2347 KeyCell = Parent->KeyCell;
2349 VERIFY_KEY_CELL(KeyCell);
2351 /* Skip leading backslash */
2352 if (SubKeyName->Buffer[0] == L'\\')
2354 NamePtr = &SubKeyName->Buffer[1];
2355 NameSize = SubKeyName->Length - sizeof(WCHAR);
2359 NamePtr = SubKeyName->Buffer;
2360 NameSize = SubKeyName->Length;
2363 /* Check whether key name can be packed */
2365 for (i = 0; i < NameSize / sizeof(WCHAR); i++)
2367 if (NamePtr[i] & 0xFF00)
2374 /* Adjust name size */
2377 NameSize = NameSize / sizeof(WCHAR);
2380 DPRINT("Key %S Length %lu %s\n", NamePtr, NameSize, (Packable)?"True":"False");
2382 Status = STATUS_SUCCESS;
2384 NewBlockSize = sizeof(KEY_CELL) + NameSize;
2385 Status = CmiAllocateBlock(RegistryHive,
2386 (PVOID) &NewKeyCell,
2389 if (NewKeyCell == NULL)
2391 Status = STATUS_INSUFFICIENT_RESOURCES;
2395 NewKeyCell->Id = REG_KEY_CELL_ID;
2396 NewKeyCell->Flags = 0;
2397 NtQuerySystemTime(&NewKeyCell->LastWriteTime);
2398 NewKeyCell->ParentKeyOffset = -1;
2399 NewKeyCell->NumberOfSubKeys = 0;
2400 NewKeyCell->HashTableOffset = -1;
2401 NewKeyCell->NumberOfValues = 0;
2402 NewKeyCell->ValuesOffset = -1;
2403 NewKeyCell->SecurityKeyOffset = -1;
2404 NewKeyCell->ClassNameOffset = -1;
2406 /* Pack the key name */
2407 NewKeyCell->NameSize = NameSize;
2410 NewKeyCell->Flags |= REG_KEY_NAME_PACKED;
2411 for (i = 0; i < NameSize; i++)
2413 NewKeyCell->Name[i] = (CHAR)(NamePtr[i] & 0x00FF);
2418 RtlCopyMemory(NewKeyCell->Name,
2423 VERIFY_KEY_CELL(NewKeyCell);
2429 NewKeyCell->ClassSize = Class->Length + sizeof(WCHAR);
2430 Status = CmiAllocateBlock(RegistryHive,
2432 NewKeyCell->ClassSize,
2433 &NewKeyCell->ClassNameOffset);
2434 wcsncpy((PWSTR)pClass->Data,
2437 ((PWSTR) (pClass->Data))[Class->Length] = 0;
2441 if (!NT_SUCCESS(Status))
2446 SubKey->KeyCell = NewKeyCell;
2447 SubKey->BlockOffset = NKBOffset;
2449 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2450 if (IsPointerHive(RegistryHive) && (!IsPointerHive(Parent->RegistryHive)))
2455 if (KeyCell->HashTableOffset == (ULONG_PTR) -1)
2457 Status = CmiAllocateHashTableBlock(RegistryHive,
2459 &KeyCell->HashTableOffset,
2460 REG_INIT_HASH_TABLE_SIZE);
2461 if (!NT_SUCCESS(Status))
2468 HashBlock = CmiGetBlock(RegistryHive,
2469 KeyCell->HashTableOffset,
2471 if (HashBlock == NULL)
2473 DPRINT("CmiGetBlock() failed\n");
2474 return STATUS_UNSUCCESSFUL;
2477 if (((KeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
2479 BLOCK_OFFSET HTOffset;
2481 /* Reallocate the hash table block */
2482 Status = CmiAllocateHashTableBlock(RegistryHive,
2485 HashBlock->HashTableSize +
2486 REG_EXTEND_HASH_TABLE_SIZE);
2487 if (!NT_SUCCESS(Status))
2492 RtlZeroMemory(&NewHashBlock->Table[0],
2493 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
2494 RtlCopyMemory(&NewHashBlock->Table[0],
2495 &HashBlock->Table[0],
2496 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
2497 CmiDestroyBlock(RegistryHive,
2499 KeyCell->HashTableOffset);
2500 KeyCell->HashTableOffset = HTOffset;
2501 HashBlock = NewHashBlock;
2505 Status = CmiAddKeyToHashTable(RegistryHive,
2509 if (NT_SUCCESS(Status))
2511 KeyCell->NumberOfSubKeys++;
2519 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
2520 PKEY_OBJECT ParentKey,
2523 PHASH_TABLE_CELL HashBlock;
2524 PVALUE_LIST_CELL ValueList;
2525 PVALUE_CELL ValueCell;
2526 PDATA_CELL DataCell;
2529 DPRINT("CmiRemoveSubKey() called\n");
2531 /* Remove all values */
2532 if (SubKey->KeyCell->NumberOfValues != 0)
2534 /* Get pointer to the value list cell */
2535 ValueList = CmiGetBlock(RegistryHive,
2536 SubKey->KeyCell->ValuesOffset,
2538 if (ValueList == NULL)
2540 DPRINT("CmiGetBlock() failed\n");
2541 return STATUS_UNSUCCESSFUL;
2544 if (ValueList != NULL)
2546 /* Enumerate all values */
2547 for (i = 0; i < SubKey->KeyCell->NumberOfValues; i++)
2549 /* Get pointer to value cell */
2550 ValueCell = CmiGetBlock(RegistryHive,
2551 ValueList->Values[i],
2553 if (ValueCell != NULL)
2555 if (ValueCell->DataSize > 4)
2557 DataCell = CmiGetBlock(RegistryHive,
2558 ValueCell->DataOffset,
2560 if (DataCell == NULL)
2562 DPRINT("CmiGetBlock() failed\n");
2563 return STATUS_UNSUCCESSFUL;
2566 if (DataCell != NULL)
2568 /* Destroy data cell */
2569 CmiDestroyBlock(RegistryHive,
2571 ValueCell->DataOffset);
2575 /* Destroy value cell */
2576 CmiDestroyBlock(RegistryHive,
2578 ValueList->Values[i]);
2583 /* Destroy value list cell */
2584 CmiDestroyBlock(RegistryHive,
2586 SubKey->KeyCell->ValuesOffset);
2588 SubKey->KeyCell->NumberOfValues = 0;
2589 SubKey->KeyCell->ValuesOffset = -1;
2592 /* Remove the key from the parent key's hash block */
2593 if (ParentKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2595 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset)
2596 HashBlock = CmiGetBlock(ParentKey->RegistryHive,
2597 ParentKey->KeyCell->HashTableOffset,
2599 if (HashBlock == NULL)
2601 DPRINT("CmiGetBlock() failed\n");
2602 return STATUS_UNSUCCESSFUL;
2604 DPRINT("ParentKey HashBlock %p\n", HashBlock)
2605 if (HashBlock != NULL)
2607 CmiRemoveKeyFromHashTable(ParentKey->RegistryHive,
2609 SubKey->BlockOffset);
2610 CmiMarkBlockDirty(ParentKey->RegistryHive,
2611 ParentKey->KeyCell->HashTableOffset);
2615 /* Remove the key's hash block */
2616 if (SubKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2618 DPRINT("SubKey HashTableOffset %lx\n", SubKey->KeyCell->HashTableOffset)
2619 HashBlock = CmiGetBlock(RegistryHive,
2620 SubKey->KeyCell->HashTableOffset,
2622 if (HashBlock == NULL)
2624 DPRINT("CmiGetBlock() failed\n");
2625 return STATUS_UNSUCCESSFUL;
2627 DPRINT("SubKey HashBlock %p\n", HashBlock)
2628 if (HashBlock != NULL)
2630 CmiDestroyBlock(RegistryHive,
2632 SubKey->KeyCell->HashTableOffset);
2633 SubKey->KeyCell->HashTableOffset = -1;
2637 /* Decrement the number of the parent key's sub keys */
2638 if (ParentKey != NULL)
2640 DPRINT("ParentKey %p\n", ParentKey)
2641 ParentKey->KeyCell->NumberOfSubKeys--;
2643 /* Remove the parent key's hash table */
2644 if (ParentKey->KeyCell->NumberOfSubKeys == 0)
2646 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset)
2647 HashBlock = CmiGetBlock(ParentKey->RegistryHive,
2648 ParentKey->KeyCell->HashTableOffset,
2650 if (HashBlock == NULL)
2652 DPRINT("CmiGetBlock() failed\n");
2653 return STATUS_UNSUCCESSFUL;
2655 DPRINT("ParentKey HashBlock %p\n", HashBlock)
2656 if (HashBlock != NULL)
2658 CmiDestroyBlock(ParentKey->RegistryHive,
2660 ParentKey->KeyCell->HashTableOffset);
2661 ParentKey->KeyCell->HashTableOffset = -1;
2665 NtQuerySystemTime(&ParentKey->KeyCell->LastWriteTime);
2666 CmiMarkBlockDirty(ParentKey->RegistryHive,
2667 ParentKey->BlockOffset);
2670 /* Destroy key cell */
2671 CmiDestroyBlock(RegistryHive,
2673 SubKey->BlockOffset);
2674 SubKey->BlockOffset = -1;
2675 SubKey->KeyCell = NULL;
2677 return(STATUS_SUCCESS);
2682 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
2683 IN PKEY_CELL KeyCell,
2684 IN PUNICODE_STRING ValueName,
2685 OUT PVALUE_CELL *ValueCell,
2686 OUT BLOCK_OFFSET *VBOffset)
2688 PVALUE_LIST_CELL ValueListCell;
2689 PVALUE_CELL CurValueCell;
2694 /* The key does not have any values */
2695 if (KeyCell->ValuesOffset == (BLOCK_OFFSET)-1)
2697 return STATUS_SUCCESS;
2700 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2701 if (ValueListCell == NULL)
2703 DPRINT("ValueListCell is NULL\n");
2704 return STATUS_UNSUCCESSFUL;
2707 VERIFY_VALUE_LIST_CELL(ValueListCell);
2709 for (i = 0; i < KeyCell->NumberOfValues; i++)
2711 CurValueCell = CmiGetBlock(RegistryHive,
2712 ValueListCell->Values[i],
2714 if (CurValueCell == NULL)
2716 DPRINT("CmiGetBlock() failed\n");
2717 return STATUS_UNSUCCESSFUL;
2720 if ((CurValueCell != NULL) &&
2721 CmiComparePackedNames(ValueName,
2723 CurValueCell->NameSize,
2724 CurValueCell->Flags & REG_VALUE_NAME_PACKED))
2726 *ValueCell = CurValueCell;
2728 *VBOffset = ValueListCell->Values[i];
2729 //DPRINT("Found value %s\n", ValueName);
2734 return STATUS_SUCCESS;
2739 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
2740 IN PKEY_CELL KeyCell,
2742 OUT PVALUE_CELL *ValueCell)
2744 PVALUE_LIST_CELL ValueListCell;
2745 PVALUE_CELL CurValueCell;
2749 if (KeyCell->ValuesOffset == (BLOCK_OFFSET)-1)
2751 return STATUS_NO_MORE_ENTRIES;
2754 if (Index >= KeyCell->NumberOfValues)
2756 return STATUS_NO_MORE_ENTRIES;
2760 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2761 if (ValueListCell == NULL)
2763 DPRINT("CmiGetBlock() failed\n");
2764 return STATUS_UNSUCCESSFUL;
2767 VERIFY_VALUE_LIST_CELL(ValueListCell);
2770 CurValueCell = CmiGetBlock(RegistryHive,
2771 ValueListCell->Values[Index],
2773 if (CurValueCell == NULL)
2775 DPRINT("CmiGetBlock() failed\n");
2776 return STATUS_UNSUCCESSFUL;
2779 *ValueCell = CurValueCell;
2781 return STATUS_SUCCESS;
2786 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
2787 IN PKEY_CELL KeyCell,
2788 IN PUNICODE_STRING ValueName,
2789 OUT PVALUE_CELL *pValueCell,
2790 OUT BLOCK_OFFSET *pVBOffset)
2792 PVALUE_LIST_CELL NewValueListCell;
2793 PVALUE_LIST_CELL ValueListCell;
2794 PVALUE_CELL NewValueCell;
2795 BLOCK_OFFSET VLBOffset;
2796 BLOCK_OFFSET VBOffset;
2799 Status = CmiAllocateValueCell(RegistryHive,
2803 if (!NT_SUCCESS(Status))
2808 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG)KeyCell->ValuesOffset);
2810 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2812 if (ValueListCell == NULL)
2814 Status = CmiAllocateBlock(RegistryHive,
2815 (PVOID) &ValueListCell,
2816 sizeof(BLOCK_OFFSET) * 3,
2819 if (!NT_SUCCESS(Status))
2821 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
2824 KeyCell->ValuesOffset = VLBOffset;
2826 else if (KeyCell->NumberOfValues >=
2827 (((ULONG)ABS_VALUE(ValueListCell->CellSize) - 4) / sizeof(BLOCK_OFFSET)))
2829 Status = CmiAllocateBlock(RegistryHive,
2830 (PVOID) &NewValueListCell,
2831 (KeyCell->NumberOfValues + REG_VALUE_LIST_CELL_MULTIPLE) *
2832 sizeof(BLOCK_OFFSET),
2834 if (!NT_SUCCESS(Status))
2836 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
2840 RtlCopyMemory(&NewValueListCell->Values[0],
2841 &ValueListCell->Values[0],
2842 sizeof(BLOCK_OFFSET) * KeyCell->NumberOfValues);
2843 CmiDestroyBlock(RegistryHive, ValueListCell, KeyCell->ValuesOffset);
2844 KeyCell->ValuesOffset = VLBOffset;
2845 ValueListCell = NewValueListCell;
2848 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2849 KeyCell->NumberOfValues,
2850 (ULONG)ABS_VALUE(ValueListCell->CellSize),
2851 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - 4) / sizeof(BLOCK_OFFSET),
2852 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - 4) / sizeof(BLOCK_OFFSET));
2854 ValueListCell->Values[KeyCell->NumberOfValues] = VBOffset;
2855 KeyCell->NumberOfValues++;
2857 *pValueCell = NewValueCell;
2858 *pVBOffset = VBOffset;
2860 return STATUS_SUCCESS;
2865 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
2866 IN PKEY_CELL KeyCell,
2867 IN BLOCK_OFFSET KeyCellOffset,
2868 IN PUNICODE_STRING ValueName)
2870 PVALUE_LIST_CELL ValueListCell;
2871 PVALUE_CELL CurValueCell;
2874 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2876 if (ValueListCell == NULL)
2878 DPRINT("CmiGetBlock() failed\n");
2879 return STATUS_SUCCESS;
2882 VERIFY_VALUE_LIST_CELL(ValueListCell);
2884 for (i = 0; i < KeyCell->NumberOfValues; i++)
2886 CurValueCell = CmiGetBlock(RegistryHive, ValueListCell->Values[i], NULL);
2887 if (CurValueCell == NULL)
2889 DPRINT("CmiGetBlock() failed\n");
2890 return STATUS_UNSUCCESSFUL;
2893 if ((CurValueCell != NULL) &&
2894 CmiComparePackedNames(ValueName,
2896 CurValueCell->NameSize,
2897 CurValueCell->Flags & REG_VALUE_NAME_PACKED))
2899 CmiDestroyValueCell(RegistryHive, CurValueCell, ValueListCell->Values[i]);
2901 if ((KeyCell->NumberOfValues - 1) < i)
2903 RtlCopyMemory(&ValueListCell->Values[i],
2904 &ValueListCell->Values[i + 1],
2905 sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues - 1 - i));
2909 RtlZeroMemory(&ValueListCell->Values[i], sizeof(BLOCK_OFFSET));
2912 KeyCell->NumberOfValues -= 1;
2917 if (KeyCell->NumberOfValues == 0)
2919 CmiDestroyBlock(RegistryHive,
2921 KeyCell->ValuesOffset);
2925 CmiMarkBlockDirty(RegistryHive,
2926 KeyCell->ValuesOffset);
2929 CmiMarkBlockDirty(RegistryHive,
2932 return STATUS_SUCCESS;
2937 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive,
2938 OUT PHASH_TABLE_CELL *HashBlock,
2939 OUT BLOCK_OFFSET *HBOffset,
2940 IN ULONG HashTableSize)
2942 PHASH_TABLE_CELL NewHashBlock;
2946 Status = STATUS_SUCCESS;
2948 NewHashSize = sizeof(HASH_TABLE_CELL) +
2949 (HashTableSize - 1) * sizeof(HASH_RECORD);
2950 Status = CmiAllocateBlock(RegistryHive,
2951 (PVOID*) &NewHashBlock,
2955 if ((NewHashBlock == NULL) || (!NT_SUCCESS(Status)))
2957 Status = STATUS_INSUFFICIENT_RESOURCES;
2961 NewHashBlock->Id = REG_HASH_TABLE_BLOCK_ID;
2962 NewHashBlock->HashTableSize = HashTableSize;
2963 *HashBlock = NewHashBlock;
2971 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
2972 PHASH_TABLE_CELL HashBlock,
2975 BLOCK_OFFSET KeyOffset;
2978 if (HashBlock == NULL)
2981 if (IsPointerHive(RegistryHive))
2983 KeyCell = (PKEY_CELL) HashBlock->Table[Index].KeyOffset;
2987 KeyOffset = HashBlock->Table[Index].KeyOffset;
2988 KeyCell = CmiGetBlock(RegistryHive, KeyOffset, NULL);
2996 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
2997 PHASH_TABLE_CELL HashBlock,
2998 PKEY_CELL NewKeyCell,
2999 BLOCK_OFFSET NKBOffset)
3003 for (i = 0; i < HashBlock->HashTableSize; i++)
3005 if (HashBlock->Table[i].KeyOffset == 0)
3007 HashBlock->Table[i].KeyOffset = NKBOffset;
3008 HashBlock->Table[i].HashValue = 0;
3009 if (NewKeyCell->Flags & REG_KEY_NAME_PACKED)
3011 RtlCopyMemory(&HashBlock->Table[i].HashValue,
3013 min(NewKeyCell->NameSize, 4));
3015 return STATUS_SUCCESS;
3019 return STATUS_UNSUCCESSFUL;
3024 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive,
3025 PHASH_TABLE_CELL HashBlock,
3026 BLOCK_OFFSET NKBOffset)
3030 for (i = 0; i < HashBlock->HashTableSize; i++)
3032 if (HashBlock->Table[i].KeyOffset == NKBOffset)
3034 HashBlock->Table[i].KeyOffset = 0;
3035 HashBlock->Table[i].HashValue = 0;
3036 return STATUS_SUCCESS;
3040 return STATUS_UNSUCCESSFUL;
3045 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
3046 PVALUE_CELL *ValueCell,
3047 BLOCK_OFFSET *VBOffset,
3048 IN PUNICODE_STRING ValueName)
3050 PVALUE_CELL NewValueCell;
3056 Status = STATUS_SUCCESS;
3058 NameSize = CmiGetPackedNameLength(ValueName,
3061 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName->Length, NameSize);
3063 Status = CmiAllocateBlock(RegistryHive,
3064 (PVOID*) &NewValueCell,
3065 sizeof(VALUE_CELL) + NameSize,
3067 if ((NewValueCell == NULL) || (!NT_SUCCESS(Status)))
3069 Status = STATUS_INSUFFICIENT_RESOURCES;
3073 NewValueCell->Id = REG_VALUE_CELL_ID;
3074 NewValueCell->NameSize = NameSize;
3077 /* Pack the value name */
3078 for (i = 0; i < NameSize; i++)
3079 NewValueCell->Name[i] = (CHAR)ValueName->Buffer[i];
3080 NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
3084 /* Copy the value name */
3085 RtlCopyMemory(NewValueCell->Name,
3088 NewValueCell->Flags = 0;
3090 NewValueCell->DataType = 0;
3091 NewValueCell->DataSize = 0;
3092 NewValueCell->DataOffset = 0xffffffff;
3093 *ValueCell = NewValueCell;
3101 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
3102 PVALUE_CELL ValueCell,
3103 BLOCK_OFFSET VBOffset)
3109 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell, VBOffset);
3111 VERIFY_VALUE_CELL(ValueCell);
3113 /* Destroy the data cell */
3114 if (ValueCell->DataSize > 4)
3116 pBlock = CmiGetBlock(RegistryHive, ValueCell->DataOffset, &pBin);
3119 DPRINT("CmiGetBlock() failed\n");
3120 return STATUS_UNSUCCESSFUL;
3123 Status = CmiDestroyBlock(RegistryHive, pBlock, ValueCell->DataOffset);
3124 if (!NT_SUCCESS(Status))
3129 /* Update time of heap */
3130 if (!IsNoFileHive(RegistryHive))
3131 NtQuerySystemTime(&pBin->DateModified);
3134 /* Destroy the value cell */
3135 Status = CmiDestroyBlock(RegistryHive, ValueCell, VBOffset);
3137 /* Update time of heap */
3138 if (!IsNoFileHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
3140 NtQuerySystemTime(&pBin->DateModified);
3148 CmiAddBin(PREGISTRY_HIVE RegistryHive,
3150 BLOCK_OFFSET *NewBlockOffset)
3152 PCELL_HEADER tmpBlock;
3153 PHBIN * tmpBlockList;
3156 tmpBin = ExAllocatePool(PagedPool, REG_BLOCK_SIZE);
3159 return STATUS_INSUFFICIENT_RESOURCES;
3162 tmpBin->BlockId = REG_BIN_ID;
3163 tmpBin->BlockOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
3164 RegistryHive->FileSize += REG_BLOCK_SIZE;
3165 tmpBin->BlockSize = REG_BLOCK_SIZE;
3166 tmpBin->Unused1 = 0;
3167 ZwQuerySystemTime(&tmpBin->DateModified);
3168 tmpBin->Unused2 = 0;
3170 /* Increase size of list of blocks */
3171 tmpBlockList = ExAllocatePool(NonPagedPool,
3172 sizeof(PHBIN *) * (RegistryHive->BlockListSize + 1));
3173 if (tmpBlockList == NULL)
3176 return STATUS_INSUFFICIENT_RESOURCES;
3179 if (RegistryHive->BlockListSize > 0)
3181 RtlCopyMemory (tmpBlockList,
3182 RegistryHive->BlockList,
3183 sizeof(PHBIN *)*(RegistryHive->BlockListSize));
3184 ExFreePool(RegistryHive->BlockList);
3187 RegistryHive->BlockList = tmpBlockList;
3188 RegistryHive->BlockList[RegistryHive->BlockListSize] = tmpBin;
3189 RegistryHive->BlockListSize++;
3191 /* Initialize a free block in this heap : */
3192 tmpBlock = (PCELL_HEADER)((ULONG_PTR) tmpBin + REG_HBIN_DATA_OFFSET);
3193 tmpBlock->CellSize = (REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET);
3195 /* Grow bitmap if necessary */
3196 if (IsNoFileHive(RegistryHive) &&
3197 (RegistryHive->BlockListSize % (sizeof(ULONG) * 8) == 0))
3199 PULONG BitmapBuffer;
3202 DPRINT("Grow hive bitmap\n");
3204 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3205 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
3206 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
3207 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
3208 BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
3210 RtlZeroMemory(BitmapBuffer, BitmapSize);
3211 RtlCopyMemory(BitmapBuffer,
3212 RegistryHive->DirtyBitMap.Buffer,
3213 RegistryHive->DirtyBitMap.SizeOfBitMap);
3214 ExFreePool(RegistryHive->BitmapBuffer);
3215 RegistryHive->BitmapBuffer = BitmapBuffer;
3216 RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
3217 RegistryHive->BitmapBuffer,
3221 *NewBlock = (PVOID) tmpBlock;
3224 *NewBlockOffset = tmpBin->BlockOffset + REG_HBIN_DATA_OFFSET;
3226 /* Mark new bin dirty */
3227 CmiMarkBinDirty(RegistryHive,
3228 tmpBin->BlockOffset);
3230 return STATUS_SUCCESS;
3235 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive,
3238 BLOCK_OFFSET * pBlockOffset)
3240 PCELL_HEADER NewBlock;
3246 Status = STATUS_SUCCESS;
3248 /* Round to 16 bytes multiple */
3249 BlockSize = (BlockSize + sizeof(DWORD) + 15) & 0xfffffff0;
3251 /* Handle volatile hives first */
3252 if (IsPointerHive(RegistryHive))
3254 NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
3256 if (NewBlock == NULL)
3258 Status = STATUS_INSUFFICIENT_RESOURCES;
3262 RtlZeroMemory(NewBlock, BlockSize);
3263 NewBlock->CellSize = BlockSize;
3266 *pBlockOffset = (BLOCK_OFFSET) NewBlock;
3271 /* first search in free blocks */
3273 for (i = 0; i < RegistryHive->FreeListSize; i++)
3275 if (RegistryHive->FreeList[i]->CellSize >= BlockSize)
3277 NewBlock = RegistryHive->FreeList[i];
3279 *pBlockOffset = RegistryHive->FreeListOffset[i];
3281 /* Update time of heap */
3282 Temp = CmiGetBlock(RegistryHive, RegistryHive->FreeListOffset[i], &pBin);
3285 DPRINT("CmiGetBlock() failed\n");
3286 return STATUS_UNSUCCESSFUL;
3291 NtQuerySystemTime(&pBin->DateModified);
3292 CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]);
3295 if ((i + 1) < RegistryHive->FreeListSize)
3297 RtlMoveMemory(&RegistryHive->FreeList[i],
3298 &RegistryHive->FreeList[i + 1],
3299 sizeof(RegistryHive->FreeList[0])
3300 * (RegistryHive->FreeListSize - i - 1));
3301 RtlMoveMemory(&RegistryHive->FreeListOffset[i],
3302 &RegistryHive->FreeListOffset[i + 1],
3303 sizeof(RegistryHive->FreeListOffset[0])
3304 * (RegistryHive->FreeListSize - i - 1));
3306 RegistryHive->FreeListSize--;
3311 /* Need to extend hive file : */
3312 if (NewBlock == NULL)
3314 /* Add a new block */
3315 Status = CmiAddBin(RegistryHive, (PVOID *) &NewBlock , pBlockOffset);
3318 if (NT_SUCCESS(Status))
3322 /* Split the block in two parts */
3323 if (NewBlock->CellSize > BlockSize)
3325 NewBlock = (PCELL_HEADER) ((ULONG_PTR) NewBlock+BlockSize);
3326 NewBlock->CellSize = ((PCELL_HEADER) (*Block))->CellSize - BlockSize;
3327 CmiAddFree(RegistryHive,
3329 *pBlockOffset + BlockSize,
3331 CmiMarkBlockDirty(RegistryHive,
3332 *pBlockOffset + BlockSize);
3334 else if (NewBlock->CellSize < BlockSize)
3336 return(STATUS_UNSUCCESSFUL);
3339 RtlZeroMemory(*Block, BlockSize);
3340 ((PCELL_HEADER) (*Block))->CellSize = -BlockSize;
3349 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive,
3351 BLOCK_OFFSET Offset)
3356 Status = STATUS_SUCCESS;
3358 if (IsPointerHive(RegistryHive))
3364 PCELL_HEADER pFree = Block;
3366 if (pFree->CellSize < 0)
3367 pFree->CellSize = -pFree->CellSize;
3369 /* Clear block (except the block size) */
3370 RtlZeroMemory(((PVOID)pFree) + sizeof(ULONG),
3371 pFree->CellSize - sizeof(ULONG));
3373 /* Add block to the list of free blocks */
3374 CmiAddFree(RegistryHive, Block, Offset, TRUE);
3376 /* Update time of heap */
3377 if (!IsNoFileHive(RegistryHive) && CmiGetBlock(RegistryHive, Offset,&pBin))
3378 NtQuerySystemTime(&pBin->DateModified);
3380 CmiMarkBlockDirty(RegistryHive, Offset);
3388 CmiMergeFree(PREGISTRY_HIVE RegistryHive,
3389 PCELL_HEADER FreeBlock,
3390 BLOCK_OFFSET FreeOffset)
3392 BLOCK_OFFSET BlockOffset;
3393 BLOCK_OFFSET BinOffset;
3399 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3400 FreeBlock, FreeOffset, FreeBlock->CellSize);
3402 CmiGetBlock(RegistryHive,
3405 DPRINT("Bin %p\n", Bin);
3409 BinOffset = Bin->BlockOffset;
3410 BinSize = Bin->BlockSize;
3411 DPRINT("Bin %p Offset %lx Size %lx\n", Bin, BinOffset, BinSize);
3413 for (i = 0; i < RegistryHive->FreeListSize; i++)
3415 BlockOffset = RegistryHive->FreeListOffset[i];
3416 BlockSize = RegistryHive->FreeList[i]->CellSize;
3417 if (BlockOffset > BinOffset &&
3418 BlockOffset < BinOffset + BinSize)
3420 DPRINT("Free block: Offset %lx Size %lx\n",
3421 BlockOffset, BlockSize);
3423 if ((i < (RegistryHive->FreeListSize - 1)) &&
3424 (BlockOffset + BlockSize == FreeOffset) &&
3425 (FreeOffset + FreeBlock->CellSize == RegistryHive->FreeListOffset[i + 1]))
3427 DPRINT("Merge current block with previous and next block\n");
3429 RegistryHive->FreeList[i]->CellSize +=
3430 (FreeBlock->CellSize + RegistryHive->FreeList[i + 1]->CellSize);
3432 FreeBlock->CellSize = 0;
3433 RegistryHive->FreeList[i + 1]->CellSize = 0;
3436 if ((i + 2) < RegistryHive->FreeListSize)
3438 RtlMoveMemory(&RegistryHive->FreeList[i + 1],
3439 &RegistryHive->FreeList[i + 2],
3440 sizeof(RegistryHive->FreeList[0])
3441 * (RegistryHive->FreeListSize - i - 2));
3442 RtlMoveMemory(&RegistryHive->FreeListOffset[i + 1],
3443 &RegistryHive->FreeListOffset[i + 2],
3444 sizeof(RegistryHive->FreeListOffset[0])
3445 * (RegistryHive->FreeListSize - i - 2));
3447 RegistryHive->FreeListSize--;
3449 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3453 else if (BlockOffset + BlockSize == FreeOffset)
3455 DPRINT("Merge current block with previous block\n");
3457 RegistryHive->FreeList[i]->CellSize += FreeBlock->CellSize;
3458 FreeBlock->CellSize = 0;
3460 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3464 else if (FreeOffset + FreeBlock->CellSize == BlockOffset)
3466 DPRINT("Merge current block with next block\n");
3468 FreeBlock->CellSize += RegistryHive->FreeList[i]->CellSize;
3469 RegistryHive->FreeList[i]->CellSize = 0;
3470 RegistryHive->FreeList[i] = FreeBlock;
3471 RegistryHive->FreeListOffset[i] = FreeOffset;
3473 CmiMarkBlockDirty(RegistryHive, FreeOffset);
3485 CmiAddFree(PREGISTRY_HIVE RegistryHive,
3486 PCELL_HEADER FreeBlock,
3487 BLOCK_OFFSET FreeOffset,
3488 BOOLEAN MergeFreeBlocks)
3490 PCELL_HEADER *tmpList;
3491 BLOCK_OFFSET *tmpListOffset;
3496 assert(RegistryHive);
3499 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3500 FreeBlock, FreeOffset);
3502 /* Merge free blocks */
3503 if (MergeFreeBlocks == TRUE)
3505 if (CmiMergeFree(RegistryHive, FreeBlock, FreeOffset))
3506 return(STATUS_SUCCESS);
3509 if ((RegistryHive->FreeListSize + 1) > RegistryHive->FreeListMax)
3511 tmpList = ExAllocatePool(PagedPool,
3512 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax + 32));
3513 if (tmpList == NULL)
3514 return STATUS_INSUFFICIENT_RESOURCES;
3516 tmpListOffset = ExAllocatePool(PagedPool,
3517 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax + 32));
3519 if (tmpListOffset == NULL)
3521 ExFreePool(tmpList);
3522 return STATUS_INSUFFICIENT_RESOURCES;
3525 if (RegistryHive->FreeListMax)
3527 RtlMoveMemory(tmpList,
3528 RegistryHive->FreeList,
3529 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
3530 RtlMoveMemory(tmpListOffset,
3531 RegistryHive->FreeListOffset,
3532 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax));
3533 ExFreePool(RegistryHive->FreeList);
3534 ExFreePool(RegistryHive->FreeListOffset);
3536 RegistryHive->FreeList = tmpList;
3537 RegistryHive->FreeListOffset = tmpListOffset;
3538 RegistryHive->FreeListMax += 32;
3541 /* Add new offset to free list, maintaining list in ascending order */
3542 if ((RegistryHive->FreeListSize == 0)
3543 || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
3545 /* Add to end of list */
3546 RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
3547 RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
3549 else if (RegistryHive->FreeListOffset[0] > FreeOffset)
3551 /* Add to begin of list */
3552 RtlMoveMemory(&RegistryHive->FreeList[1],
3553 &RegistryHive->FreeList[0],
3554 sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
3555 RtlMoveMemory(&RegistryHive->FreeListOffset[1],
3556 &RegistryHive->FreeListOffset[0],
3557 sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
3558 RegistryHive->FreeList[0] = FreeBlock;
3559 RegistryHive->FreeListOffset[0] = FreeOffset;
3560 RegistryHive->FreeListSize++;
3564 /* Search where to insert */
3566 maxInd = RegistryHive->FreeListSize - 1;
3567 while ((maxInd - minInd) > 1)
3569 medInd = (minInd + maxInd) / 2;
3570 if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
3576 /* Insert before maxInd */
3577 RtlMoveMemory(&RegistryHive->FreeList[maxInd+1],
3578 &RegistryHive->FreeList[maxInd],
3579 sizeof(RegistryHive->FreeList[0]) * (RegistryHive->FreeListSize - minInd));
3580 RtlMoveMemory(&RegistryHive->FreeListOffset[maxInd + 1],
3581 &RegistryHive->FreeListOffset[maxInd],
3582 sizeof(RegistryHive->FreeListOffset[0]) * (RegistryHive->FreeListSize-minInd));
3583 RegistryHive->FreeList[maxInd] = FreeBlock;
3584 RegistryHive->FreeListOffset[maxInd] = FreeOffset;
3585 RegistryHive->FreeListSize++;
3588 return STATUS_SUCCESS;
3593 CmiGetBlock(PREGISTRY_HIVE RegistryHive,
3594 BLOCK_OFFSET BlockOffset,
3602 if (BlockOffset == (BLOCK_OFFSET)-1)
3607 if (IsPointerHive (RegistryHive))
3609 return (PVOID)BlockOffset;
3613 if (BlockOffset > RegistryHive->BlockListSize * 4096)
3615 DPRINT1("BlockOffset exceeds valid range (%lu > %lu)\n",
3616 BlockOffset, RegistryHive->BlockListSize * 4096);
3619 pBin = RegistryHive->BlockList[BlockOffset / 4096];
3622 return((PVOID)((ULONG_PTR)pBin + (BlockOffset - pBin->BlockOffset)));
3628 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
3629 BLOCK_OFFSET BlockOffset)
3636 if (IsNoFileHive(RegistryHive))
3639 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG)BlockOffset);
3641 BlockNumber = (ULONG)BlockOffset / 4096;
3643 Cell = CmiGetBlock(RegistryHive,
3647 CellSize = Cell->CellSize;
3649 CellSize = -CellSize;
3651 BlockCount = (ROUND_UP(BlockOffset + CellSize, 4096) - ROUND_DOWN(BlockOffset, 4096)) / 4096;
3653 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3656 (Cell->CellSize < 0) ? "used" : "free",
3659 RegistryHive->HiveDirty = TRUE;
3660 RtlSetBits(&RegistryHive->DirtyBitMap,
3667 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive,
3668 BLOCK_OFFSET BinOffset)
3674 if (IsNoFileHive(RegistryHive))
3677 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG)BinOffset);
3679 BlockNumber = (ULONG)BinOffset / 4096;
3681 Bin = RegistryHive->BlockList[BlockNumber];
3683 BlockCount = Bin->BlockSize / 4096;
3685 DPRINT(" BlockNumber %lu Size %lu BlockCount %lu\n",
3690 RegistryHive->HiveDirty = TRUE;
3691 RtlSetBits(&RegistryHive->DirtyBitMap,
3698 CmiGetPackedNameLength(IN PUNICODE_STRING Name,
3699 OUT PBOOLEAN Packable)
3703 if (Packable != NULL)
3706 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3708 if (Name->Buffer[i] & 0xFF00)
3710 if (Packable != NULL)
3712 return Name->Length;
3716 return (Name->Length / sizeof(WCHAR));
3721 CmiComparePackedNames(IN PUNICODE_STRING Name,
3722 IN PCHAR NameBuffer,
3723 IN USHORT NameBufferSize,
3724 IN BOOLEAN NamePacked)
3729 if (NamePacked == TRUE)
3731 if (Name->Length != NameBufferSize * sizeof(WCHAR))
3734 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3736 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar((WCHAR)NameBuffer[i]))
3742 if (Name->Length != NameBufferSize)
3745 UNameBuffer = (PWCHAR)NameBuffer;
3747 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3749 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar(UNameBuffer[i]))
3759 CmiCopyPackedName(PWCHAR NameBuffer,
3760 PCHAR PackedNameBuffer,
3761 ULONG PackedNameSize)
3765 for (i = 0; i < PackedNameSize; i++)
3766 NameBuffer[i] = (WCHAR)PackedNameBuffer[i];
3771 CmiCompareHash(PUNICODE_STRING KeyName,
3776 Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0;
3777 Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0;
3778 Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0;
3779 Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0;
3781 return (strncmp(Buffer, HashString, 4) == 0);
3786 CmiCompareHashI(PUNICODE_STRING KeyName,
3791 Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0;
3792 Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0;
3793 Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0;
3794 Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0;
3796 return (_strnicmp(Buffer, HashString, 4) == 0);
3801 CmiCompareKeyNames(PUNICODE_STRING KeyName,
3807 DPRINT("Flags: %hx\n", KeyCell->Flags);
3809 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
3811 if (KeyName->Length != KeyCell->NameSize * sizeof(WCHAR))
3814 for (i = 0; i < KeyCell->NameSize; i++)
3816 if (KeyName->Buffer[i] != (WCHAR)KeyCell->Name[i])
3822 if (KeyName->Length != KeyCell->NameSize)
3825 UnicodeName = (PWCHAR)KeyCell->Name;
3826 for (i = 0; i < KeyCell->NameSize / sizeof(WCHAR); i++)
3828 if (KeyName->Buffer[i] != UnicodeName[i])
3838 CmiCompareKeyNamesI(PUNICODE_STRING KeyName,
3844 DPRINT("Flags: %hx\n", KeyCell->Flags);
3846 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
3848 if (KeyName->Length != KeyCell->NameSize * sizeof(WCHAR))
3851 for (i = 0; i < KeyCell->NameSize; i++)
3853 if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) !=
3854 RtlUpcaseUnicodeChar((WCHAR)KeyCell->Name[i]))
3860 if (KeyName->Length != KeyCell->NameSize)
3863 UnicodeName = (PWCHAR)KeyCell->Name;
3864 for (i = 0; i < KeyCell->NameSize / sizeof(WCHAR); i++)
3866 if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) !=
3867 RtlUpcaseUnicodeChar(UnicodeName[i]))
3877 CmiCopyKey (PREGISTRY_HIVE DstHive,
3878 PKEY_CELL DstKeyCell,
3879 PREGISTRY_HIVE SrcHive,
3880 PKEY_CELL SrcKeyCell)
3882 PKEY_CELL NewKeyCell;
3883 ULONG NewKeyCellSize;
3884 BLOCK_OFFSET NewKeyCellOffset;
3885 PHASH_TABLE_CELL NewHashTableCell;
3886 ULONG NewHashTableSize;
3887 BLOCK_OFFSET NewHashTableOffset;
3891 DPRINT ("CmiCopyKey() called\n");
3893 if (DstKeyCell == NULL)
3895 /* Allocate and copy key cell */
3896 NewKeyCellSize = sizeof(KEY_CELL) + SrcKeyCell->NameSize;
3897 Status = CmiAllocateBlock (DstHive,
3898 (PVOID) &NewKeyCell,
3901 if (!NT_SUCCESS(Status))
3903 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
3906 if (NewKeyCell == NULL)
3908 DPRINT1 ("Failed to allocate a key cell\n");
3909 return STATUS_INSUFFICIENT_RESOURCES;
3912 RtlCopyMemory (NewKeyCell,
3916 DstHive->HiveHeader->RootKeyCell = NewKeyCellOffset;
3918 /* Copy class name */
3919 if (SrcKeyCell->ClassNameOffset != (BLOCK_OFFSET) -1)
3921 PDATA_CELL SrcClassNameCell;
3922 PDATA_CELL NewClassNameCell;
3923 BLOCK_OFFSET NewClassNameOffset;
3925 SrcClassNameCell = CmiGetBlock (SrcHive, SrcKeyCell->ClassNameOffset, NULL),
3927 NewKeyCell->ClassSize = SrcKeyCell->ClassSize;
3928 Status = CmiAllocateBlock (DstHive,
3929 (PVOID)&NewClassNameCell,
3930 NewKeyCell->ClassSize,
3931 &NewClassNameOffset);
3932 if (!NT_SUCCESS(Status))
3934 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
3938 RtlCopyMemory (NewClassNameCell,
3940 NewKeyCell->ClassSize);
3941 NewKeyCell->ClassNameOffset = NewClassNameOffset;
3946 NewKeyCell = DstKeyCell;
3949 /* Allocate hash table */
3950 if (SrcKeyCell->NumberOfSubKeys > 0)
3952 NewHashTableSize = ROUND_UP(SrcKeyCell->NumberOfSubKeys + 1, 4) - 1;
3953 Status = CmiAllocateHashTableBlock (DstHive,
3955 &NewHashTableOffset,
3957 if (!NT_SUCCESS(Status))
3959 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status);
3962 NewKeyCell->HashTableOffset = NewHashTableOffset;
3965 /* Allocate and copy value list and values */
3966 if (SrcKeyCell->NumberOfValues != 0)
3968 PVALUE_LIST_CELL NewValueListCell;
3969 PVALUE_LIST_CELL SrcValueListCell;
3970 PVALUE_CELL NewValueCell;
3971 PVALUE_CELL SrcValueCell;
3972 PDATA_CELL SrcValueDataCell;
3973 PDATA_CELL NewValueDataCell;
3974 BLOCK_OFFSET ValueCellOffset;
3975 BLOCK_OFFSET ValueDataCellOffset;
3976 ULONG NewValueListCellSize;
3977 ULONG NewValueCellSize;
3980 NewValueListCellSize =
3981 ROUND_UP(SrcKeyCell->NumberOfValues, 4) * sizeof(BLOCK_OFFSET);
3982 Status = CmiAllocateBlock (DstHive,
3983 (PVOID)&NewValueListCell,
3984 NewValueListCellSize,
3985 &NewKeyCell->ValuesOffset);
3986 if (!NT_SUCCESS(Status))
3988 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
3992 RtlZeroMemory (NewValueListCell,
3993 NewValueListCellSize);
3996 SrcValueListCell = CmiGetBlock (SrcHive, SrcKeyCell->ValuesOffset, NULL);
3997 for (i = 0; i < SrcKeyCell->NumberOfValues; i++)
3999 /* Copy value cell */
4000 SrcValueCell = CmiGetBlock (SrcHive, SrcValueListCell->Values[i], NULL);
4002 NewValueCellSize = sizeof(VALUE_CELL) + SrcValueCell->NameSize;
4003 Status = CmiAllocateBlock (DstHive,
4004 (PVOID*) &NewValueCell,
4007 if (!NT_SUCCESS(Status))
4009 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4013 NewValueListCell->Values[i] = ValueCellOffset;
4014 RtlCopyMemory (NewValueCell,
4018 /* Copy value data cell */
4019 if (SrcValueCell->DataSize > (LONG) sizeof(PVOID))
4021 SrcValueDataCell = CmiGetBlock (SrcHive, SrcValueCell->DataOffset, NULL);
4023 Status = CmiAllocateBlock (DstHive,
4024 (PVOID*) &NewValueDataCell,
4025 SrcValueCell->DataSize,
4026 &ValueDataCellOffset);
4027 if (!NT_SUCCESS(Status))
4029 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4032 RtlCopyMemory (NewValueDataCell,
4034 SrcValueCell->DataSize);
4035 NewValueCell->DataOffset = ValueDataCellOffset;
4041 if (SrcKeyCell->NumberOfSubKeys > 0)
4043 PHASH_TABLE_CELL SrcHashTableCell;
4044 PKEY_CELL SrcSubKeyCell;
4045 PKEY_CELL NewSubKeyCell;
4046 ULONG NewSubKeyCellSize;
4047 BLOCK_OFFSET NewSubKeyCellOffset;
4048 PHASH_RECORD SrcHashRecord;
4050 SrcHashTableCell = CmiGetBlock (SrcHive,
4051 SrcKeyCell->HashTableOffset,
4054 for (i = 0; i < SrcKeyCell->NumberOfSubKeys; i++)
4056 SrcHashRecord = &SrcHashTableCell->Table[i];
4057 SrcSubKeyCell = CmiGetBlock (SrcHive, SrcHashRecord->KeyOffset, NULL);
4059 /* Allocate and copy key cell */
4060 NewSubKeyCellSize = sizeof(KEY_CELL) + SrcSubKeyCell->NameSize;
4061 Status = CmiAllocateBlock (DstHive,
4062 (PVOID)&NewSubKeyCell,
4064 &NewSubKeyCellOffset);
4065 if (!NT_SUCCESS(Status))
4067 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4070 if (NewKeyCell == NULL)
4072 DPRINT1 ("Failed to allocate a sub key cell\n");
4073 return STATUS_INSUFFICIENT_RESOURCES;
4076 NewHashTableCell->Table[i].KeyOffset = NewSubKeyCellOffset;
4077 NewHashTableCell->Table[i].HashValue = SrcHashRecord->HashValue;
4079 RtlCopyMemory (NewSubKeyCell,
4083 /* Copy class name */
4084 if (SrcSubKeyCell->ClassNameOffset != (BLOCK_OFFSET) -1)
4086 PDATA_CELL SrcClassNameCell;
4087 PDATA_CELL NewClassNameCell;
4088 BLOCK_OFFSET NewClassNameOffset;
4090 SrcClassNameCell = CmiGetBlock (SrcHive,
4091 SrcSubKeyCell->ClassNameOffset,
4094 NewSubKeyCell->ClassSize = SrcSubKeyCell->ClassSize;
4095 Status = CmiAllocateBlock (DstHive,
4096 (PVOID)&NewClassNameCell,
4097 NewSubKeyCell->ClassSize,
4098 &NewClassNameOffset);
4099 if (!NT_SUCCESS(Status))
4101 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4105 NewSubKeyCell->ClassNameOffset = NewClassNameOffset;
4106 RtlCopyMemory (NewClassNameCell,
4108 NewSubKeyCell->ClassSize);
4111 /* Copy subkey data and subkeys */
4112 Status = CmiCopyKey (DstHive,
4116 if (!NT_SUCCESS(Status))
4118 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4124 return STATUS_SUCCESS;
4129 CmiSaveTempHive (PREGISTRY_HIVE Hive,
4132 IO_STATUS_BLOCK IoStatusBlock;
4133 LARGE_INTEGER FileOffset;
4138 DPRINT ("CmiSaveTempHive() called\n");
4140 Hive->HiveHeader->Checksum = CmiCalcChecksum ((PULONG)Hive->HiveHeader);
4142 /* Write hive block */
4143 FileOffset.QuadPart = 0ULL;
4144 Status = NtWriteFile (FileHandle,
4150 sizeof(HIVE_HEADER),
4153 if (!NT_SUCCESS(Status))
4155 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status);
4159 DPRINT ("Saving %lu blocks\n", Hive->BlockListSize);
4160 for (BlockIndex = 0; BlockIndex < Hive->BlockListSize; BlockIndex++)
4162 BlockPtr = Hive->BlockList[BlockIndex];
4163 DPRINT ("BlockPtr %p\n", BlockPtr);
4165 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096ULL;
4166 DPRINT ("File offset %I64x\n", FileOffset.QuadPart);
4168 /* Write hive block */
4169 Status = NtWriteFile (FileHandle,
4178 if (!NT_SUCCESS(Status))
4180 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status);
4185 Status = NtFlushBuffersFile (FileHandle,
4187 if (!NT_SUCCESS(Status))
4189 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status);
4192 DPRINT ("CmiSaveTempHive() done\n");