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
;
1179 DPRINT("CmiStartLogUpdate() called\n");
1181 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1182 BufferSize
= sizeof(HIVE_HEADER
) +
1185 BufferSize
= ROUND_UP(BufferSize
, 4096);
1187 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1189 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1192 DPRINT("ExAllocatePool() failed\n");
1193 return(STATUS_INSUFFICIENT_RESOURCES
);
1196 /* Open log file for writing */
1197 InitializeObjectAttributes(&ObjectAttributes
,
1198 &RegistryHive
->LogFileName
,
1203 Status
= NtCreateFile(&FileHandle
,
1208 FILE_ATTRIBUTE_NORMAL
,
1211 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1214 if (!NT_SUCCESS(Status
))
1216 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1221 /* Update firt update counter and checksum */
1222 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1223 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1225 /* Copy hive header */
1226 RtlCopyMemory(Buffer
,
1227 RegistryHive
->HiveHeader
,
1228 sizeof(HIVE_HEADER
));
1229 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1236 RegistryHive
->DirtyBitMap
.Buffer
,
1239 /* Write hive block and block bitmap */
1240 FileOffset
.QuadPart
= 0ULL;
1241 Status
= NtWriteFile(FileHandle
,
1250 if (!NT_SUCCESS(Status
))
1252 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1253 NtClose(FileHandle
);
1259 /* Write dirty blocks */
1260 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1264 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1267 if (BlockIndex
== (ULONG
)-1)
1269 DPRINT("No more set bits\n");
1270 Status
= STATUS_SUCCESS
;
1274 DPRINT("Block %lu is dirty\n", BlockIndex
);
1276 BlockOffset
= RegistryHive
->BlockList
[BlockIndex
]->BlockOffset
;
1277 DPRINT("Block offset %lx\n", BlockOffset
);
1279 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
] + ((BlockIndex
* 4096) - BlockOffset
);
1280 DPRINT("BlockPtr %p\n", BlockPtr
);
1282 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1284 /* Write hive block */
1285 Status
= NtWriteFile(FileHandle
,
1294 if (!NT_SUCCESS(Status
))
1296 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1297 NtClose(FileHandle
);
1302 FileOffset
.QuadPart
+= 4096ULL;
1305 /* Truncate log file */
1306 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1307 Status
= NtSetInformationFile(FileHandle
,
1310 sizeof(FILE_END_OF_FILE_INFORMATION
),
1311 FileEndOfFileInformation
);
1312 if (!NT_SUCCESS(Status
))
1314 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1315 NtClose(FileHandle
);
1319 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1320 Status
= NtSetInformationFile(FileHandle
,
1322 &FileAllocationInfo
,
1323 sizeof(FILE_ALLOCATION_INFORMATION
),
1324 FileAllocationInformation
);
1325 if (!NT_SUCCESS(Status
))
1327 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1328 NtClose(FileHandle
);
1332 /* Flush the log file */
1333 Status
= NtFlushBuffersFile(FileHandle
,
1335 if (!NT_SUCCESS(Status
))
1337 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1340 NtClose(FileHandle
);
1347 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1349 OBJECT_ATTRIBUTES ObjectAttributes
;
1350 IO_STATUS_BLOCK IoStatusBlock
;
1352 LARGE_INTEGER FileOffset
;
1359 DPRINT("CmiFinishLogUpdate() called\n");
1361 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1362 BufferSize
= sizeof(HIVE_HEADER
) +
1365 BufferSize
= ROUND_UP(BufferSize
, 4096);
1367 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1369 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1372 DPRINT("ExAllocatePool() failed\n");
1373 return(STATUS_INSUFFICIENT_RESOURCES
);
1376 /* Open log file for writing */
1377 InitializeObjectAttributes(&ObjectAttributes
,
1378 &RegistryHive
->LogFileName
,
1383 Status
= NtCreateFile(&FileHandle
,
1388 FILE_ATTRIBUTE_NORMAL
,
1391 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1394 if (!NT_SUCCESS(Status
))
1396 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1401 /* Update first and second update counter and checksum */
1402 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1403 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1404 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1406 /* Copy hive header */
1407 RtlCopyMemory(Buffer
,
1408 RegistryHive
->HiveHeader
,
1409 sizeof(HIVE_HEADER
));
1410 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1412 /* Write empty block bitmap */
1420 /* Write hive block and block bitmap */
1421 FileOffset
.QuadPart
= 0ULL;
1422 Status
= NtWriteFile(FileHandle
,
1431 if (!NT_SUCCESS(Status
))
1433 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1434 NtClose(FileHandle
);
1441 /* Flush the log file */
1442 Status
= NtFlushBuffersFile(FileHandle
,
1444 if (!NT_SUCCESS(Status
))
1446 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1449 NtClose(FileHandle
);
1456 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1458 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1459 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1460 OBJECT_ATTRIBUTES ObjectAttributes
;
1461 IO_STATUS_BLOCK IoStatusBlock
;
1467 DPRINT("CmiFinishLogUpdate() called\n");
1469 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1470 BufferSize
= sizeof(HIVE_HEADER
) +
1473 BufferSize
= ROUND_UP(BufferSize
, 4096);
1475 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1477 /* Open log file for writing */
1478 InitializeObjectAttributes(&ObjectAttributes
,
1479 &RegistryHive
->LogFileName
,
1484 Status
= NtCreateFile(&FileHandle
,
1489 FILE_ATTRIBUTE_NORMAL
,
1492 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1495 if (!NT_SUCCESS(Status
))
1497 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1501 /* Truncate log file */
1502 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1503 Status
= NtSetInformationFile(FileHandle
,
1506 sizeof(FILE_END_OF_FILE_INFORMATION
),
1507 FileEndOfFileInformation
);
1508 if (!NT_SUCCESS(Status
))
1510 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1511 NtClose(FileHandle
);
1515 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1516 Status
= NtSetInformationFile(FileHandle
,
1518 &FileAllocationInfo
,
1519 sizeof(FILE_ALLOCATION_INFORMATION
),
1520 FileAllocationInformation
);
1521 if (!NT_SUCCESS(Status
))
1523 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1524 NtClose(FileHandle
);
1528 /* Flush the log file */
1529 Status
= NtFlushBuffersFile(FileHandle
,
1531 if (!NT_SUCCESS(Status
))
1533 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1536 NtClose(FileHandle
);
1543 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1545 OBJECT_ATTRIBUTES ObjectAttributes
;
1546 IO_STATUS_BLOCK IoStatusBlock
;
1548 LARGE_INTEGER FileOffset
;
1554 DPRINT("CmiStartHiveUpdate() called\n");
1556 /* Open hive for writing */
1557 InitializeObjectAttributes(&ObjectAttributes
,
1558 &RegistryHive
->HiveFileName
,
1563 Status
= NtCreateFile(&FileHandle
,
1568 FILE_ATTRIBUTE_NORMAL
,
1571 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1574 if (!NT_SUCCESS(Status
))
1576 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1580 /* Update firt update counter and checksum */
1581 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1582 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1584 /* Write hive block */
1585 FileOffset
.QuadPart
= 0ULL;
1586 Status
= NtWriteFile(FileHandle
,
1591 RegistryHive
->HiveHeader
,
1592 sizeof(HIVE_HEADER
),
1595 if (!NT_SUCCESS(Status
))
1597 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1598 NtClose(FileHandle
);
1605 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1608 if (BlockIndex
== (ULONG
)-1)
1610 DPRINT("No more set bits\n");
1611 Status
= STATUS_SUCCESS
;
1615 DPRINT("Block %lu is dirty\n", BlockIndex
);
1617 BlockOffset
= RegistryHive
->BlockList
[BlockIndex
]->BlockOffset
;
1618 DPRINT("Block offset %lx\n", BlockOffset
);
1620 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
] + ((BlockIndex
* 4096) - BlockOffset
);
1621 DPRINT("BlockPtr %p\n", BlockPtr
);
1623 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096ULL;
1624 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1627 /* Write hive block */
1628 Status
= NtWriteFile(FileHandle
,
1637 if (!NT_SUCCESS(Status
))
1639 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1640 NtClose(FileHandle
);
1647 Status
= NtFlushBuffersFile(FileHandle
,
1649 if (!NT_SUCCESS(Status
))
1651 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1654 NtClose(FileHandle
);
1661 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1663 OBJECT_ATTRIBUTES ObjectAttributes
;
1664 IO_STATUS_BLOCK IoStatusBlock
;
1665 LARGE_INTEGER FileOffset
;
1669 DPRINT("CmiFinishHiveUpdate() called\n");
1671 InitializeObjectAttributes(&ObjectAttributes
,
1672 &RegistryHive
->HiveFileName
,
1677 Status
= NtCreateFile(&FileHandle
,
1682 FILE_ATTRIBUTE_NORMAL
,
1685 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1688 if (!NT_SUCCESS(Status
))
1690 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1694 /* Update second update counter and checksum */
1695 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1696 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1697 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1699 /* Write hive block */
1700 FileOffset
.QuadPart
= 0ULL;
1701 Status
= NtWriteFile(FileHandle
,
1706 RegistryHive
->HiveHeader
,
1707 sizeof(HIVE_HEADER
),
1710 if (!NT_SUCCESS(Status
))
1712 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1713 NtClose(FileHandle
);
1717 Status
= NtFlushBuffersFile(FileHandle
,
1719 if (!NT_SUCCESS(Status
))
1721 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1724 NtClose(FileHandle
);
1731 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1735 DPRINT("CmiFlushRegistryHive() called\n");
1737 if (RegistryHive
->HiveDirty
== FALSE
)
1739 return(STATUS_SUCCESS
);
1742 DPRINT("Hive '%wZ' is dirty\n",
1743 &RegistryHive
->HiveFileName
);
1744 DPRINT("Log file: '%wZ'\n",
1745 &RegistryHive
->LogFileName
);
1747 /* Update hive header modification time */
1748 NtQuerySystemTime((PTIME
)&RegistryHive
->HiveHeader
->DateModified
);
1750 /* Start log update */
1751 Status
= CmiStartLogUpdate(RegistryHive
);
1752 if (!NT_SUCCESS(Status
))
1754 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1758 /* Finish log update */
1759 Status
= CmiFinishLogUpdate(RegistryHive
);
1760 if (!NT_SUCCESS(Status
))
1762 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1766 /* Start hive update */
1767 Status
= CmiStartHiveUpdate(RegistryHive
);
1768 if (!NT_SUCCESS(Status
))
1770 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1774 /* Finish the hive update */
1775 Status
= CmiFinishHiveUpdate(RegistryHive
);
1776 if (!NT_SUCCESS(Status
))
1778 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
1782 /* Cleanup log update */
1783 Status
= CmiCleanupLogUpdate(RegistryHive
);
1784 if (!NT_SUCCESS(Status
))
1786 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1790 /* Increment hive update counter */
1791 RegistryHive
->UpdateCounter
++;
1793 /* Clear dirty bitmap and dirty flag */
1794 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
1795 RegistryHive
->HiveDirty
= FALSE
;
1797 DPRINT("CmiFlushRegistryHive() done\n");
1799 return(STATUS_SUCCESS
);
1804 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive
,
1807 PHASH_TABLE_CELL HashBlock
;
1808 PKEY_CELL CurSubKeyCell
;
1812 VERIFY_KEY_CELL(KeyCell
);
1815 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1816 if (HashBlock
== NULL
)
1821 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1823 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
1825 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1826 HashBlock
->Table
[i
].KeyOffset
,
1828 if (MaxName
< CurSubKeyCell
->NameSize
)
1830 MaxName
= CurSubKeyCell
->NameSize
;
1840 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive
,
1843 PHASH_TABLE_CELL HashBlock
;
1844 PKEY_CELL CurSubKeyCell
;
1848 VERIFY_KEY_CELL(KeyCell
);
1851 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1852 if (HashBlock
== NULL
)
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 (MaxClass
< CurSubKeyCell
->ClassSize
)
1866 MaxClass
= CurSubKeyCell
->ClassSize
;
1876 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
1879 PVALUE_LIST_CELL ValueListCell
;
1880 PVALUE_CELL CurValueCell
;
1884 VERIFY_KEY_CELL(KeyCell
);
1886 ValueListCell
= CmiGetBlock(RegistryHive
,
1887 KeyCell
->ValuesOffset
,
1890 if (ValueListCell
== NULL
)
1895 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1897 CurValueCell
= CmiGetBlock(RegistryHive
,
1898 ValueListCell
->Values
[i
],
1900 if (CurValueCell
!= NULL
&&
1901 MaxValueName
< CurValueCell
->NameSize
)
1903 MaxValueName
= CurValueCell
->NameSize
;
1907 return MaxValueName
;
1912 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
1915 PVALUE_LIST_CELL ValueListCell
;
1916 PVALUE_CELL CurValueCell
;
1920 VERIFY_KEY_CELL(KeyCell
);
1922 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1924 if (ValueListCell
== NULL
)
1929 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1931 CurValueCell
= CmiGetBlock(RegistryHive
,
1932 ValueListCell
->Values
[i
],NULL
);
1933 if ((CurValueCell
!= NULL
) &&
1934 (MaxValueData
< (CurValueCell
->DataSize
& LONG_MAX
)))
1936 MaxValueData
= CurValueCell
->DataSize
& LONG_MAX
;
1940 return MaxValueData
;
1945 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
1946 IN PKEY_CELL KeyCell
,
1947 OUT PKEY_CELL
*SubKeyCell
,
1948 OUT BLOCK_OFFSET
*BlockOffset
,
1950 IN ACCESS_MASK DesiredAccess
,
1951 IN ULONG Attributes
)
1953 PHASH_TABLE_CELL HashBlock
;
1954 PKEY_CELL CurSubKeyCell
;
1958 VERIFY_KEY_CELL(KeyCell
);
1960 //DPRINT("Scanning for sub key %s\n", KeyName);
1962 assert(RegistryHive
);
1965 KeyLength
= strlen(KeyName
);
1967 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1968 if (HashBlock
== NULL
)
1970 return STATUS_SUCCESS
;
1973 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
)
1974 && (i
< HashBlock
->HashTableSize
); i
++)
1976 if (Attributes
& OBJ_CASE_INSENSITIVE
)
1978 if ((HashBlock
->Table
[i
].KeyOffset
!= 0) &&
1979 (HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1) &&
1980 (_strnicmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4) == 0))
1982 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1983 HashBlock
->Table
[i
].KeyOffset
,
1985 if ((CurSubKeyCell
->NameSize
== KeyLength
)
1986 && (_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
) == 0))
1988 *SubKeyCell
= CurSubKeyCell
;
1989 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
1996 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
1997 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
1998 !strncmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4))
2000 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
2001 HashBlock
->Table
[i
].KeyOffset
,NULL
);
2002 if (CurSubKeyCell
->NameSize
== KeyLength
2003 && !_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
))
2005 *SubKeyCell
= CurSubKeyCell
;
2006 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2013 return STATUS_SUCCESS
;
2018 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2021 PWSTR NewSubKeyName
,
2022 USHORT NewSubKeyNameSize
,
2024 PUNICODE_STRING Class
,
2025 ULONG CreateOptions
)
2027 PHASH_TABLE_CELL NewHashBlock
;
2028 PHASH_TABLE_CELL HashBlock
;
2029 BLOCK_OFFSET NKBOffset
;
2030 PKEY_CELL NewKeyCell
;
2036 KeyCell
= Parent
->KeyCell
;
2038 VERIFY_KEY_CELL(KeyCell
);
2040 if (NewSubKeyName
[0] == L
'\\')
2043 NameSize
= NewSubKeyNameSize
/ 2 - 1;
2047 NameSize
= NewSubKeyNameSize
/ 2;
2049 Status
= STATUS_SUCCESS
;
2051 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2052 Status
= CmiAllocateBlock(RegistryHive
,
2053 (PVOID
) &NewKeyCell
,
2057 if (NewKeyCell
== NULL
)
2059 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2063 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2064 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
2065 ZwQuerySystemTime((PTIME
) &NewKeyCell
->LastWriteTime
);
2066 NewKeyCell
->ParentKeyOffset
= -1;
2067 NewKeyCell
->NumberOfSubKeys
= 0;
2068 NewKeyCell
->HashTableOffset
= -1;
2069 NewKeyCell
->NumberOfValues
= 0;
2070 NewKeyCell
->ValuesOffset
= -1;
2071 NewKeyCell
->SecurityKeyOffset
= -1;
2072 NewKeyCell
->NameSize
= NameSize
;
2073 wcstombs(NewKeyCell
->Name
, NewSubKeyName
, NameSize
);
2074 NewKeyCell
->ClassNameOffset
= -1;
2076 VERIFY_KEY_CELL(NewKeyCell
);
2082 NewKeyCell
->ClassSize
= Class
->Length
+ sizeof(WCHAR
);
2083 Status
= CmiAllocateBlock(RegistryHive
,
2085 NewKeyCell
->ClassSize
,
2086 &NewKeyCell
->ClassNameOffset
);
2087 wcsncpy((PWSTR
) pClass
->Data
, Class
->Buffer
, Class
->Length
);
2088 ((PWSTR
) (pClass
->Data
))[Class
->Length
] = 0;
2092 if (!NT_SUCCESS(Status
))
2097 SubKey
->KeyCell
= NewKeyCell
;
2098 SubKey
->BlockOffset
= NKBOffset
;
2100 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2101 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(Parent
->RegistryHive
)))
2106 if (KeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2108 Status
= CmiAllocateHashTableBlock(RegistryHive
,
2110 &KeyCell
->HashTableOffset
,
2111 REG_INIT_HASH_TABLE_SIZE
);
2112 if (!NT_SUCCESS(Status
))
2119 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2120 if (((KeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2122 BLOCK_OFFSET HTOffset
;
2124 /* Reallocate the hash table block */
2125 Status
= CmiAllocateHashTableBlock(RegistryHive
,
2128 HashBlock
->HashTableSize
+
2129 REG_EXTEND_HASH_TABLE_SIZE
);
2130 if (!NT_SUCCESS(Status
))
2135 RtlZeroMemory(&NewHashBlock
->Table
[0],
2136 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2137 RtlCopyMemory(&NewHashBlock
->Table
[0],
2138 &HashBlock
->Table
[0],
2139 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2140 CmiDestroyBlock(RegistryHive
,
2142 KeyCell
->HashTableOffset
);
2143 KeyCell
->HashTableOffset
= HTOffset
;
2144 HashBlock
= NewHashBlock
;
2148 Status
= CmiAddKeyToHashTable(RegistryHive
,
2152 if (NT_SUCCESS(Status
))
2154 KeyCell
->NumberOfSubKeys
++;
2162 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2163 PKEY_OBJECT ParentKey
,
2166 PHASH_TABLE_CELL HashBlock
;
2167 PVALUE_LIST_CELL ValueList
;
2168 PVALUE_CELL ValueCell
;
2169 PDATA_CELL DataCell
;
2172 DPRINT("CmiRemoveSubKey() called\n");
2174 /* Remove all values */
2175 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2177 /* Get pointer to the value list cell */
2178 ValueList
= CmiGetBlock(RegistryHive
,
2179 SubKey
->KeyCell
->ValuesOffset
,
2181 if (ValueList
!= NULL
)
2183 /* Enumerate all values */
2184 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2186 /* Get pointer to value cell */
2187 ValueCell
= CmiGetBlock(RegistryHive
,
2188 ValueList
->Values
[i
],
2190 if (ValueCell
!= NULL
)
2192 if (ValueCell
->DataSize
> 4)
2194 DataCell
= CmiGetBlock(RegistryHive
,
2195 ValueCell
->DataOffset
,
2197 if (DataCell
!= NULL
)
2199 /* Destroy data cell */
2200 CmiDestroyBlock(RegistryHive
,
2202 ValueCell
->DataOffset
);
2206 /* Destroy value cell */
2207 CmiDestroyBlock(RegistryHive
,
2209 ValueList
->Values
[i
]);
2214 /* Destroy value list cell */
2215 CmiDestroyBlock(RegistryHive
,
2217 SubKey
->KeyCell
->ValuesOffset
);
2219 SubKey
->KeyCell
->NumberOfValues
= 0;
2220 SubKey
->KeyCell
->ValuesOffset
= -1;
2223 /* Remove the key from the parent key's hash block */
2224 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2226 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
)
2227 HashBlock
= CmiGetBlock(RegistryHive
,
2228 ParentKey
->KeyCell
->HashTableOffset
,
2230 DPRINT("ParentKey HashBlock %p\n", HashBlock
)
2231 if (HashBlock
!= NULL
)
2233 CmiRemoveKeyFromHashTable(RegistryHive
,
2235 SubKey
->BlockOffset
);
2236 CmiMarkBlockDirty(RegistryHive
,
2237 ParentKey
->KeyCell
->HashTableOffset
);
2241 /* Remove the key's hash block */
2242 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2244 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
)
2245 HashBlock
= CmiGetBlock(RegistryHive
,
2246 SubKey
->KeyCell
->HashTableOffset
,
2248 DPRINT("SubKey HashBlock %p\n", HashBlock
)
2249 if (HashBlock
!= NULL
)
2251 CmiDestroyBlock(RegistryHive
,
2253 SubKey
->KeyCell
->HashTableOffset
);
2254 SubKey
->KeyCell
->HashTableOffset
= -1;
2258 /* Decrement the number of the parent key's sub keys */
2259 if (ParentKey
!= NULL
)
2261 DPRINT("ParentKey %p\n", ParentKey
)
2262 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2264 /* Remove the parent key's hash table */
2265 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2267 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
)
2268 HashBlock
= CmiGetBlock(RegistryHive
,
2269 ParentKey
->KeyCell
->HashTableOffset
,
2271 DPRINT("ParentKey HashBlock %p\n", HashBlock
)
2272 if (HashBlock
!= NULL
)
2274 CmiDestroyBlock(RegistryHive
,
2276 ParentKey
->KeyCell
->HashTableOffset
);
2277 ParentKey
->KeyCell
->HashTableOffset
= -1;
2281 NtQuerySystemTime((PTIME
)&ParentKey
->KeyCell
->LastWriteTime
);
2282 CmiMarkBlockDirty(RegistryHive
,
2283 ParentKey
->BlockOffset
);
2286 /* Destroy key cell */
2287 CmiDestroyBlock(RegistryHive
,
2289 SubKey
->BlockOffset
);
2290 SubKey
->BlockOffset
= -1;
2291 SubKey
->KeyCell
= NULL
;
2293 return(STATUS_SUCCESS
);
2298 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2299 IN PKEY_CELL KeyCell
,
2300 IN PUNICODE_STRING ValueName
,
2301 OUT PVALUE_CELL
*ValueCell
,
2302 OUT BLOCK_OFFSET
*VBOffset
)
2304 PVALUE_LIST_CELL ValueListCell
;
2305 PVALUE_CELL CurValueCell
;
2310 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2311 if (ValueListCell
== NULL
)
2313 DPRINT("ValueListCell is NULL\n");
2314 return STATUS_SUCCESS
;
2317 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2319 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2321 CurValueCell
= CmiGetBlock(RegistryHive
,
2322 ValueListCell
->Values
[i
],
2325 if ((CurValueCell
!= NULL
) &&
2326 CmiComparePackedNames(ValueName
,
2328 CurValueCell
->NameSize
,
2329 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
2331 *ValueCell
= CurValueCell
;
2333 *VBOffset
= ValueListCell
->Values
[i
];
2334 //DPRINT("Found value %s\n", ValueName);
2339 return STATUS_SUCCESS
;
2344 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2345 IN PKEY_CELL KeyCell
,
2347 OUT PVALUE_CELL
*ValueCell
)
2349 PVALUE_LIST_CELL ValueListCell
;
2350 PVALUE_CELL CurValueCell
;
2354 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2355 if (ValueListCell
== NULL
)
2357 return STATUS_NO_MORE_ENTRIES
;
2360 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2362 if (Index
>= KeyCell
->NumberOfValues
)
2364 return STATUS_NO_MORE_ENTRIES
;
2367 CurValueCell
= CmiGetBlock(RegistryHive
,
2368 ValueListCell
->Values
[Index
],
2370 if (CurValueCell
!= NULL
)
2372 *ValueCell
= CurValueCell
;
2375 return STATUS_SUCCESS
;
2380 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2381 IN PKEY_CELL KeyCell
,
2382 IN PUNICODE_STRING ValueName
,
2383 OUT PVALUE_CELL
*pValueCell
,
2384 OUT BLOCK_OFFSET
*pVBOffset
)
2386 PVALUE_LIST_CELL NewValueListCell
;
2387 PVALUE_LIST_CELL ValueListCell
;
2388 PVALUE_CELL NewValueCell
;
2389 BLOCK_OFFSET VLBOffset
;
2390 BLOCK_OFFSET VBOffset
;
2393 *pVBOffset
= VBOffset
;
2395 Status
= CmiAllocateValueCell(RegistryHive
,
2399 if (!NT_SUCCESS(Status
))
2404 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2406 if (ValueListCell
== NULL
)
2408 Status
= CmiAllocateBlock(RegistryHive
,
2409 (PVOID
) &ValueListCell
,
2410 sizeof(BLOCK_OFFSET
) * 3,
2413 if (!NT_SUCCESS(Status
))
2415 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2418 KeyCell
->ValuesOffset
= VLBOffset
;
2420 else if (KeyCell
->NumberOfValues
>=
2421 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - 4) / sizeof(BLOCK_OFFSET
)))
2423 Status
= CmiAllocateBlock(RegistryHive
,
2424 (PVOID
) &NewValueListCell
,
2425 (KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) *
2426 sizeof(BLOCK_OFFSET
),
2428 if (!NT_SUCCESS(Status
))
2430 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2434 RtlCopyMemory(&NewValueListCell
->Values
[0],
2435 &ValueListCell
->Values
[0],
2436 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2437 CmiDestroyBlock(RegistryHive
, ValueListCell
, KeyCell
->ValuesOffset
);
2438 KeyCell
->ValuesOffset
= VLBOffset
;
2439 ValueListCell
= NewValueListCell
;
2442 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2443 KeyCell
->NumberOfValues
,
2444 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2445 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - 4) / sizeof(BLOCK_OFFSET
),
2446 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - 4) / sizeof(BLOCK_OFFSET
));
2448 ValueListCell
->Values
[KeyCell
->NumberOfValues
] = VBOffset
;
2449 KeyCell
->NumberOfValues
++;
2451 *pValueCell
= NewValueCell
;
2453 return STATUS_SUCCESS
;
2458 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2459 IN PKEY_CELL KeyCell
,
2460 IN BLOCK_OFFSET KeyCellOffset
,
2461 IN PUNICODE_STRING ValueName
)
2463 PVALUE_LIST_CELL ValueListCell
;
2464 PVALUE_CELL CurValueCell
;
2467 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2469 if (ValueListCell
== NULL
)
2471 return STATUS_SUCCESS
;
2474 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2476 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2478 CurValueCell
= CmiGetBlock(RegistryHive
, ValueListCell
->Values
[i
], NULL
);
2480 if ((CurValueCell
!= NULL
) &&
2481 CmiComparePackedNames(ValueName
,
2483 CurValueCell
->NameSize
,
2484 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
2486 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->Values
[i
]);
2488 if ((KeyCell
->NumberOfValues
- 1) < i
)
2490 RtlCopyMemory(&ValueListCell
->Values
[i
],
2491 &ValueListCell
->Values
[i
+ 1],
2492 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2496 RtlZeroMemory(&ValueListCell
->Values
[i
], sizeof(BLOCK_OFFSET
));
2499 KeyCell
->NumberOfValues
-= 1;
2504 if (KeyCell
->NumberOfValues
== 0)
2506 CmiDestroyBlock(RegistryHive
,
2508 KeyCell
->ValuesOffset
);
2512 CmiMarkBlockDirty(RegistryHive
,
2513 KeyCell
->ValuesOffset
);
2516 CmiMarkBlockDirty(RegistryHive
,
2519 return STATUS_SUCCESS
;
2524 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive
,
2525 OUT PHASH_TABLE_CELL
*HashBlock
,
2526 OUT BLOCK_OFFSET
*HBOffset
,
2527 IN ULONG HashTableSize
)
2529 PHASH_TABLE_CELL NewHashBlock
;
2533 Status
= STATUS_SUCCESS
;
2535 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
2536 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
2537 Status
= CmiAllocateBlock(RegistryHive
,
2538 (PVOID
*) &NewHashBlock
,
2542 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
2544 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2548 NewHashBlock
->Id
= REG_HASH_TABLE_BLOCK_ID
;
2549 NewHashBlock
->HashTableSize
= HashTableSize
;
2550 *HashBlock
= NewHashBlock
;
2558 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
2559 PHASH_TABLE_CELL HashBlock
,
2562 BLOCK_OFFSET KeyOffset
;
2565 if (HashBlock
== NULL
)
2568 if (IsPointerHive(RegistryHive
))
2570 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
2574 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
2575 KeyCell
= CmiGetBlock(RegistryHive
, KeyOffset
, NULL
);
2583 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
2584 PHASH_TABLE_CELL HashBlock
,
2585 PKEY_CELL NewKeyCell
,
2586 BLOCK_OFFSET NKBOffset
)
2590 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2592 if (HashBlock
->Table
[i
].KeyOffset
== 0)
2594 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
2595 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
, NewKeyCell
->Name
, 4);
2596 return STATUS_SUCCESS
;
2600 return STATUS_UNSUCCESSFUL
;
2605 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
2606 PHASH_TABLE_CELL HashBlock
,
2607 BLOCK_OFFSET NKBOffset
)
2611 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2613 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
2615 HashBlock
->Table
[i
].KeyOffset
= 0;
2616 RtlZeroMemory(&HashBlock
->Table
[i
].HashValue
, 4);
2617 return STATUS_SUCCESS
;
2621 return STATUS_UNSUCCESSFUL
;
2626 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
2627 PVALUE_CELL
*ValueCell
,
2628 BLOCK_OFFSET
*VBOffset
,
2629 IN PUNICODE_STRING ValueName
)
2631 PVALUE_CELL NewValueCell
;
2637 Status
= STATUS_SUCCESS
;
2639 NameSize
= CmiGetPackedNameLength(ValueName
,
2642 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
2644 Status
= CmiAllocateBlock(RegistryHive
,
2645 (PVOID
*) &NewValueCell
,
2646 sizeof(VALUE_CELL
) + NameSize
,
2648 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
2650 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2654 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
2655 NewValueCell
->NameSize
= NameSize
;
2658 /* Pack the value name */
2659 for (i
= 0; i
< NameSize
; i
++)
2660 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
2661 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
2665 /* Copy the value name */
2666 RtlCopyMemory(NewValueCell
->Name
,
2669 NewValueCell
->Flags
= 0;
2671 NewValueCell
->DataType
= 0;
2672 NewValueCell
->DataSize
= 0;
2673 NewValueCell
->DataOffset
= 0xffffffff;
2674 *ValueCell
= NewValueCell
;
2682 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
2683 PVALUE_CELL ValueCell
,
2684 BLOCK_OFFSET VBOffset
)
2690 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell
, VBOffset
);
2692 VERIFY_VALUE_CELL(ValueCell
);
2694 /* Destroy the data cell */
2695 if (ValueCell
->DataSize
> 4)
2697 pBlock
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, &pBin
);
2698 Status
= CmiDestroyBlock(RegistryHive
, pBlock
, ValueCell
->DataOffset
);
2699 if (!NT_SUCCESS(Status
))
2704 /* Update time of heap */
2705 if (!IsVolatileHive(RegistryHive
))
2706 NtQuerySystemTime((PTIME
) &pBin
->DateModified
);
2709 /* Destroy the value cell */
2710 Status
= CmiDestroyBlock(RegistryHive
, ValueCell
, VBOffset
);
2712 /* Update time of heap */
2713 if (!IsVolatileHive(RegistryHive
) && CmiGetBlock(RegistryHive
, VBOffset
, &pBin
))
2715 NtQuerySystemTime((PTIME
) &pBin
->DateModified
);
2723 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
2725 BLOCK_OFFSET
*NewBlockOffset
)
2727 PCELL_HEADER tmpBlock
;
2728 PHBIN
* tmpBlockList
;
2731 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
2734 return STATUS_INSUFFICIENT_RESOURCES
;
2737 tmpBin
->BlockId
= REG_BIN_ID
;
2738 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
2739 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
2740 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
2741 tmpBin
->Unused1
= 0;
2742 ZwQuerySystemTime((PTIME
) &tmpBin
->DateModified
);
2743 tmpBin
->Unused2
= 0;
2745 /* Increase size of list of blocks */
2746 tmpBlockList
= ExAllocatePool(NonPagedPool
,
2747 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
2748 if (tmpBlockList
== NULL
)
2751 return STATUS_INSUFFICIENT_RESOURCES
;
2754 if (RegistryHive
->BlockListSize
> 0)
2756 memcpy(tmpBlockList
,
2757 RegistryHive
->BlockList
,
2758 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
2759 ExFreePool(RegistryHive
->BlockList
);
2762 RegistryHive
->BlockList
= tmpBlockList
;
2763 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
++] = tmpBin
;
2765 /* Initialize a free block in this heap : */
2766 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
2767 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
2769 /* Grow bitmap if necessary */
2770 if (IsVolatileHive(RegistryHive
) &&
2771 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
2773 PULONG BitmapBuffer
;
2776 DPRINT1("Grow hive bitmap\n");
2778 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
2779 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
2780 DPRINT1("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
2781 DPRINT1("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
2782 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
2784 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
2785 RtlCopyMemory(BitmapBuffer
,
2786 RegistryHive
->DirtyBitMap
.Buffer
,
2787 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
2788 ExFreePool(RegistryHive
->BitmapBuffer
);
2789 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
2790 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
2791 RegistryHive
->BitmapBuffer
,
2795 *NewBlock
= (PVOID
) tmpBlock
;
2798 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
2800 /* Mark new bin dirty */
2801 CmiMarkBinDirty(RegistryHive
,
2802 tmpBin
->BlockOffset
);
2804 return STATUS_SUCCESS
;
2809 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive
,
2812 BLOCK_OFFSET
* pBlockOffset
)
2814 PCELL_HEADER NewBlock
;
2818 Status
= STATUS_SUCCESS
;
2820 /* Round to 16 bytes multiple */
2821 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
2823 /* Handle volatile hives first */
2824 if (IsPointerHive(RegistryHive
))
2826 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
2828 if (NewBlock
== NULL
)
2830 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2834 RtlZeroMemory(NewBlock
, BlockSize
);
2835 NewBlock
->CellSize
= BlockSize
;
2838 *pBlockOffset
= (BLOCK_OFFSET
) NewBlock
;
2845 /* first search in free blocks */
2847 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
2849 if (RegistryHive
->FreeList
[i
]->CellSize
>= BlockSize
)
2853 NewBlock
= RegistryHive
->FreeList
[i
];
2855 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
2857 /* Update time of heap */
2858 Temp
= CmiGetBlock(RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
2862 NtQuerySystemTime((PTIME
) &pBin
->DateModified
);
2863 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
2866 if ((i
+ 1) < RegistryHive
->FreeListSize
)
2868 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
2869 &RegistryHive
->FreeList
[i
+ 1],
2870 sizeof(RegistryHive
->FreeList
[0])
2871 * (RegistryHive
->FreeListSize
- i
- 1));
2872 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
2873 &RegistryHive
->FreeListOffset
[i
+ 1],
2874 sizeof(RegistryHive
->FreeListOffset
[0])
2875 * (RegistryHive
->FreeListSize
- i
- 1));
2877 RegistryHive
->FreeListSize
--;
2882 /* Need to extend hive file : */
2883 if (NewBlock
== NULL
)
2885 /* Add a new block */
2886 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewBlock
, pBlockOffset
);
2889 if (NT_SUCCESS(Status
))
2893 /* Split the block in two parts */
2894 if (NewBlock
->CellSize
> BlockSize
)
2896 NewBlock
= (PCELL_HEADER
) ((ULONG_PTR
) NewBlock
+BlockSize
);
2897 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- BlockSize
;
2898 CmiAddFree(RegistryHive
,
2900 *pBlockOffset
+ BlockSize
,
2902 CmiMarkBlockDirty(RegistryHive
,
2903 *pBlockOffset
+ BlockSize
);
2905 else if (NewBlock
->CellSize
< BlockSize
)
2907 return(STATUS_UNSUCCESSFUL
);
2910 RtlZeroMemory(*Block
, BlockSize
);
2911 ((PCELL_HEADER
) (*Block
))->CellSize
= -BlockSize
;
2920 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive
,
2922 BLOCK_OFFSET Offset
)
2927 Status
= STATUS_SUCCESS
;
2929 if (IsPointerHive(RegistryHive
))
2935 PCELL_HEADER pFree
= Block
;
2937 if (pFree
->CellSize
< 0)
2938 pFree
->CellSize
= -pFree
->CellSize
;
2940 /* Clear block (except the block size) */
2941 RtlZeroMemory(((PVOID
)pFree
) + sizeof(ULONG
),
2942 pFree
->CellSize
- sizeof(ULONG
));
2944 /* Add block to the list of free blocks */
2945 CmiAddFree(RegistryHive
, Block
, Offset
, TRUE
);
2947 /* Update time of heap */
2948 if (!IsVolatileHive(RegistryHive
) && CmiGetBlock(RegistryHive
, Offset
,&pBin
))
2949 NtQuerySystemTime((PTIME
) &pBin
->DateModified
);
2951 CmiMarkBlockDirty(RegistryHive
, Offset
);
2959 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
2960 PCELL_HEADER FreeBlock
,
2961 BLOCK_OFFSET FreeOffset
)
2963 BLOCK_OFFSET BlockOffset
;
2964 BLOCK_OFFSET BinOffset
;
2970 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
2971 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
2973 CmiGetBlock(RegistryHive
,
2976 DPRINT("Bin %p\n", Bin
);
2980 BinOffset
= Bin
->BlockOffset
;
2981 BinSize
= Bin
->BlockSize
;
2982 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
2984 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
2986 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
2987 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
2988 if (BlockOffset
> BinOffset
&&
2989 BlockOffset
< BinOffset
+ BinSize
)
2991 DPRINT("Free block: Offset %lx Size %lx\n",
2992 BlockOffset
, BlockSize
);
2994 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
2995 (BlockOffset
+ BlockSize
== FreeOffset
) &&
2996 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
2998 DPRINT("Merge current block with previous and next block\n");
3000 RegistryHive
->FreeList
[i
]->CellSize
+=
3001 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3003 FreeBlock
->CellSize
= 0;
3004 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3007 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3009 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3010 &RegistryHive
->FreeListOffset
[i
+ 2],
3011 sizeof(RegistryHive
->FreeListOffset
[0])
3012 * (RegistryHive
->FreeListSize
- i
- 2));
3014 RegistryHive
->FreeListSize
--;
3016 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3020 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3022 DPRINT("Merge current block with previous block\n");
3024 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3025 FreeBlock
->CellSize
= 0;
3027 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3031 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3033 DPRINT("Merge current block with next block\n");
3035 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3036 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3037 RegistryHive
->FreeList
[i
] = FreeBlock
;
3038 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3040 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3052 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3053 PCELL_HEADER FreeBlock
,
3054 BLOCK_OFFSET FreeOffset
,
3055 BOOLEAN MergeFreeBlocks
)
3057 PCELL_HEADER
*tmpList
;
3058 BLOCK_OFFSET
*tmpListOffset
;
3063 assert(RegistryHive
);
3066 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3067 FreeBlock
, FreeOffset
);
3069 /* Merge free blocks */
3070 if (MergeFreeBlocks
== TRUE
)
3072 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3073 return(STATUS_SUCCESS
);
3076 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3078 tmpList
= ExAllocatePool(PagedPool
,
3079 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3080 if (tmpList
== NULL
)
3081 return STATUS_INSUFFICIENT_RESOURCES
;
3083 tmpListOffset
= ExAllocatePool(PagedPool
,
3084 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3086 if (tmpListOffset
== NULL
)
3088 ExFreePool(tmpList
);
3089 return STATUS_INSUFFICIENT_RESOURCES
;
3092 if (RegistryHive
->FreeListMax
)
3094 RtlMoveMemory(tmpList
,
3095 RegistryHive
->FreeList
,
3096 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3097 RtlMoveMemory(tmpListOffset
,
3098 RegistryHive
->FreeListOffset
,
3099 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3100 ExFreePool(RegistryHive
->FreeList
);
3101 ExFreePool(RegistryHive
->FreeListOffset
);
3103 RegistryHive
->FreeList
= tmpList
;
3104 RegistryHive
->FreeListOffset
= tmpListOffset
;
3105 RegistryHive
->FreeListMax
+= 32;
3108 /* Add new offset to free list, maintaining list in ascending order */
3109 if ((RegistryHive
->FreeListSize
== 0)
3110 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3112 /* Add to end of list */
3113 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3114 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3116 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3118 /* Add to begin of list */
3119 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3120 &RegistryHive
->FreeList
[0],
3121 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3122 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3123 &RegistryHive
->FreeListOffset
[0],
3124 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3125 RegistryHive
->FreeList
[0] = FreeBlock
;
3126 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3127 RegistryHive
->FreeListSize
++;
3131 /* Search where to insert */
3133 maxInd
= RegistryHive
->FreeListSize
- 1;
3134 while ((maxInd
- minInd
) > 1)
3136 medInd
= (minInd
+ maxInd
) / 2;
3137 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3143 /* Insert before maxInd */
3144 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3145 &RegistryHive
->FreeList
[maxInd
],
3146 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3147 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3148 &RegistryHive
->FreeListOffset
[maxInd
],
3149 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3150 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3151 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3152 RegistryHive
->FreeListSize
++;
3155 return STATUS_SUCCESS
;
3160 CmiGetBlock(PREGISTRY_HIVE RegistryHive
,
3161 BLOCK_OFFSET BlockOffset
,
3167 if ((BlockOffset
== 0) || (BlockOffset
== (ULONG_PTR
) -1))
3170 if (IsPointerHive(RegistryHive
))
3172 return (PVOID
) BlockOffset
;
3178 pBin
= RegistryHive
->BlockList
[BlockOffset
/ 4096];
3181 return((PVOID
)((ULONG_PTR
)pBin
+ (BlockOffset
- pBin
->BlockOffset
)));
3187 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3188 BLOCK_OFFSET BlockOffset
)
3195 if (IsVolatileHive(RegistryHive
))
3198 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3200 BlockNumber
= (ULONG
)BlockOffset
/ 4096;
3202 Cell
= CmiGetBlock(RegistryHive
,
3206 CellSize
= Cell
->CellSize
;
3208 CellSize
= -CellSize
;
3210 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, 4096) - ROUND_DOWN(BlockOffset
, 4096)) / 4096;
3212 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3215 (Cell
->CellSize
< 0) ? "used" : "free",
3218 RegistryHive
->HiveDirty
= TRUE
;
3219 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3226 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3227 BLOCK_OFFSET BinOffset
)
3233 if (IsVolatileHive(RegistryHive
))
3236 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3238 BlockNumber
= (ULONG
)BinOffset
/ 4096;
3240 Bin
= RegistryHive
->BlockList
[BlockNumber
];
3242 BlockCount
= Bin
->BlockSize
/ 4096;
3244 DPRINT(" BlockNumber %lu Size %lu BlockCount %lu\n",
3249 RegistryHive
->HiveDirty
= TRUE
;
3250 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3257 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3258 OUT PBOOLEAN Packable
)
3262 if (Packable
!= NULL
)
3265 for (i
= 0; i
< Name
->Length
; i
++)
3267 if (Name
->Buffer
[i
] > 0xFF)
3269 if (Packable
!= NULL
)
3271 return(Name
->Length
);
3275 return(Name
->Length
/ sizeof(WCHAR
));
3280 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3281 IN PCHAR NameBuffer
,
3282 IN USHORT NameBufferSize
,
3283 IN BOOLEAN NamePacked
)
3288 if (NamePacked
== TRUE
)
3290 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3293 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3295 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3301 if (Name
->Length
!= NameBufferSize
)
3304 UNameBuffer
= (PWCHAR
)NameBuffer
;
3306 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3308 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3318 CmiCopyPackedName(PWCHAR NameBuffer
,
3319 PCHAR PackedNameBuffer
,
3320 ULONG PackedNameSize
)
3324 for (i
= 0; i
< PackedNameSize
; i
++)
3325 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];