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
10 #include <ddk/ntifs.h>
12 #include <internal/ob.h>
15 #include <internal/pool.h>
16 #include <internal/registry.h>
17 #include <reactos/bugcodes.h>
20 #include <internal/debug.h>
25 /* uncomment to enable hive checks (incomplete and probably buggy) */
28 /* LOCAL MACROS *************************************************************/
30 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
31 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
33 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
35 BOOLEAN CmiDoVerify = FALSE;
38 CmiCalcChecksum(PULONG Buffer);
40 /* FUNCTIONS ****************************************************************/
43 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header)
46 RtlZeroMemory(Header, sizeof(HIVE_HEADER));
47 Header->BlockId = REG_HIVE_ID;
48 Header->UpdateCounter1 = 0;
49 Header->UpdateCounter2 = 0;
50 Header->DateModified.dwLowDateTime = 0;
51 Header->DateModified.dwHighDateTime = 0;
57 Header->RootKeyCell = 0;
58 Header->BlockSize = REG_BLOCK_SIZE;
65 CmiCreateDefaultBinCell(PHBIN BinCell)
68 RtlZeroMemory(BinCell, sizeof(HBIN));
69 BinCell->BlockId = REG_BIN_ID;
70 BinCell->DateModified.dwLowDateTime = 0;
71 BinCell->DateModified.dwHighDateTime = 0;
72 BinCell->BlockSize = REG_BLOCK_SIZE;
77 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell)
80 RtlZeroMemory(RootKeyCell, sizeof(KEY_CELL));
81 RootKeyCell->CellSize = -sizeof(KEY_CELL);
82 RootKeyCell->Id = REG_KEY_CELL_ID;
83 RootKeyCell->Type = REG_ROOT_KEY_CELL_TYPE;
84 NtQuerySystemTime((PTIME) &RootKeyCell->LastWriteTime);
85 RootKeyCell->ParentKeyOffset = 0;
86 RootKeyCell->NumberOfSubKeys = 0;
87 RootKeyCell->HashTableOffset = -1;
88 RootKeyCell->NumberOfValues = 0;
89 RootKeyCell->ValuesOffset = -1;
90 RootKeyCell->SecurityKeyOffset = 0;
91 RootKeyCell->ClassNameOffset = -1;
92 RootKeyCell->NameSize = 0;
93 RootKeyCell->ClassSize = 0;
98 CmiVerifyBinCell(PHBIN BinCell)
105 if (BinCell->BlockId != REG_BIN_ID)
107 DbgPrint("BlockId is %.08x (should be %.08x)\n",
108 BinCell->BlockId, REG_BIN_ID);
109 assert(BinCell->BlockId == REG_BIN_ID);
112 //BinCell->DateModified.dwLowDateTime
114 //BinCell->DateModified.dwHighDateTime
117 if (BinCell->BlockSize != REG_BLOCK_SIZE)
119 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
120 BinCell->BlockSize, REG_BLOCK_SIZE);
121 assert(BinCell->BlockSize == REG_BLOCK_SIZE);
129 CmiVerifyKeyCell(PKEY_CELL KeyCell)
136 if (KeyCell->CellSize == 0)
138 DbgPrint("CellSize is %d (must not be 0)\n",
140 assert(KeyCell->CellSize != 0);
143 if (KeyCell->Id != REG_KEY_CELL_ID)
145 DbgPrint("Id is %.08x (should be %.08x)\n",
146 KeyCell->Id, REG_KEY_CELL_ID);
147 assert(KeyCell->Id == REG_KEY_CELL_ID);
150 if ((KeyCell->Type != REG_KEY_CELL_TYPE)
151 && (KeyCell->Type != REG_ROOT_KEY_CELL_TYPE))
153 DbgPrint("Type is %.08x (should be %.08x or %.08x)\n",
154 KeyCell->Type, REG_KEY_CELL_TYPE, REG_ROOT_KEY_CELL_TYPE);
158 //KeyCell->LastWriteTime;
160 if (KeyCell->ParentKeyOffset < 0)
162 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
163 KeyCell->ParentKeyOffset);
164 assert(KeyCell->ParentKeyOffset >= 0);
167 if (KeyCell->NumberOfSubKeys < 0)
169 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
170 KeyCell->NumberOfSubKeys);
171 assert(KeyCell->NumberOfSubKeys >= 0);
174 //KeyCell->HashTableOffset;
176 if (KeyCell->NumberOfValues < 0)
178 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
179 KeyCell->NumberOfValues);
180 assert(KeyCell->NumberOfValues >= 0);
183 //KeyCell->ValuesOffset = -1;
185 if (KeyCell->SecurityKeyOffset < 0)
187 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
188 KeyCell->SecurityKeyOffset);
189 assert(KeyCell->SecurityKeyOffset >= 0);
192 //KeyCell->ClassNameOffset = -1;
203 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell)
208 CmiVerifyKeyCell(RootKeyCell);
210 if (RootKeyCell->Type != REG_ROOT_KEY_CELL_TYPE)
212 DbgPrint("Type is %.08x (should be %.08x)\n",
213 RootKeyCell->Type, REG_ROOT_KEY_CELL_TYPE);
214 assert(RootKeyCell->Type == REG_ROOT_KEY_CELL_TYPE);
222 CmiVerifyValueCell(PVALUE_CELL ValueCell)
229 if (ValueCell->CellSize == 0)
231 DbgPrint("CellSize is %d (must not be 0)\n",
232 ValueCell->CellSize);
233 assert(ValueCell->CellSize != 0);
236 if (ValueCell->Id != REG_VALUE_CELL_ID)
238 DbgPrint("Id is %.08x (should be %.08x)\n",
239 ValueCell->Id, REG_VALUE_CELL_ID);
240 assert(ValueCell->Id == REG_VALUE_CELL_ID);
243 //ValueCell->NameSize;
244 //ValueCell->LONG DataSize;
245 //ValueCell->DataOffset;
246 //ValueCell->ULONG DataType;
247 //ValueCell->USHORT Flags;
248 //ValueCell->USHORT Unused1;
249 //ValueCell->UCHAR Name[0];
255 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell)
260 if (ValueListCell->CellSize == 0)
262 DbgPrint("CellSize is %d (must not be 0)\n",
263 ValueListCell->CellSize);
264 assert(ValueListCell->CellSize != 0);
272 CmiVerifyKeyObject(PKEY_OBJECT KeyObject)
277 if (KeyObject->RegistryHive == NULL)
279 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
280 KeyObject->RegistryHive);
281 assert(KeyObject->RegistryHive != NULL);
284 if (KeyObject->KeyCell == NULL)
286 DbgPrint("KeyCell is NULL (must not be NULL)\n",
288 assert(KeyObject->KeyCell != NULL);
291 if (KeyObject->ParentKey == NULL)
293 DbgPrint("ParentKey is NULL (must not be NULL)\n",
294 KeyObject->ParentKey);
295 assert(KeyObject->ParentKey != NULL);
303 CmiVerifyHiveHeader(PHIVE_HEADER Header)
308 if (Header->BlockId != REG_HIVE_ID)
310 DbgPrint("BlockId is %.08x (must be %.08x)\n",
313 assert(Header->BlockId == REG_HIVE_ID);
316 if (Header->Unused3 != 1)
318 DbgPrint("Unused3 is %.08x (must be 1)\n",
320 assert(Header->Unused3 == 1);
323 if (Header->Unused4 != 3)
325 DbgPrint("Unused4 is %.08x (must be 3)\n",
327 assert(Header->Unused4 == 3);
330 if (Header->Unused5 != 0)
332 DbgPrint("Unused5 is %.08x (must be 0)\n",
334 assert(Header->Unused5 == 0);
337 if (Header->Unused6 != 1)
339 DbgPrint("Unused6 is %.08x (must be 1)\n",
341 assert(Header->Unused6 == 1);
344 if (Header->Unused7 != 1)
346 DbgPrint("Unused7 is %.08x (must be 1)\n",
348 assert(Header->Unused7 == 1);
356 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive)
361 CmiVerifyHiveHeader(RegistryHive->HiveHeader);
369 CmiPopulateHive(HANDLE FileHandle)
371 IO_STATUS_BLOCK IoStatusBlock;
372 LARGE_INTEGER FileOffset;
373 PCELL_HEADER FreeCell;
379 tBuf = (PCHAR) ExAllocatePool(NonPagedPool, REG_BLOCK_SIZE);
381 return STATUS_INSUFFICIENT_RESOURCES;
383 BinCell = (PHBIN) tBuf;
384 FreeCell = (PCELL_HEADER) (tBuf + REG_HBIN_DATA_OFFSET);
386 CmiCreateDefaultBinCell(BinCell);
388 // The whole block is free
389 FreeCell->CellSize = REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET;
391 // Add free blocks so we don't need to expand
392 // the file for a while
393 for (i = 1; i < 50; i++)
395 // Block offset of this bin
396 BinCell->BlockOffset = i * REG_BLOCK_SIZE;
398 FileOffset.u.HighPart = 0;
399 FileOffset.u.LowPart = (i + 1) * REG_BLOCK_SIZE;
401 Status = NtWriteFile(FileHandle,
410 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
411 if (!NT_SUCCESS(Status))
426 CmiCreateNewRegFile(HANDLE FileHandle)
428 IO_STATUS_BLOCK IoStatusBlock;
429 PCELL_HEADER FreeCell;
430 PHIVE_HEADER HiveHeader;
431 PKEY_CELL RootKeyCell;
436 Buffer = (PCHAR) ExAllocatePool(NonPagedPool, 2 * REG_BLOCK_SIZE);
438 return STATUS_INSUFFICIENT_RESOURCES;
440 HiveHeader = (PHIVE_HEADER)Buffer;
441 BinCell = (PHBIN)((ULONG_PTR)Buffer + REG_BLOCK_SIZE);
442 RootKeyCell = (PKEY_CELL)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET);
443 FreeCell = (PCELL_HEADER)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
445 CmiCreateDefaultHiveHeader(HiveHeader);
446 CmiCreateDefaultBinCell(BinCell);
447 CmiCreateDefaultRootKeyCell(RootKeyCell);
450 BinCell->BlockOffset = 0;
452 /* Offset to root key block */
453 HiveHeader->RootKeyCell = REG_HBIN_DATA_OFFSET;
455 /* The rest of the block is free */
456 FreeCell->CellSize = REG_BLOCK_SIZE - (REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
458 Status = NtWriteFile(FileHandle,
470 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
472 if (!NT_SUCCESS(Status))
478 if (NT_SUCCESS(Status))
480 CmiPopulateHive(FileHandle);
484 Status = NtFlushBuffersFile(FileHandle,
493 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive)
495 OBJECT_ATTRIBUTES ObjectAttributes;
496 FILE_STANDARD_INFORMATION fsi;
497 IO_STATUS_BLOCK IoStatusBlock;
498 HANDLE HiveHandle = INVALID_HANDLE_VALUE;
499 HANDLE LogHandle = INVALID_HANDLE_VALUE;
500 PHIVE_HEADER HiveHeader = NULL;
501 PHIVE_HEADER LogHeader = NULL;
502 LARGE_INTEGER FileOffset;
506 RTL_BITMAP BlockBitMap;
509 DPRINT("CmiCheckAndFixHive() called\n");
511 /* Try to open the hive file */
512 InitializeObjectAttributes(&ObjectAttributes,
513 &RegistryHive->HiveFileName,
518 Status = NtCreateFile(&HiveHandle,
519 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
523 FILE_ATTRIBUTE_NORMAL,
526 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
529 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
531 return(STATUS_SUCCESS);
533 if (!NT_SUCCESS(Status))
535 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
539 /* Try to open the log file */
540 InitializeObjectAttributes(&ObjectAttributes,
541 &RegistryHive->LogFileName,
546 Status = NtCreateFile(&LogHandle,
547 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
551 FILE_ATTRIBUTE_NORMAL,
554 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
557 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
559 LogHandle = INVALID_HANDLE_VALUE;
561 else if (!NT_SUCCESS(Status))
563 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
568 /* Allocate hive header */
569 HiveHeader = ExAllocatePool(PagedPool,
570 sizeof(HIVE_HEADER));
571 if (HiveHeader == NULL)
573 DPRINT("ExAllocatePool() failed\n");
574 Status = STATUS_INSUFFICIENT_RESOURCES;
578 /* Read hive base block */
579 FileOffset.QuadPart = 0ULL;
580 Status = NtReadFile(HiveHandle,
589 if (!NT_SUCCESS(Status))
591 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
595 if (LogHandle == INVALID_HANDLE_VALUE)
597 if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) ||
598 HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2)
600 /* There is no way to fix the hive without log file - BSOD! */
601 DPRINT("Hive header inconsistent and no log file available!\n");
602 KeBugCheck(CONFIG_LIST_FAILED);
605 Status = STATUS_SUCCESS;
610 /* Allocate hive header */
611 LogHeader = ExAllocatePool(PagedPool,
612 sizeof(HIVE_HEADER));
613 if (LogHeader == NULL)
615 DPRINT("ExAllocatePool() failed\n");
616 Status = STATUS_INSUFFICIENT_RESOURCES;
620 /* Read log file header */
621 FileOffset.QuadPart = 0ULL;
622 Status = NtReadFile(LogHandle,
631 if (!NT_SUCCESS(Status))
633 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
637 /* Check log file header integrity */
638 if (LogHeader->Checksum != CmiCalcChecksum((PULONG)LogHeader) ||
639 LogHeader->UpdateCounter1 != LogHeader->UpdateCounter2)
641 if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) ||
642 HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2)
644 DPRINT("Hive file and log file are inconsistent!\n");
645 KeBugCheck(CONFIG_LIST_FAILED);
648 /* Log file damaged but hive is okay */
649 Status = STATUS_SUCCESS;
653 if (HiveHeader->UpdateCounter1 == HiveHeader->UpdateCounter2 &&
654 HiveHeader->UpdateCounter1 == LogHeader->UpdateCounter1)
656 /* Hive and log file are up-to-date */
657 Status = STATUS_SUCCESS;
662 * Hive needs an update!
666 Status = NtQueryInformationFile(LogHandle,
670 FileStandardInformation);
671 if (!NT_SUCCESS(Status))
673 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
676 FileSize = fsi.EndOfFile.u.LowPart;
678 /* Calculate bitmap and block size */
679 BitmapSize = ROUND_UP((FileSize / 4096) - 1, sizeof(ULONG) * 8) / 8;
680 BufferSize = sizeof(HIVE_HEADER) +
683 BufferSize = ROUND_UP(BufferSize, 4096);
685 /* Reallocate log header block */
686 ExFreePool(LogHeader);
687 LogHeader = ExAllocatePool(PagedPool,
689 if (LogHeader == NULL)
691 DPRINT("ExAllocatePool() failed\n");
692 Status = STATUS_INSUFFICIENT_RESOURCES;
696 /* Read log file header */
697 FileOffset.QuadPart = 0ULL;
698 Status = NtReadFile(LogHandle,
707 if (!NT_SUCCESS(Status))
709 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
713 /* Initialize bitmap */
714 RtlInitializeBitMap(&BlockBitMap,
715 (PVOID)((ULONG)LogHeader + 4096 + sizeof(ULONG)),
718 /* FIXME: Update dirty blocks */
721 /* FIXME: Update hive header */
724 Status = STATUS_SUCCESS;
728 /* Clean up the mess */
730 if (HiveHeader != NULL)
731 ExFreePool(HiveHeader);
733 if (LogHeader != NULL)
734 ExFreePool(LogHeader);
736 if (LogHandle != INVALID_HANDLE_VALUE)
747 CmiInitNonVolatileRegistryHive(PREGISTRY_HIVE RegistryHive,
751 OBJECT_ATTRIBUTES ObjectAttributes;
752 FILE_STANDARD_INFORMATION fsi;
753 PCELL_HEADER FreeBlock;
754 LARGE_INTEGER FileOffset;
755 BLOCK_OFFSET BlockOffset;
756 ULONG CreateDisposition;
757 IO_STATUS_BLOCK IoSB;
765 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S, %d) called\n",
766 RegistryHive, Filename, CreateNew);
768 /* Duplicate Filename */
769 Status = RtlCreateUnicodeString(&RegistryHive->HiveFileName,
771 if (!NT_SUCCESS(Status))
773 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status);
777 /* Create log file name */
778 RegistryHive->LogFileName.Length = (wcslen(Filename) + 4) * sizeof(WCHAR);
779 RegistryHive->LogFileName.MaximumLength = RegistryHive->LogFileName.Length + sizeof(WCHAR);
780 RegistryHive->LogFileName.Buffer = ExAllocatePool(NonPagedPool,
781 RegistryHive->LogFileName.MaximumLength);
782 if (RegistryHive->LogFileName.Buffer == NULL)
784 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
785 DPRINT("ExAllocatePool() failed\n");
786 return(STATUS_INSUFFICIENT_RESOURCES);
788 wcscpy(RegistryHive->LogFileName.Buffer,
790 wcscat(RegistryHive->LogFileName.Buffer,
794 /* Check and eventually fix a hive */
795 Status = CmiCheckAndFixHive(RegistryHive);
796 if (!NT_SUCCESS(Status))
798 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
799 RtlFreeUnicodeString(&RegistryHive->LogFileName);
800 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status);
805 InitializeObjectAttributes(&ObjectAttributes,
806 &RegistryHive->HiveFileName,
813 * This is a workaround to prevent a BSOD because of missing registry hives.
814 * The workaround is only useful for developers. An implementation for the
815 * ordinary user must bail out on missing registry hives because they are
816 * essential to booting and configuring the OS.
819 if (CreateNew == TRUE)
820 CreateDisposition = FILE_OPEN_IF;
822 CreateDisposition = FILE_OPEN;
824 CreateDisposition = FILE_OPEN_IF;
826 Status = NtCreateFile(&FileHandle,
831 FILE_ATTRIBUTE_NORMAL,
834 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
837 if (!NT_SUCCESS(Status))
839 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
840 RtlFreeUnicodeString(&RegistryHive->LogFileName);
841 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
845 /* Note: Another workaround! See the note above! */
847 if ((CreateNew) && (IoSB.Information == FILE_CREATED))
849 if (IoSB.Information != FILE_OPENED)
851 Status = CmiCreateNewRegFile(FileHandle);
852 if (!NT_SUCCESS(Status))
854 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status);
856 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
857 RtlFreeUnicodeString(&RegistryHive->LogFileName);
862 /* Read hive header */
863 FileOffset.u.HighPart = 0;
864 FileOffset.u.LowPart = 0;
865 DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle, sizeof(HIVE_HEADER), RegistryHive->HiveHeader);
866 Status = NtReadFile(FileHandle,
871 RegistryHive->HiveHeader,
875 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
876 if (!NT_SUCCESS(Status))
878 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
880 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
881 RtlFreeUnicodeString(&RegistryHive->LogFileName);
885 /* Read update counter */
886 RegistryHive->UpdateCounter = RegistryHive->HiveHeader->UpdateCounter1;
888 Status = NtQueryInformationFile(FileHandle,
892 FileStandardInformation);
893 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
894 if (!NT_SUCCESS(Status) || fsi.EndOfFile.u.LowPart == 0)
896 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
898 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
899 RtlFreeUnicodeString(&RegistryHive->LogFileName);
903 RegistryHive->FileSize = fsi.EndOfFile.u.LowPart;
904 RegistryHive->BlockListSize = (RegistryHive->FileSize / 4096) - 1;
906 DPRINT("Space needed for block list describing hive: 0x%x\n",
907 sizeof(PHBIN *) * RegistryHive->BlockListSize);
909 RegistryHive->BlockList = ExAllocatePool(NonPagedPool,
910 sizeof(PHBIN *) * RegistryHive->BlockListSize);
912 if (RegistryHive->BlockList == NULL)
914 ExFreePool(RegistryHive->BlockList);
916 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
917 RtlFreeUnicodeString(&RegistryHive->LogFileName);
918 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 6.\n");
919 return STATUS_INSUFFICIENT_RESOURCES;
922 RegistryHive->BlockList[0] = ExAllocatePool(PagedPool,
923 RegistryHive->FileSize - 4096);
924 if (RegistryHive->BlockList[0] == NULL)
926 ExFreePool(RegistryHive->BlockList);
928 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
929 RtlFreeUnicodeString(&RegistryHive->LogFileName);
930 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 8.\n");
931 return STATUS_INSUFFICIENT_RESOURCES;
934 FileOffset.u.HighPart = 0;
935 FileOffset.u.LowPart = 4096;
937 DPRINT(" Attempting to NtReadFile(%d) for %d bytes into %p\n",
938 FileHandle, RegistryHive->FileSize - 4096, (PVOID)RegistryHive->BlockList[0]);
939 Status = NtReadFile(FileHandle,
944 (PVOID) RegistryHive->BlockList[0],
945 RegistryHive->FileSize - 4096,
949 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
953 RegistryHive->FreeListSize = 0;
954 RegistryHive->FreeListMax = 0;
955 RegistryHive->FreeList = NULL;
958 for (i = 0; i < RegistryHive->BlockListSize; i++)
960 RegistryHive->BlockList[i] = (PHBIN) (((ULONG_PTR) RegistryHive->BlockList[0]) + BlockOffset);
961 tmpBin = (PHBIN) (((ULONG_PTR) RegistryHive->BlockList[i]));
962 if (tmpBin->BlockId != REG_BIN_ID)
964 DPRINT("Bad BlockId %x, offset %x\n", tmpBin->BlockId, BlockOffset);
966 return STATUS_INSUFFICIENT_RESOURCES;
969 assertmsg((tmpBin->BlockSize % 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin->BlockSize));
971 if (tmpBin->BlockSize > 4096)
973 for (j = 1; j < tmpBin->BlockSize / 4096; j++)
975 RegistryHive->BlockList[i + j] = RegistryHive->BlockList[i];
980 /* Search free blocks and add to list */
981 FreeOffset = REG_HBIN_DATA_OFFSET;
982 while (FreeOffset < tmpBin->BlockSize)
984 FreeBlock = (PCELL_HEADER) ((ULONG_PTR) RegistryHive->BlockList[i] + FreeOffset);
985 if (FreeBlock->CellSize > 0)
987 Status = CmiAddFree(RegistryHive,
989 RegistryHive->BlockList[i]->BlockOffset + FreeOffset,
992 if (!NT_SUCCESS(Status))
998 FreeOffset += FreeBlock->CellSize;
1002 FreeOffset -= FreeBlock->CellSize;
1005 BlockOffset += tmpBin->BlockSize;
1009 * Create block bitmap and clear all bits
1011 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
1012 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1013 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
1014 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
1016 /* Allocate bitmap */
1017 RegistryHive->BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
1019 RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
1020 RegistryHive->BitmapBuffer,
1023 /* Initialize bitmap */
1024 RtlClearAllBits(&RegistryHive->DirtyBitMap);
1025 RegistryHive->HiveDirty = FALSE;
1027 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S, %d) - Finished.\n",
1028 RegistryHive, Filename, CreateNew);
1030 return(STATUS_SUCCESS);
1035 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive)
1037 PKEY_CELL RootKeyCell;
1039 RegistryHive->Flags |= (HIVE_VOLATILE | HIVE_POINTER);
1041 CmiCreateDefaultHiveHeader(RegistryHive->HiveHeader);
1043 RootKeyCell = (PKEY_CELL) ExAllocatePool(NonPagedPool, sizeof(KEY_CELL));
1045 if (RootKeyCell == NULL)
1046 return STATUS_INSUFFICIENT_RESOURCES;
1048 CmiCreateDefaultRootKeyCell(RootKeyCell);
1050 RegistryHive->HiveHeader->RootKeyCell = (BLOCK_OFFSET) RootKeyCell;
1052 return STATUS_SUCCESS;
1057 CmiCreateRegistryHive(PWSTR Filename,
1058 PREGISTRY_HIVE *RegistryHive,
1061 PREGISTRY_HIVE Hive;
1064 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename);
1066 *RegistryHive = NULL;
1068 Hive = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_HIVE));
1070 return(STATUS_INSUFFICIENT_RESOURCES);
1072 DPRINT("Hive %x\n", Hive);
1074 RtlZeroMemory(Hive, sizeof(REGISTRY_HIVE));
1076 Hive->HiveHeader = (PHIVE_HEADER)
1077 ExAllocatePool(NonPagedPool, sizeof(HIVE_HEADER));
1079 if (Hive->HiveHeader == NULL)
1082 return(STATUS_INSUFFICIENT_RESOURCES);
1085 if (Filename != NULL)
1087 Status = CmiInitNonVolatileRegistryHive(Hive, Filename, CreateNew);
1091 Status = CmiInitVolatileRegistryHive(Hive);
1094 if (!NT_SUCCESS(Status))
1096 ExFreePool(Hive->HiveHeader);
1101 ExInitializeResourceLite(&Hive->HiveResource);
1103 /* Acquire hive list lock exclusively */
1104 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1106 /* Add the new hive to the hive list */
1107 InsertTailList(&CmiHiveListHead, &Hive->HiveList);
1109 /* Release hive list lock */
1110 ExReleaseResourceLite(&CmiHiveListLock);
1112 VERIFY_REGISTRY_HIVE(Hive);
1114 *RegistryHive = Hive;
1116 DPRINT("CmiCreateRegistryHive(Filename %S) - Finished.\n", Filename);
1118 return(STATUS_SUCCESS);
1123 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive)
1125 /* Acquire hive list lock exclusively */
1126 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1128 /* Remove hive from hive list */
1129 RemoveEntryList(&RegistryHive->HiveList);
1131 /* Release hive list lock */
1132 ExReleaseResourceLite(&CmiHiveListLock);
1135 /* FIXME: Remove attached keys and values */
1138 /* Release hive header */
1139 ExFreePool(RegistryHive->HiveHeader);
1142 ExFreePool(RegistryHive);
1144 return(STATUS_SUCCESS);
1149 CmiCalcChecksum(PULONG Buffer)
1154 for (i = 0; i < 127; i++)
1162 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive)
1164 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1165 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1166 OBJECT_ATTRIBUTES ObjectAttributes;
1167 IO_STATUS_BLOCK IoStatusBlock;
1169 LARGE_INTEGER FileOffset;
1178 DPRINT("CmiStartLogUpdate() called\n");
1180 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1181 BufferSize = sizeof(HIVE_HEADER) +
1184 BufferSize = ROUND_UP(BufferSize, 4096);
1186 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1188 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool, BufferSize);
1191 DPRINT("ExAllocatePool() failed\n");
1192 return(STATUS_INSUFFICIENT_RESOURCES);
1195 /* Open log file for writing */
1196 InitializeObjectAttributes(&ObjectAttributes,
1197 &RegistryHive->LogFileName,
1202 Status = NtCreateFile(&FileHandle,
1207 FILE_ATTRIBUTE_NORMAL,
1210 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1213 if (!NT_SUCCESS(Status))
1215 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1220 /* Update firt update counter and checksum */
1221 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1222 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1224 /* Copy hive header */
1225 RtlCopyMemory(Buffer,
1226 RegistryHive->HiveHeader,
1227 sizeof(HIVE_HEADER));
1228 Ptr = Buffer + sizeof(HIVE_HEADER);
1235 RegistryHive->DirtyBitMap.Buffer,
1238 /* Write hive block and block bitmap */
1239 FileOffset.QuadPart = 0ULL;
1240 Status = NtWriteFile(FileHandle,
1249 if (!NT_SUCCESS(Status))
1251 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1252 NtClose(FileHandle);
1258 /* Write dirty blocks */
1259 FileOffset.QuadPart = (ULONGLONG)BufferSize;
1263 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1266 if ((BlockIndex == (ULONG)-1) ||
1267 (BlockIndex >= RegistryHive->BlockListSize))
1269 DPRINT("No more set bits\n");
1270 Status = STATUS_SUCCESS;
1274 DPRINT("Block %lu is dirty\n", BlockIndex);
1276 BlockPtr = RegistryHive->BlockList[BlockIndex];
1277 DPRINT("BlockPtr %p\n", BlockPtr);
1278 DPRINT("File offset %I64x\n", FileOffset.QuadPart);
1280 /* Write hive block */
1281 Status = NtWriteFile(FileHandle,
1290 if (!NT_SUCCESS(Status))
1292 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1293 NtClose(FileHandle);
1298 FileOffset.QuadPart += 4096ULL;
1301 /* Truncate log file */
1302 EndOfFileInfo.EndOfFile.QuadPart = FileOffset.QuadPart;
1303 Status = NtSetInformationFile(FileHandle,
1306 sizeof(FILE_END_OF_FILE_INFORMATION),
1307 FileEndOfFileInformation);
1308 if (!NT_SUCCESS(Status))
1310 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1311 NtClose(FileHandle);
1315 FileAllocationInfo.AllocationSize.QuadPart = FileOffset.QuadPart;
1316 Status = NtSetInformationFile(FileHandle,
1318 &FileAllocationInfo,
1319 sizeof(FILE_ALLOCATION_INFORMATION),
1320 FileAllocationInformation);
1321 if (!NT_SUCCESS(Status))
1323 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1324 NtClose(FileHandle);
1328 /* Flush the log file */
1329 Status = NtFlushBuffersFile(FileHandle,
1331 if (!NT_SUCCESS(Status))
1333 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1336 NtClose(FileHandle);
1343 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive)
1345 OBJECT_ATTRIBUTES ObjectAttributes;
1346 IO_STATUS_BLOCK IoStatusBlock;
1348 LARGE_INTEGER FileOffset;
1355 DPRINT("CmiFinishLogUpdate() called\n");
1357 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1358 BufferSize = sizeof(HIVE_HEADER) +
1361 BufferSize = ROUND_UP(BufferSize, 4096);
1363 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1365 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool, BufferSize);
1368 DPRINT("ExAllocatePool() failed\n");
1369 return(STATUS_INSUFFICIENT_RESOURCES);
1372 /* Open log file for writing */
1373 InitializeObjectAttributes(&ObjectAttributes,
1374 &RegistryHive->LogFileName,
1379 Status = NtCreateFile(&FileHandle,
1384 FILE_ATTRIBUTE_NORMAL,
1387 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1390 if (!NT_SUCCESS(Status))
1392 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1397 /* Update first and second update counter and checksum */
1398 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1399 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1400 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1402 /* Copy hive header */
1403 RtlCopyMemory(Buffer,
1404 RegistryHive->HiveHeader,
1405 sizeof(HIVE_HEADER));
1406 Ptr = Buffer + sizeof(HIVE_HEADER);
1408 /* Write empty block bitmap */
1416 /* Write hive block and block bitmap */
1417 FileOffset.QuadPart = 0ULL;
1418 Status = NtWriteFile(FileHandle,
1427 if (!NT_SUCCESS(Status))
1429 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1430 NtClose(FileHandle);
1437 /* Flush the log file */
1438 Status = NtFlushBuffersFile(FileHandle,
1440 if (!NT_SUCCESS(Status))
1442 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1445 NtClose(FileHandle);
1452 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive)
1454 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1455 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1456 OBJECT_ATTRIBUTES ObjectAttributes;
1457 IO_STATUS_BLOCK IoStatusBlock;
1463 DPRINT("CmiCleanupLogUpdate() called\n");
1465 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1466 BufferSize = sizeof(HIVE_HEADER) +
1469 BufferSize = ROUND_UP(BufferSize, 4096);
1471 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1473 /* Open log file for writing */
1474 InitializeObjectAttributes(&ObjectAttributes,
1475 &RegistryHive->LogFileName,
1480 Status = NtCreateFile(&FileHandle,
1485 FILE_ATTRIBUTE_NORMAL,
1488 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1491 if (!NT_SUCCESS(Status))
1493 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1497 /* Truncate log file */
1498 EndOfFileInfo.EndOfFile.QuadPart = (ULONGLONG)BufferSize;
1499 Status = NtSetInformationFile(FileHandle,
1502 sizeof(FILE_END_OF_FILE_INFORMATION),
1503 FileEndOfFileInformation);
1504 if (!NT_SUCCESS(Status))
1506 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1507 NtClose(FileHandle);
1511 FileAllocationInfo.AllocationSize.QuadPart = (ULONGLONG)BufferSize;
1512 Status = NtSetInformationFile(FileHandle,
1514 &FileAllocationInfo,
1515 sizeof(FILE_ALLOCATION_INFORMATION),
1516 FileAllocationInformation);
1517 if (!NT_SUCCESS(Status))
1519 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1520 NtClose(FileHandle);
1524 /* Flush the log file */
1525 Status = NtFlushBuffersFile(FileHandle,
1527 if (!NT_SUCCESS(Status))
1529 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1532 NtClose(FileHandle);
1539 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive)
1541 OBJECT_ATTRIBUTES ObjectAttributes;
1542 IO_STATUS_BLOCK IoStatusBlock;
1544 LARGE_INTEGER FileOffset;
1549 DPRINT("CmiStartHiveUpdate() called\n");
1551 /* Open hive for writing */
1552 InitializeObjectAttributes(&ObjectAttributes,
1553 &RegistryHive->HiveFileName,
1558 Status = NtCreateFile(&FileHandle,
1563 FILE_ATTRIBUTE_NORMAL,
1566 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1569 if (!NT_SUCCESS(Status))
1571 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1575 /* Update firt update counter and checksum */
1576 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1577 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1579 /* Write hive block */
1580 FileOffset.QuadPart = 0ULL;
1581 Status = NtWriteFile(FileHandle,
1586 RegistryHive->HiveHeader,
1587 sizeof(HIVE_HEADER),
1590 if (!NT_SUCCESS(Status))
1592 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1593 NtClose(FileHandle);
1600 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1603 if ((BlockIndex == (ULONG)-1) ||
1604 (BlockIndex >= RegistryHive->BlockListSize))
1606 DPRINT("No more set bits\n");
1607 Status = STATUS_SUCCESS;
1611 DPRINT("Block %lu is dirty\n", BlockIndex);
1613 BlockPtr = RegistryHive->BlockList[BlockIndex];
1614 DPRINT("BlockPtr %p\n", BlockPtr);
1616 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096ULL;
1617 DPRINT("File offset %I64x\n", FileOffset.QuadPart);
1619 /* Write hive block */
1620 Status = NtWriteFile(FileHandle,
1629 if (!NT_SUCCESS(Status))
1631 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1632 NtClose(FileHandle);
1639 Status = NtFlushBuffersFile(FileHandle,
1641 if (!NT_SUCCESS(Status))
1643 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1646 NtClose(FileHandle);
1653 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive)
1655 OBJECT_ATTRIBUTES ObjectAttributes;
1656 IO_STATUS_BLOCK IoStatusBlock;
1657 LARGE_INTEGER FileOffset;
1661 DPRINT("CmiFinishHiveUpdate() called\n");
1663 InitializeObjectAttributes(&ObjectAttributes,
1664 &RegistryHive->HiveFileName,
1669 Status = NtCreateFile(&FileHandle,
1674 FILE_ATTRIBUTE_NORMAL,
1677 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1680 if (!NT_SUCCESS(Status))
1682 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1686 /* Update second update counter and checksum */
1687 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1688 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1689 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1691 /* Write hive block */
1692 FileOffset.QuadPart = 0ULL;
1693 Status = NtWriteFile(FileHandle,
1698 RegistryHive->HiveHeader,
1699 sizeof(HIVE_HEADER),
1702 if (!NT_SUCCESS(Status))
1704 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1705 NtClose(FileHandle);
1709 Status = NtFlushBuffersFile(FileHandle,
1711 if (!NT_SUCCESS(Status))
1713 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1716 NtClose(FileHandle);
1723 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
1727 DPRINT("CmiFlushRegistryHive() called\n");
1729 if (RegistryHive->HiveDirty == FALSE)
1731 return(STATUS_SUCCESS);
1734 DPRINT("Hive '%wZ' is dirty\n",
1735 &RegistryHive->HiveFileName);
1736 DPRINT("Log file: '%wZ'\n",
1737 &RegistryHive->LogFileName);
1739 /* Update hive header modification time */
1740 NtQuerySystemTime((PTIME)&RegistryHive->HiveHeader->DateModified);
1742 /* Start log update */
1743 Status = CmiStartLogUpdate(RegistryHive);
1744 if (!NT_SUCCESS(Status))
1746 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status);
1750 /* Finish log update */
1751 Status = CmiFinishLogUpdate(RegistryHive);
1752 if (!NT_SUCCESS(Status))
1754 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
1758 /* Start hive update */
1759 Status = CmiStartHiveUpdate(RegistryHive);
1760 if (!NT_SUCCESS(Status))
1762 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status);
1766 /* Finish the hive update */
1767 Status = CmiFinishHiveUpdate(RegistryHive);
1768 if (!NT_SUCCESS(Status))
1770 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status);
1774 /* Cleanup log update */
1775 Status = CmiCleanupLogUpdate(RegistryHive);
1776 if (!NT_SUCCESS(Status))
1778 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
1782 /* Increment hive update counter */
1783 RegistryHive->UpdateCounter++;
1785 /* Clear dirty bitmap and dirty flag */
1786 RtlClearAllBits(&RegistryHive->DirtyBitMap);
1787 RegistryHive->HiveDirty = FALSE;
1789 DPRINT("CmiFlushRegistryHive() done\n");
1791 return(STATUS_SUCCESS);
1796 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive,
1799 PHASH_TABLE_CELL HashBlock;
1800 PKEY_CELL CurSubKeyCell;
1804 VERIFY_KEY_CELL(KeyCell);
1807 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1808 if (HashBlock == NULL)
1810 DPRINT("CmiGetBlock() failed\n");
1814 for (i = 0; i < HashBlock->HashTableSize; i++)
1816 if (HashBlock->Table[i].KeyOffset != 0)
1818 CurSubKeyCell = CmiGetBlock(RegistryHive,
1819 HashBlock->Table[i].KeyOffset,
1821 if (CurSubKeyCell == NULL)
1823 DPRINT("CmiGetBlock() failed\n");
1827 if (MaxName < CurSubKeyCell->NameSize)
1829 MaxName = CurSubKeyCell->NameSize;
1839 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive,
1842 PHASH_TABLE_CELL HashBlock;
1843 PKEY_CELL CurSubKeyCell;
1847 VERIFY_KEY_CELL(KeyCell);
1850 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1851 if (HashBlock == NULL)
1853 DPRINT("CmiGetBlock() failed\n");
1857 for (i = 0; i < HashBlock->HashTableSize; i++)
1859 if (HashBlock->Table[i].KeyOffset != 0)
1861 CurSubKeyCell = CmiGetBlock(RegistryHive,
1862 HashBlock->Table[i].KeyOffset,
1864 if (CurSubKeyCell == NULL)
1866 DPRINT("CmiGetBlock() failed\n");
1870 if (MaxClass < CurSubKeyCell->ClassSize)
1872 MaxClass = CurSubKeyCell->ClassSize;
1882 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive,
1885 PVALUE_LIST_CELL ValueListCell;
1886 PVALUE_CELL CurValueCell;
1890 VERIFY_KEY_CELL(KeyCell);
1893 ValueListCell = CmiGetBlock(RegistryHive,
1894 KeyCell->ValuesOffset,
1896 if (ValueListCell == NULL)
1898 DPRINT("CmiGetBlock() failed\n");
1902 for (i = 0; i < KeyCell->NumberOfValues; i++)
1904 CurValueCell = CmiGetBlock (RegistryHive,
1905 ValueListCell->Values[i],
1907 if (CurValueCell == NULL)
1909 DPRINT("CmiGetBlock() failed\n");
1912 if (CurValueCell != NULL &&
1913 MaxValueName < CurValueCell->NameSize)
1915 MaxValueName = CurValueCell->NameSize;
1919 return MaxValueName;
1924 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive,
1927 PVALUE_LIST_CELL ValueListCell;
1928 PVALUE_CELL CurValueCell;
1932 VERIFY_KEY_CELL(KeyCell);
1935 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1936 if (ValueListCell == NULL)
1941 for (i = 0; i < KeyCell->NumberOfValues; i++)
1943 CurValueCell = CmiGetBlock(RegistryHive,
1944 ValueListCell->Values[i],NULL);
1945 if ((CurValueCell != NULL) &&
1946 (MaxValueData < (CurValueCell->DataSize & LONG_MAX)))
1948 MaxValueData = CurValueCell->DataSize & LONG_MAX;
1952 return MaxValueData;
1957 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
1958 IN PKEY_CELL KeyCell,
1959 OUT PKEY_CELL *SubKeyCell,
1960 OUT BLOCK_OFFSET *BlockOffset,
1962 IN ACCESS_MASK DesiredAccess,
1963 IN ULONG Attributes)
1965 PHASH_TABLE_CELL HashBlock;
1966 PKEY_CELL CurSubKeyCell;
1970 VERIFY_KEY_CELL(KeyCell);
1972 //DPRINT("Scanning for sub key %s\n", KeyName);
1974 assert(RegistryHive);
1978 /* The key does not have any subkeys */
1979 if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
1981 return STATUS_SUCCESS;
1984 /* Get hash table */
1985 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1986 if (HashBlock == NULL)
1988 DPRINT("CmiGetBlock() failed\n");
1989 return STATUS_UNSUCCESSFUL;
1992 KeyLength = strlen(KeyName);
1993 for (i = 0; (i < KeyCell->NumberOfSubKeys) && (i < HashBlock->HashTableSize); i++)
1995 if (Attributes & OBJ_CASE_INSENSITIVE)
1997 if ((HashBlock->Table[i].KeyOffset != 0) &&
1998 (HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1) &&
1999 (_strnicmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4) == 0))
2001 CurSubKeyCell = CmiGetBlock(RegistryHive,
2002 HashBlock->Table[i].KeyOffset,
2004 if (CurSubKeyCell == NULL)
2006 DPRINT("CmiGetBlock() failed\n");
2007 return STATUS_UNSUCCESSFUL;
2010 if ((CurSubKeyCell->NameSize == KeyLength)
2011 && (_strnicmp(KeyName, CurSubKeyCell->Name, KeyLength) == 0))
2013 *SubKeyCell = CurSubKeyCell;
2014 *BlockOffset = HashBlock->Table[i].KeyOffset;
2021 if (HashBlock->Table[i].KeyOffset != 0 &&
2022 HashBlock->Table[i].KeyOffset != (ULONG_PTR) -1 &&
2023 !strncmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4))
2025 CurSubKeyCell = CmiGetBlock(RegistryHive,
2026 HashBlock->Table[i].KeyOffset,
2028 if (CurSubKeyCell == NULL)
2030 DPRINT("CmiGetBlock() failed\n");
2031 return STATUS_UNSUCCESSFUL;
2034 if (CurSubKeyCell->NameSize == KeyLength
2035 && !_strnicmp(KeyName, CurSubKeyCell->Name, KeyLength))
2037 *SubKeyCell = CurSubKeyCell;
2038 *BlockOffset = HashBlock->Table[i].KeyOffset;
2045 return STATUS_SUCCESS;
2050 CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
2053 PWSTR NewSubKeyName,
2054 USHORT NewSubKeyNameSize,
2056 PUNICODE_STRING Class,
2057 ULONG CreateOptions)
2059 PHASH_TABLE_CELL NewHashBlock;
2060 PHASH_TABLE_CELL HashBlock;
2061 BLOCK_OFFSET NKBOffset;
2062 PKEY_CELL NewKeyCell;
2068 KeyCell = Parent->KeyCell;
2070 VERIFY_KEY_CELL(KeyCell);
2072 if (NewSubKeyName[0] == L'\\')
2075 NameSize = NewSubKeyNameSize / 2 - 1;
2079 NameSize = NewSubKeyNameSize / 2;
2081 Status = STATUS_SUCCESS;
2083 NewBlockSize = sizeof(KEY_CELL) + NameSize;
2084 Status = CmiAllocateBlock(RegistryHive,
2085 (PVOID) &NewKeyCell,
2088 if (NewKeyCell == NULL)
2090 Status = STATUS_INSUFFICIENT_RESOURCES;
2094 NewKeyCell->Id = REG_KEY_CELL_ID;
2095 NewKeyCell->Type = REG_KEY_CELL_TYPE;
2096 ZwQuerySystemTime((PTIME) &NewKeyCell->LastWriteTime);
2097 NewKeyCell->ParentKeyOffset = -1;
2098 NewKeyCell->NumberOfSubKeys = 0;
2099 NewKeyCell->HashTableOffset = -1;
2100 NewKeyCell->NumberOfValues = 0;
2101 NewKeyCell->ValuesOffset = -1;
2102 NewKeyCell->SecurityKeyOffset = -1;
2103 NewKeyCell->NameSize = NameSize;
2104 wcstombs(NewKeyCell->Name, NewSubKeyName, NameSize);
2105 NewKeyCell->ClassNameOffset = -1;
2107 VERIFY_KEY_CELL(NewKeyCell);
2113 NewKeyCell->ClassSize = Class->Length + sizeof(WCHAR);
2114 Status = CmiAllocateBlock(RegistryHive,
2116 NewKeyCell->ClassSize,
2117 &NewKeyCell->ClassNameOffset);
2118 wcsncpy((PWSTR) pClass->Data, Class->Buffer, Class->Length);
2119 ((PWSTR) (pClass->Data))[Class->Length] = 0;
2123 if (!NT_SUCCESS(Status))
2128 SubKey->KeyCell = NewKeyCell;
2129 SubKey->BlockOffset = NKBOffset;
2131 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2132 if (IsPointerHive(RegistryHive) && (!IsPointerHive(Parent->RegistryHive)))
2137 if (KeyCell->HashTableOffset == (ULONG_PTR) -1)
2139 Status = CmiAllocateHashTableBlock(RegistryHive,
2141 &KeyCell->HashTableOffset,
2142 REG_INIT_HASH_TABLE_SIZE);
2143 if (!NT_SUCCESS(Status))
2150 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
2151 if (HashBlock == NULL)
2153 DPRINT("CmiGetBlock() failed\n");
2154 return STATUS_UNSUCCESSFUL;
2157 if (((KeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
2159 BLOCK_OFFSET HTOffset;
2161 /* Reallocate the hash table block */
2162 Status = CmiAllocateHashTableBlock(RegistryHive,
2165 HashBlock->HashTableSize +
2166 REG_EXTEND_HASH_TABLE_SIZE);
2167 if (!NT_SUCCESS(Status))
2172 RtlZeroMemory(&NewHashBlock->Table[0],
2173 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
2174 RtlCopyMemory(&NewHashBlock->Table[0],
2175 &HashBlock->Table[0],
2176 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
2177 CmiDestroyBlock(RegistryHive,
2179 KeyCell->HashTableOffset);
2180 KeyCell->HashTableOffset = HTOffset;
2181 HashBlock = NewHashBlock;
2185 Status = CmiAddKeyToHashTable(RegistryHive,
2189 if (NT_SUCCESS(Status))
2191 KeyCell->NumberOfSubKeys++;
2199 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
2200 PKEY_OBJECT ParentKey,
2203 PHASH_TABLE_CELL HashBlock;
2204 PVALUE_LIST_CELL ValueList;
2205 PVALUE_CELL ValueCell;
2206 PDATA_CELL DataCell;
2209 DPRINT("CmiRemoveSubKey() called\n");
2211 /* Remove all values */
2212 if (SubKey->KeyCell->NumberOfValues != 0)
2214 /* Get pointer to the value list cell */
2215 ValueList = CmiGetBlock(RegistryHive,
2216 SubKey->KeyCell->ValuesOffset,
2218 if (ValueList == NULL)
2220 DPRINT("CmiGetBlock() failed\n");
2221 return STATUS_UNSUCCESSFUL;
2224 if (ValueList != NULL)
2226 /* Enumerate all values */
2227 for (i = 0; i < SubKey->KeyCell->NumberOfValues; i++)
2229 /* Get pointer to value cell */
2230 ValueCell = CmiGetBlock(RegistryHive,
2231 ValueList->Values[i],
2233 if (ValueCell != NULL)
2235 if (ValueCell->DataSize > 4)
2237 DataCell = CmiGetBlock(RegistryHive,
2238 ValueCell->DataOffset,
2240 if (DataCell == NULL)
2242 DPRINT("CmiGetBlock() failed\n");
2243 return STATUS_UNSUCCESSFUL;
2246 if (DataCell != NULL)
2248 /* Destroy data cell */
2249 CmiDestroyBlock(RegistryHive,
2251 ValueCell->DataOffset);
2255 /* Destroy value cell */
2256 CmiDestroyBlock(RegistryHive,
2258 ValueList->Values[i]);
2263 /* Destroy value list cell */
2264 CmiDestroyBlock(RegistryHive,
2266 SubKey->KeyCell->ValuesOffset);
2268 SubKey->KeyCell->NumberOfValues = 0;
2269 SubKey->KeyCell->ValuesOffset = -1;
2272 /* Remove the key from the parent key's hash block */
2273 if (ParentKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2275 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset)
2276 HashBlock = CmiGetBlock(RegistryHive,
2277 ParentKey->KeyCell->HashTableOffset,
2279 if (HashBlock == NULL)
2281 DPRINT("CmiGetBlock() failed\n");
2282 return STATUS_UNSUCCESSFUL;
2284 DPRINT("ParentKey HashBlock %p\n", HashBlock)
2285 if (HashBlock != NULL)
2287 CmiRemoveKeyFromHashTable(RegistryHive,
2289 SubKey->BlockOffset);
2290 CmiMarkBlockDirty(RegistryHive,
2291 ParentKey->KeyCell->HashTableOffset);
2295 /* Remove the key's hash block */
2296 if (SubKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2298 DPRINT("SubKey HashTableOffset %lx\n", SubKey->KeyCell->HashTableOffset)
2299 HashBlock = CmiGetBlock(RegistryHive,
2300 SubKey->KeyCell->HashTableOffset,
2302 if (HashBlock == NULL)
2304 DPRINT("CmiGetBlock() failed\n");
2305 return STATUS_UNSUCCESSFUL;
2307 DPRINT("SubKey HashBlock %p\n", HashBlock)
2308 if (HashBlock != NULL)
2310 CmiDestroyBlock(RegistryHive,
2312 SubKey->KeyCell->HashTableOffset);
2313 SubKey->KeyCell->HashTableOffset = -1;
2317 /* Decrement the number of the parent key's sub keys */
2318 if (ParentKey != NULL)
2320 DPRINT("ParentKey %p\n", ParentKey)
2321 ParentKey->KeyCell->NumberOfSubKeys--;
2323 /* Remove the parent key's hash table */
2324 if (ParentKey->KeyCell->NumberOfSubKeys == 0)
2326 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset)
2327 HashBlock = CmiGetBlock(RegistryHive,
2328 ParentKey->KeyCell->HashTableOffset,
2330 if (HashBlock == NULL)
2332 DPRINT("CmiGetBlock() failed\n");
2333 return STATUS_UNSUCCESSFUL;
2335 DPRINT("ParentKey HashBlock %p\n", HashBlock)
2336 if (HashBlock != NULL)
2338 CmiDestroyBlock(RegistryHive,
2340 ParentKey->KeyCell->HashTableOffset);
2341 ParentKey->KeyCell->HashTableOffset = -1;
2345 NtQuerySystemTime((PTIME)&ParentKey->KeyCell->LastWriteTime);
2346 CmiMarkBlockDirty(RegistryHive,
2347 ParentKey->BlockOffset);
2350 /* Destroy key cell */
2351 CmiDestroyBlock(RegistryHive,
2353 SubKey->BlockOffset);
2354 SubKey->BlockOffset = -1;
2355 SubKey->KeyCell = NULL;
2357 return(STATUS_SUCCESS);
2362 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
2363 IN PKEY_CELL KeyCell,
2364 IN PUNICODE_STRING ValueName,
2365 OUT PVALUE_CELL *ValueCell,
2366 OUT BLOCK_OFFSET *VBOffset)
2368 PVALUE_LIST_CELL ValueListCell;
2369 PVALUE_CELL CurValueCell;
2374 /* The key does not have any values */
2375 if (KeyCell->ValuesOffset == (BLOCK_OFFSET)-1)
2377 return STATUS_SUCCESS;
2380 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2381 if (ValueListCell == NULL)
2383 DPRINT("ValueListCell is NULL\n");
2384 return STATUS_UNSUCCESSFUL;
2387 VERIFY_VALUE_LIST_CELL(ValueListCell);
2389 for (i = 0; i < KeyCell->NumberOfValues; i++)
2391 CurValueCell = CmiGetBlock(RegistryHive,
2392 ValueListCell->Values[i],
2394 if (CurValueCell == NULL)
2396 DPRINT("CmiGetBlock() failed\n");
2397 return STATUS_UNSUCCESSFUL;
2400 if ((CurValueCell != NULL) &&
2401 CmiComparePackedNames(ValueName,
2403 CurValueCell->NameSize,
2404 CurValueCell->Flags & REG_VALUE_NAME_PACKED))
2406 *ValueCell = CurValueCell;
2408 *VBOffset = ValueListCell->Values[i];
2409 //DPRINT("Found value %s\n", ValueName);
2414 return STATUS_SUCCESS;
2419 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
2420 IN PKEY_CELL KeyCell,
2422 OUT PVALUE_CELL *ValueCell)
2424 PVALUE_LIST_CELL ValueListCell;
2425 PVALUE_CELL CurValueCell;
2429 if (KeyCell->ValuesOffset == (BLOCK_OFFSET)-1)
2431 return STATUS_NO_MORE_ENTRIES;
2434 if (Index >= KeyCell->NumberOfValues)
2436 return STATUS_NO_MORE_ENTRIES;
2440 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2441 if (ValueListCell == NULL)
2443 DPRINT("CmiGetBlock() failed\n");
2444 return STATUS_UNSUCCESSFUL;
2447 VERIFY_VALUE_LIST_CELL(ValueListCell);
2450 CurValueCell = CmiGetBlock(RegistryHive,
2451 ValueListCell->Values[Index],
2453 if (CurValueCell == NULL)
2455 DPRINT("CmiGetBlock() failed\n");
2456 return STATUS_UNSUCCESSFUL;
2459 *ValueCell = CurValueCell;
2461 return STATUS_SUCCESS;
2466 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
2467 IN PKEY_CELL KeyCell,
2468 IN PUNICODE_STRING ValueName,
2469 OUT PVALUE_CELL *pValueCell,
2470 OUT BLOCK_OFFSET *pVBOffset)
2472 PVALUE_LIST_CELL NewValueListCell;
2473 PVALUE_LIST_CELL ValueListCell;
2474 PVALUE_CELL NewValueCell;
2475 BLOCK_OFFSET VLBOffset;
2476 BLOCK_OFFSET VBOffset;
2479 Status = CmiAllocateValueCell(RegistryHive,
2483 if (!NT_SUCCESS(Status))
2488 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG)KeyCell->ValuesOffset);
2490 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2492 if (ValueListCell == NULL)
2494 Status = CmiAllocateBlock(RegistryHive,
2495 (PVOID) &ValueListCell,
2496 sizeof(BLOCK_OFFSET) * 3,
2499 if (!NT_SUCCESS(Status))
2501 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
2504 KeyCell->ValuesOffset = VLBOffset;
2506 else if (KeyCell->NumberOfValues >=
2507 (((ULONG)ABS_VALUE(ValueListCell->CellSize) - 4) / sizeof(BLOCK_OFFSET)))
2509 Status = CmiAllocateBlock(RegistryHive,
2510 (PVOID) &NewValueListCell,
2511 (KeyCell->NumberOfValues + REG_VALUE_LIST_CELL_MULTIPLE) *
2512 sizeof(BLOCK_OFFSET),
2514 if (!NT_SUCCESS(Status))
2516 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
2520 RtlCopyMemory(&NewValueListCell->Values[0],
2521 &ValueListCell->Values[0],
2522 sizeof(BLOCK_OFFSET) * KeyCell->NumberOfValues);
2523 CmiDestroyBlock(RegistryHive, ValueListCell, KeyCell->ValuesOffset);
2524 KeyCell->ValuesOffset = VLBOffset;
2525 ValueListCell = NewValueListCell;
2528 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2529 KeyCell->NumberOfValues,
2530 (ULONG)ABS_VALUE(ValueListCell->CellSize),
2531 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - 4) / sizeof(BLOCK_OFFSET),
2532 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - 4) / sizeof(BLOCK_OFFSET));
2534 ValueListCell->Values[KeyCell->NumberOfValues] = VBOffset;
2535 KeyCell->NumberOfValues++;
2537 *pValueCell = NewValueCell;
2538 *pVBOffset = VBOffset;
2540 return STATUS_SUCCESS;
2545 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
2546 IN PKEY_CELL KeyCell,
2547 IN BLOCK_OFFSET KeyCellOffset,
2548 IN PUNICODE_STRING ValueName)
2550 PVALUE_LIST_CELL ValueListCell;
2551 PVALUE_CELL CurValueCell;
2554 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2556 if (ValueListCell == NULL)
2558 DPRINT("CmiGetBlock() failed\n");
2559 return STATUS_SUCCESS;
2562 VERIFY_VALUE_LIST_CELL(ValueListCell);
2564 for (i = 0; i < KeyCell->NumberOfValues; i++)
2566 CurValueCell = CmiGetBlock(RegistryHive, ValueListCell->Values[i], NULL);
2567 if (CurValueCell == NULL)
2569 DPRINT("CmiGetBlock() failed\n");
2570 return STATUS_UNSUCCESSFUL;
2573 if ((CurValueCell != NULL) &&
2574 CmiComparePackedNames(ValueName,
2576 CurValueCell->NameSize,
2577 CurValueCell->Flags & REG_VALUE_NAME_PACKED))
2579 CmiDestroyValueCell(RegistryHive, CurValueCell, ValueListCell->Values[i]);
2581 if ((KeyCell->NumberOfValues - 1) < i)
2583 RtlCopyMemory(&ValueListCell->Values[i],
2584 &ValueListCell->Values[i + 1],
2585 sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues - 1 - i));
2589 RtlZeroMemory(&ValueListCell->Values[i], sizeof(BLOCK_OFFSET));
2592 KeyCell->NumberOfValues -= 1;
2597 if (KeyCell->NumberOfValues == 0)
2599 CmiDestroyBlock(RegistryHive,
2601 KeyCell->ValuesOffset);
2605 CmiMarkBlockDirty(RegistryHive,
2606 KeyCell->ValuesOffset);
2609 CmiMarkBlockDirty(RegistryHive,
2612 return STATUS_SUCCESS;
2617 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive,
2618 OUT PHASH_TABLE_CELL *HashBlock,
2619 OUT BLOCK_OFFSET *HBOffset,
2620 IN ULONG HashTableSize)
2622 PHASH_TABLE_CELL NewHashBlock;
2626 Status = STATUS_SUCCESS;
2628 NewHashSize = sizeof(HASH_TABLE_CELL) +
2629 (HashTableSize - 1) * sizeof(HASH_RECORD);
2630 Status = CmiAllocateBlock(RegistryHive,
2631 (PVOID*) &NewHashBlock,
2635 if ((NewHashBlock == NULL) || (!NT_SUCCESS(Status)))
2637 Status = STATUS_INSUFFICIENT_RESOURCES;
2641 NewHashBlock->Id = REG_HASH_TABLE_BLOCK_ID;
2642 NewHashBlock->HashTableSize = HashTableSize;
2643 *HashBlock = NewHashBlock;
2651 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
2652 PHASH_TABLE_CELL HashBlock,
2655 BLOCK_OFFSET KeyOffset;
2658 if (HashBlock == NULL)
2661 if (IsPointerHive(RegistryHive))
2663 KeyCell = (PKEY_CELL) HashBlock->Table[Index].KeyOffset;
2667 KeyOffset = HashBlock->Table[Index].KeyOffset;
2668 KeyCell = CmiGetBlock(RegistryHive, KeyOffset, NULL);
2676 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
2677 PHASH_TABLE_CELL HashBlock,
2678 PKEY_CELL NewKeyCell,
2679 BLOCK_OFFSET NKBOffset)
2683 for (i = 0; i < HashBlock->HashTableSize; i++)
2685 if (HashBlock->Table[i].KeyOffset == 0)
2687 HashBlock->Table[i].KeyOffset = NKBOffset;
2688 RtlCopyMemory(&HashBlock->Table[i].HashValue, NewKeyCell->Name, 4);
2689 return STATUS_SUCCESS;
2693 return STATUS_UNSUCCESSFUL;
2698 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive,
2699 PHASH_TABLE_CELL HashBlock,
2700 BLOCK_OFFSET NKBOffset)
2704 for (i = 0; i < HashBlock->HashTableSize; i++)
2706 if (HashBlock->Table[i].KeyOffset == NKBOffset)
2708 HashBlock->Table[i].KeyOffset = 0;
2709 RtlZeroMemory(&HashBlock->Table[i].HashValue, 4);
2710 return STATUS_SUCCESS;
2714 return STATUS_UNSUCCESSFUL;
2719 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
2720 PVALUE_CELL *ValueCell,
2721 BLOCK_OFFSET *VBOffset,
2722 IN PUNICODE_STRING ValueName)
2724 PVALUE_CELL NewValueCell;
2730 Status = STATUS_SUCCESS;
2732 NameSize = CmiGetPackedNameLength(ValueName,
2735 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName->Length, NameSize);
2737 Status = CmiAllocateBlock(RegistryHive,
2738 (PVOID*) &NewValueCell,
2739 sizeof(VALUE_CELL) + NameSize,
2741 if ((NewValueCell == NULL) || (!NT_SUCCESS(Status)))
2743 Status = STATUS_INSUFFICIENT_RESOURCES;
2747 NewValueCell->Id = REG_VALUE_CELL_ID;
2748 NewValueCell->NameSize = NameSize;
2751 /* Pack the value name */
2752 for (i = 0; i < NameSize; i++)
2753 NewValueCell->Name[i] = (CHAR)ValueName->Buffer[i];
2754 NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
2758 /* Copy the value name */
2759 RtlCopyMemory(NewValueCell->Name,
2762 NewValueCell->Flags = 0;
2764 NewValueCell->DataType = 0;
2765 NewValueCell->DataSize = 0;
2766 NewValueCell->DataOffset = 0xffffffff;
2767 *ValueCell = NewValueCell;
2775 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
2776 PVALUE_CELL ValueCell,
2777 BLOCK_OFFSET VBOffset)
2783 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell, VBOffset);
2785 VERIFY_VALUE_CELL(ValueCell);
2787 /* Destroy the data cell */
2788 if (ValueCell->DataSize > 4)
2790 pBlock = CmiGetBlock(RegistryHive, ValueCell->DataOffset, &pBin);
2793 DPRINT("CmiGetBlock() failed\n");
2794 return STATUS_UNSUCCESSFUL;
2797 Status = CmiDestroyBlock(RegistryHive, pBlock, ValueCell->DataOffset);
2798 if (!NT_SUCCESS(Status))
2803 /* Update time of heap */
2804 if (!IsVolatileHive(RegistryHive))
2805 NtQuerySystemTime((PTIME) &pBin->DateModified);
2808 /* Destroy the value cell */
2809 Status = CmiDestroyBlock(RegistryHive, ValueCell, VBOffset);
2811 /* Update time of heap */
2812 if (!IsVolatileHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
2814 NtQuerySystemTime((PTIME) &pBin->DateModified);
2822 CmiAddBin(PREGISTRY_HIVE RegistryHive,
2824 BLOCK_OFFSET *NewBlockOffset)
2826 PCELL_HEADER tmpBlock;
2827 PHBIN * tmpBlockList;
2830 tmpBin = ExAllocatePool(PagedPool, REG_BLOCK_SIZE);
2833 return STATUS_INSUFFICIENT_RESOURCES;
2836 tmpBin->BlockId = REG_BIN_ID;
2837 tmpBin->BlockOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
2838 RegistryHive->FileSize += REG_BLOCK_SIZE;
2839 tmpBin->BlockSize = REG_BLOCK_SIZE;
2840 tmpBin->Unused1 = 0;
2841 ZwQuerySystemTime((PTIME) &tmpBin->DateModified);
2842 tmpBin->Unused2 = 0;
2844 /* Increase size of list of blocks */
2845 tmpBlockList = ExAllocatePool(NonPagedPool,
2846 sizeof(PHBIN *) * (RegistryHive->BlockListSize + 1));
2847 if (tmpBlockList == NULL)
2850 return STATUS_INSUFFICIENT_RESOURCES;
2853 if (RegistryHive->BlockListSize > 0)
2855 RtlCopyMemory (tmpBlockList,
2856 RegistryHive->BlockList,
2857 sizeof(PHBIN *)*(RegistryHive->BlockListSize));
2858 ExFreePool(RegistryHive->BlockList);
2861 RegistryHive->BlockList = tmpBlockList;
2862 RegistryHive->BlockList[RegistryHive->BlockListSize] = tmpBin;
2863 RegistryHive->BlockListSize++;
2865 /* Initialize a free block in this heap : */
2866 tmpBlock = (PCELL_HEADER)((ULONG_PTR) tmpBin + REG_HBIN_DATA_OFFSET);
2867 tmpBlock->CellSize = (REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET);
2869 /* Grow bitmap if necessary */
2870 if (IsVolatileHive(RegistryHive) &&
2871 (RegistryHive->BlockListSize % (sizeof(ULONG) * 8) == 0))
2873 PULONG BitmapBuffer;
2876 DPRINT("Grow hive bitmap\n");
2878 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
2879 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
2880 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
2881 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
2882 BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
2884 RtlZeroMemory(BitmapBuffer, BitmapSize);
2885 RtlCopyMemory(BitmapBuffer,
2886 RegistryHive->DirtyBitMap.Buffer,
2887 RegistryHive->DirtyBitMap.SizeOfBitMap);
2888 ExFreePool(RegistryHive->BitmapBuffer);
2889 RegistryHive->BitmapBuffer = BitmapBuffer;
2890 RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
2891 RegistryHive->BitmapBuffer,
2895 *NewBlock = (PVOID) tmpBlock;
2898 *NewBlockOffset = tmpBin->BlockOffset + REG_HBIN_DATA_OFFSET;
2900 /* Mark new bin dirty */
2901 CmiMarkBinDirty(RegistryHive,
2902 tmpBin->BlockOffset);
2904 return STATUS_SUCCESS;
2909 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive,
2912 BLOCK_OFFSET * pBlockOffset)
2914 PCELL_HEADER NewBlock;
2920 Status = STATUS_SUCCESS;
2922 /* Round to 16 bytes multiple */
2923 BlockSize = (BlockSize + sizeof(DWORD) + 15) & 0xfffffff0;
2925 /* Handle volatile hives first */
2926 if (IsPointerHive(RegistryHive))
2928 NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
2930 if (NewBlock == NULL)
2932 Status = STATUS_INSUFFICIENT_RESOURCES;
2936 RtlZeroMemory(NewBlock, BlockSize);
2937 NewBlock->CellSize = BlockSize;
2940 *pBlockOffset = (BLOCK_OFFSET) NewBlock;
2945 /* first search in free blocks */
2947 for (i = 0; i < RegistryHive->FreeListSize; i++)
2949 if (RegistryHive->FreeList[i]->CellSize >= BlockSize)
2951 NewBlock = RegistryHive->FreeList[i];
2953 *pBlockOffset = RegistryHive->FreeListOffset[i];
2955 /* Update time of heap */
2956 Temp = CmiGetBlock(RegistryHive, RegistryHive->FreeListOffset[i], &pBin);
2959 DPRINT("CmiGetBlock() failed\n");
2960 return STATUS_UNSUCCESSFUL;
2965 NtQuerySystemTime((PTIME) &pBin->DateModified);
2966 CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]);
2969 if ((i + 1) < RegistryHive->FreeListSize)
2971 RtlMoveMemory(&RegistryHive->FreeList[i],
2972 &RegistryHive->FreeList[i + 1],
2973 sizeof(RegistryHive->FreeList[0])
2974 * (RegistryHive->FreeListSize - i - 1));
2975 RtlMoveMemory(&RegistryHive->FreeListOffset[i],
2976 &RegistryHive->FreeListOffset[i + 1],
2977 sizeof(RegistryHive->FreeListOffset[0])
2978 * (RegistryHive->FreeListSize - i - 1));
2980 RegistryHive->FreeListSize--;
2985 /* Need to extend hive file : */
2986 if (NewBlock == NULL)
2988 /* Add a new block */
2989 Status = CmiAddBin(RegistryHive, (PVOID *) &NewBlock , pBlockOffset);
2992 if (NT_SUCCESS(Status))
2996 /* Split the block in two parts */
2997 if (NewBlock->CellSize > BlockSize)
2999 NewBlock = (PCELL_HEADER) ((ULONG_PTR) NewBlock+BlockSize);
3000 NewBlock->CellSize = ((PCELL_HEADER) (*Block))->CellSize - BlockSize;
3001 CmiAddFree(RegistryHive,
3003 *pBlockOffset + BlockSize,
3005 CmiMarkBlockDirty(RegistryHive,
3006 *pBlockOffset + BlockSize);
3008 else if (NewBlock->CellSize < BlockSize)
3010 return(STATUS_UNSUCCESSFUL);
3013 RtlZeroMemory(*Block, BlockSize);
3014 ((PCELL_HEADER) (*Block))->CellSize = -BlockSize;
3023 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive,
3025 BLOCK_OFFSET Offset)
3030 Status = STATUS_SUCCESS;
3032 if (IsPointerHive(RegistryHive))
3038 PCELL_HEADER pFree = Block;
3040 if (pFree->CellSize < 0)
3041 pFree->CellSize = -pFree->CellSize;
3043 /* Clear block (except the block size) */
3044 RtlZeroMemory(((PVOID)pFree) + sizeof(ULONG),
3045 pFree->CellSize - sizeof(ULONG));
3047 /* Add block to the list of free blocks */
3048 CmiAddFree(RegistryHive, Block, Offset, TRUE);
3050 /* Update time of heap */
3051 if (!IsVolatileHive(RegistryHive) && CmiGetBlock(RegistryHive, Offset,&pBin))
3052 NtQuerySystemTime((PTIME) &pBin->DateModified);
3054 CmiMarkBlockDirty(RegistryHive, Offset);
3062 CmiMergeFree(PREGISTRY_HIVE RegistryHive,
3063 PCELL_HEADER FreeBlock,
3064 BLOCK_OFFSET FreeOffset)
3066 BLOCK_OFFSET BlockOffset;
3067 BLOCK_OFFSET BinOffset;
3073 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3074 FreeBlock, FreeOffset, FreeBlock->CellSize);
3076 CmiGetBlock(RegistryHive,
3079 DPRINT("Bin %p\n", Bin);
3083 BinOffset = Bin->BlockOffset;
3084 BinSize = Bin->BlockSize;
3085 DPRINT("Bin %p Offset %lx Size %lx\n", Bin, BinOffset, BinSize);
3087 for (i = 0; i < RegistryHive->FreeListSize; i++)
3089 BlockOffset = RegistryHive->FreeListOffset[i];
3090 BlockSize = RegistryHive->FreeList[i]->CellSize;
3091 if (BlockOffset > BinOffset &&
3092 BlockOffset < BinOffset + BinSize)
3094 DPRINT("Free block: Offset %lx Size %lx\n",
3095 BlockOffset, BlockSize);
3097 if ((i < (RegistryHive->FreeListSize - 1)) &&
3098 (BlockOffset + BlockSize == FreeOffset) &&
3099 (FreeOffset + FreeBlock->CellSize == RegistryHive->FreeListOffset[i + 1]))
3101 DPRINT("Merge current block with previous and next block\n");
3103 RegistryHive->FreeList[i]->CellSize +=
3104 (FreeBlock->CellSize + RegistryHive->FreeList[i + 1]->CellSize);
3106 FreeBlock->CellSize = 0;
3107 RegistryHive->FreeList[i + 1]->CellSize = 0;
3110 if ((i + 2) < RegistryHive->FreeListSize)
3112 RtlMoveMemory(&RegistryHive->FreeList[i + 1],
3113 &RegistryHive->FreeList[i + 2],
3114 sizeof(RegistryHive->FreeList[0])
3115 * (RegistryHive->FreeListSize - i - 2));
3116 RtlMoveMemory(&RegistryHive->FreeListOffset[i + 1],
3117 &RegistryHive->FreeListOffset[i + 2],
3118 sizeof(RegistryHive->FreeListOffset[0])
3119 * (RegistryHive->FreeListSize - i - 2));
3121 RegistryHive->FreeListSize--;
3123 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3127 else if (BlockOffset + BlockSize == FreeOffset)
3129 DPRINT("Merge current block with previous block\n");
3131 RegistryHive->FreeList[i]->CellSize += FreeBlock->CellSize;
3132 FreeBlock->CellSize = 0;
3134 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3138 else if (FreeOffset + FreeBlock->CellSize == BlockOffset)
3140 DPRINT("Merge current block with next block\n");
3142 FreeBlock->CellSize += RegistryHive->FreeList[i]->CellSize;
3143 RegistryHive->FreeList[i]->CellSize = 0;
3144 RegistryHive->FreeList[i] = FreeBlock;
3145 RegistryHive->FreeListOffset[i] = FreeOffset;
3147 CmiMarkBlockDirty(RegistryHive, FreeOffset);
3159 CmiAddFree(PREGISTRY_HIVE RegistryHive,
3160 PCELL_HEADER FreeBlock,
3161 BLOCK_OFFSET FreeOffset,
3162 BOOLEAN MergeFreeBlocks)
3164 PCELL_HEADER *tmpList;
3165 BLOCK_OFFSET *tmpListOffset;
3170 assert(RegistryHive);
3173 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3174 FreeBlock, FreeOffset);
3176 /* Merge free blocks */
3177 if (MergeFreeBlocks == TRUE)
3179 if (CmiMergeFree(RegistryHive, FreeBlock, FreeOffset))
3180 return(STATUS_SUCCESS);
3183 if ((RegistryHive->FreeListSize + 1) > RegistryHive->FreeListMax)
3185 tmpList = ExAllocatePool(PagedPool,
3186 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax + 32));
3187 if (tmpList == NULL)
3188 return STATUS_INSUFFICIENT_RESOURCES;
3190 tmpListOffset = ExAllocatePool(PagedPool,
3191 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax + 32));
3193 if (tmpListOffset == NULL)
3195 ExFreePool(tmpList);
3196 return STATUS_INSUFFICIENT_RESOURCES;
3199 if (RegistryHive->FreeListMax)
3201 RtlMoveMemory(tmpList,
3202 RegistryHive->FreeList,
3203 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
3204 RtlMoveMemory(tmpListOffset,
3205 RegistryHive->FreeListOffset,
3206 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax));
3207 ExFreePool(RegistryHive->FreeList);
3208 ExFreePool(RegistryHive->FreeListOffset);
3210 RegistryHive->FreeList = tmpList;
3211 RegistryHive->FreeListOffset = tmpListOffset;
3212 RegistryHive->FreeListMax += 32;
3215 /* Add new offset to free list, maintaining list in ascending order */
3216 if ((RegistryHive->FreeListSize == 0)
3217 || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
3219 /* Add to end of list */
3220 RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
3221 RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
3223 else if (RegistryHive->FreeListOffset[0] > FreeOffset)
3225 /* Add to begin of list */
3226 RtlMoveMemory(&RegistryHive->FreeList[1],
3227 &RegistryHive->FreeList[0],
3228 sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
3229 RtlMoveMemory(&RegistryHive->FreeListOffset[1],
3230 &RegistryHive->FreeListOffset[0],
3231 sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
3232 RegistryHive->FreeList[0] = FreeBlock;
3233 RegistryHive->FreeListOffset[0] = FreeOffset;
3234 RegistryHive->FreeListSize++;
3238 /* Search where to insert */
3240 maxInd = RegistryHive->FreeListSize - 1;
3241 while ((maxInd - minInd) > 1)
3243 medInd = (minInd + maxInd) / 2;
3244 if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
3250 /* Insert before maxInd */
3251 RtlMoveMemory(&RegistryHive->FreeList[maxInd+1],
3252 &RegistryHive->FreeList[maxInd],
3253 sizeof(RegistryHive->FreeList[0]) * (RegistryHive->FreeListSize - minInd));
3254 RtlMoveMemory(&RegistryHive->FreeListOffset[maxInd + 1],
3255 &RegistryHive->FreeListOffset[maxInd],
3256 sizeof(RegistryHive->FreeListOffset[0]) * (RegistryHive->FreeListSize-minInd));
3257 RegistryHive->FreeList[maxInd] = FreeBlock;
3258 RegistryHive->FreeListOffset[maxInd] = FreeOffset;
3259 RegistryHive->FreeListSize++;
3262 return STATUS_SUCCESS;
3267 CmiGetBlock(PREGISTRY_HIVE RegistryHive,
3268 BLOCK_OFFSET BlockOffset,
3276 if (BlockOffset == (BLOCK_OFFSET)-1)
3281 if (IsPointerHive (RegistryHive))
3283 return (PVOID)BlockOffset;
3287 if (BlockOffset > RegistryHive->BlockListSize * 4096)
3289 DPRINT1("BlockOffset exceeds valid range (%lu > %lu)\n",
3290 BlockOffset, RegistryHive->BlockListSize * 4096);
3293 pBin = RegistryHive->BlockList[BlockOffset / 4096];
3296 return((PVOID)((ULONG_PTR)pBin + (BlockOffset - pBin->BlockOffset)));
3302 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
3303 BLOCK_OFFSET BlockOffset)
3310 if (IsVolatileHive(RegistryHive))
3313 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG)BlockOffset);
3315 BlockNumber = (ULONG)BlockOffset / 4096;
3317 Cell = CmiGetBlock(RegistryHive,
3321 CellSize = Cell->CellSize;
3323 CellSize = -CellSize;
3325 BlockCount = (ROUND_UP(BlockOffset + CellSize, 4096) - ROUND_DOWN(BlockOffset, 4096)) / 4096;
3327 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3330 (Cell->CellSize < 0) ? "used" : "free",
3333 RegistryHive->HiveDirty = TRUE;
3334 RtlSetBits(&RegistryHive->DirtyBitMap,
3341 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive,
3342 BLOCK_OFFSET BinOffset)
3348 if (IsVolatileHive(RegistryHive))
3351 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG)BinOffset);
3353 BlockNumber = (ULONG)BinOffset / 4096;
3355 Bin = RegistryHive->BlockList[BlockNumber];
3357 BlockCount = Bin->BlockSize / 4096;
3359 DPRINT(" BlockNumber %lu Size %lu BlockCount %lu\n",
3364 RegistryHive->HiveDirty = TRUE;
3365 RtlSetBits(&RegistryHive->DirtyBitMap,
3372 CmiGetPackedNameLength(IN PUNICODE_STRING Name,
3373 OUT PBOOLEAN Packable)
3377 if (Packable != NULL)
3380 for (i = 0; i < Name->Length; i++)
3382 if (Name->Buffer[i] > 0xFF)
3384 if (Packable != NULL)
3386 return(Name->Length);
3390 return(Name->Length / sizeof(WCHAR));
3395 CmiComparePackedNames(IN PUNICODE_STRING Name,
3396 IN PCHAR NameBuffer,
3397 IN USHORT NameBufferSize,
3398 IN BOOLEAN NamePacked)
3403 if (NamePacked == TRUE)
3405 if (Name->Length != NameBufferSize * sizeof(WCHAR))
3408 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3410 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar((WCHAR)NameBuffer[i]))
3416 if (Name->Length != NameBufferSize)
3419 UNameBuffer = (PWCHAR)NameBuffer;
3421 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3423 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar(UNameBuffer[i]))
3433 CmiCopyPackedName(PWCHAR NameBuffer,
3434 PCHAR PackedNameBuffer,
3435 ULONG PackedNameSize)
3439 for (i = 0; i < PackedNameSize; i++)
3440 NameBuffer[i] = (WCHAR)PackedNameBuffer[i];