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
);
368 CmiPopulateHive(HANDLE FileHandle
)
370 IO_STATUS_BLOCK IoStatusBlock
;
371 LARGE_INTEGER FileOffset
;
372 PCELL_HEADER FreeCell
;
378 tBuf
= (PCHAR
) ExAllocatePool(NonPagedPool
, REG_BLOCK_SIZE
);
380 return STATUS_INSUFFICIENT_RESOURCES
;
382 BinCell
= (PHBIN
) tBuf
;
383 FreeCell
= (PCELL_HEADER
) (tBuf
+ REG_HBIN_DATA_OFFSET
);
385 CmiCreateDefaultBinCell(BinCell
);
387 // The whole block is free
388 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
390 // Add free blocks so we don't need to expand
391 // the file for a while
392 for (i
= 1; i
< 50; i
++)
394 // Block offset of this bin
395 BinCell
->BlockOffset
= i
* REG_BLOCK_SIZE
;
397 FileOffset
.u
.HighPart
= 0;
398 FileOffset
.u
.LowPart
= (i
+ 1) * REG_BLOCK_SIZE
;
400 Status
= NtWriteFile(FileHandle
,
409 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
410 if (!NT_SUCCESS(Status
))
424 CmiCreateNewRegFile(HANDLE FileHandle
)
426 IO_STATUS_BLOCK IoStatusBlock
;
427 PCELL_HEADER FreeCell
;
428 PHIVE_HEADER HiveHeader
;
429 PKEY_CELL RootKeyCell
;
434 Buffer
= (PCHAR
) ExAllocatePool(NonPagedPool
, 2 * REG_BLOCK_SIZE
);
436 return STATUS_INSUFFICIENT_RESOURCES
;
438 HiveHeader
= (PHIVE_HEADER
)Buffer
;
439 BinCell
= (PHBIN
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
);
440 RootKeyCell
= (PKEY_CELL
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
);
441 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
443 CmiCreateDefaultHiveHeader(HiveHeader
);
444 CmiCreateDefaultBinCell(BinCell
);
445 CmiCreateDefaultRootKeyCell(RootKeyCell
);
448 BinCell
->BlockOffset
= 0;
450 /* Offset to root key block */
451 HiveHeader
->RootKeyCell
= REG_HBIN_DATA_OFFSET
;
453 /* The rest of the block is free */
454 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
456 Status
= NtWriteFile(FileHandle
,
468 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
470 if (!NT_SUCCESS(Status
))
476 if (NT_SUCCESS(Status
))
478 CmiPopulateHive(FileHandle
);
482 Status
= NtFlushBuffersFile(FileHandle
,
491 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive
)
493 OBJECT_ATTRIBUTES ObjectAttributes
;
494 FILE_STANDARD_INFORMATION fsi
;
495 IO_STATUS_BLOCK IoStatusBlock
;
496 HANDLE HiveHandle
= INVALID_HANDLE_VALUE
;
497 HANDLE LogHandle
= INVALID_HANDLE_VALUE
;
498 PHIVE_HEADER HiveHeader
= NULL
;
499 PHIVE_HEADER LogHeader
= NULL
;
500 LARGE_INTEGER FileOffset
;
504 RTL_BITMAP BlockBitMap
;
507 DPRINT("CmiCheckAndFixHive() called\n");
509 /* Try to open the hive file */
510 InitializeObjectAttributes(&ObjectAttributes
,
511 &RegistryHive
->HiveFileName
,
516 Status
= NtCreateFile(&HiveHandle
,
517 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
521 FILE_ATTRIBUTE_NORMAL
,
524 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
527 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
529 return(STATUS_SUCCESS
);
531 if (!NT_SUCCESS(Status
))
533 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
537 /* Try to open the log file */
538 InitializeObjectAttributes(&ObjectAttributes
,
539 &RegistryHive
->LogFileName
,
544 Status
= NtCreateFile(&LogHandle
,
545 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
549 FILE_ATTRIBUTE_NORMAL
,
552 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
555 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
557 LogHandle
= INVALID_HANDLE_VALUE
;
559 else if (!NT_SUCCESS(Status
))
561 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
566 /* Allocate hive header */
567 HiveHeader
= ExAllocatePool(PagedPool
,
568 sizeof(HIVE_HEADER
));
569 if (HiveHeader
== NULL
)
571 DPRINT("ExAllocatePool() failed\n");
572 Status
= STATUS_INSUFFICIENT_RESOURCES
;
576 /* Read hive base block */
577 FileOffset
.QuadPart
= 0ULL;
578 Status
= NtReadFile(HiveHandle
,
587 if (!NT_SUCCESS(Status
))
589 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
593 if (LogHandle
== INVALID_HANDLE_VALUE
)
595 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
596 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
598 /* There is no way to fix the hive without log file - BSOD! */
599 DPRINT("Hive header inconsistent and no log file available!\n");
600 KeBugCheck(CONFIG_LIST_FAILED
);
603 Status
= STATUS_SUCCESS
;
608 /* Allocate hive header */
609 LogHeader
= ExAllocatePool(PagedPool
,
610 sizeof(HIVE_HEADER
));
611 if (LogHeader
== NULL
)
613 DPRINT("ExAllocatePool() failed\n");
614 Status
= STATUS_INSUFFICIENT_RESOURCES
;
618 /* Read log file header */
619 FileOffset
.QuadPart
= 0ULL;
620 Status
= NtReadFile(LogHandle
,
629 if (!NT_SUCCESS(Status
))
631 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
635 /* Check log file header integrity */
636 if (LogHeader
->Checksum
!= CmiCalcChecksum((PULONG
)LogHeader
) ||
637 LogHeader
->UpdateCounter1
!= LogHeader
->UpdateCounter2
)
639 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
640 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
642 DPRINT("Hive file and log file are inconsistent!\n");
643 KeBugCheck(CONFIG_LIST_FAILED
);
646 /* Log file damaged but hive is okay */
647 Status
= STATUS_SUCCESS
;
651 if (HiveHeader
->UpdateCounter1
== HiveHeader
->UpdateCounter2
&&
652 HiveHeader
->UpdateCounter1
== LogHeader
->UpdateCounter1
)
654 /* Hive and log file are up-to-date */
655 Status
= STATUS_SUCCESS
;
660 * Hive needs an update!
664 Status
= NtQueryInformationFile(LogHandle
,
668 FileStandardInformation
);
669 if (!NT_SUCCESS(Status
))
671 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
674 FileSize
= fsi
.EndOfFile
.u
.LowPart
;
676 /* Calculate bitmap and block size */
677 BitmapSize
= ROUND_UP((FileSize
/ 4096) - 1, sizeof(ULONG
) * 8) / 8;
678 BufferSize
= sizeof(HIVE_HEADER
) +
681 BufferSize
= ROUND_UP(BufferSize
, 4096);
683 /* Reallocate log header block */
684 ExFreePool(LogHeader
);
685 LogHeader
= ExAllocatePool(PagedPool
,
687 if (LogHeader
== NULL
)
689 DPRINT("ExAllocatePool() failed\n");
690 Status
= STATUS_INSUFFICIENT_RESOURCES
;
694 /* Read log file header */
695 FileOffset
.QuadPart
= 0ULL;
696 Status
= NtReadFile(LogHandle
,
705 if (!NT_SUCCESS(Status
))
707 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
711 /* Initialize bitmap */
712 RtlInitializeBitMap(&BlockBitMap
,
713 (PVOID
)((ULONG
)LogHeader
+ 4096 + sizeof(ULONG
)),
716 /* FIXME: Update dirty blocks */
719 /* FIXME: Update hive header */
722 Status
= STATUS_SUCCESS
;
726 /* Clean up the mess */
728 if (HiveHeader
!= NULL
)
729 ExFreePool(HiveHeader
);
731 if (LogHeader
!= NULL
)
732 ExFreePool(LogHeader
);
734 if (LogHandle
!= INVALID_HANDLE_VALUE
)
745 CmiInitNonVolatileRegistryHive(PREGISTRY_HIVE RegistryHive
,
749 OBJECT_ATTRIBUTES ObjectAttributes
;
750 FILE_STANDARD_INFORMATION fsi
;
751 PCELL_HEADER FreeBlock
;
752 LARGE_INTEGER FileOffset
;
753 BLOCK_OFFSET BlockOffset
;
754 ULONG CreateDisposition
;
755 IO_STATUS_BLOCK IoSB
;
763 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S, %d) called\n",
764 RegistryHive
, Filename
, CreateNew
);
766 /* Duplicate Filename */
767 Status
= RtlCreateUnicodeString(&RegistryHive
->HiveFileName
,
769 if (!NT_SUCCESS(Status
))
771 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status
);
775 /* Create log file name */
776 RegistryHive
->LogFileName
.Length
= (wcslen(Filename
) + 4) * sizeof(WCHAR
);
777 RegistryHive
->LogFileName
.MaximumLength
= RegistryHive
->LogFileName
.Length
+ sizeof(WCHAR
);
778 RegistryHive
->LogFileName
.Buffer
= ExAllocatePool(NonPagedPool
,
779 RegistryHive
->LogFileName
.MaximumLength
);
780 if (RegistryHive
->LogFileName
.Buffer
== NULL
)
782 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
783 DPRINT("ExAllocatePool() failed\n");
784 return(STATUS_INSUFFICIENT_RESOURCES
);
786 wcscpy(RegistryHive
->LogFileName
.Buffer
,
788 wcscat(RegistryHive
->LogFileName
.Buffer
,
792 /* Check and eventually fix a hive */
793 Status
= CmiCheckAndFixHive(RegistryHive
);
794 if (!NT_SUCCESS(Status
))
796 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
797 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
798 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status
);
803 InitializeObjectAttributes(&ObjectAttributes
,
804 &RegistryHive
->HiveFileName
,
811 * This is a workaround to prevent a BSOD because of missing registry hives.
812 * The workaround is only useful for developers. An implementation for the
813 * ordinary user must bail out on missing registry hives because they are
814 * essential to booting and configuring the OS.
817 if (CreateNew
== TRUE
)
818 CreateDisposition
= FILE_OPEN_IF
;
820 CreateDisposition
= FILE_OPEN
;
822 CreateDisposition
= FILE_OPEN_IF
;
824 Status
= NtCreateFile(&FileHandle
,
829 FILE_ATTRIBUTE_NORMAL
,
832 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
835 if (!NT_SUCCESS(Status
))
837 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
838 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
839 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
843 /* Note: Another workaround! See the note above! */
845 if ((CreateNew
) && (IoSB
.Information
== FILE_CREATED
))
847 if (IoSB
.Information
!= FILE_OPENED
)
849 Status
= CmiCreateNewRegFile(FileHandle
);
850 if (!NT_SUCCESS(Status
))
852 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status
);
854 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
855 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
860 /* Read hive header */
861 FileOffset
.u
.HighPart
= 0;
862 FileOffset
.u
.LowPart
= 0;
863 DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle
, sizeof(HIVE_HEADER
), RegistryHive
->HiveHeader
);
864 Status
= NtReadFile(FileHandle
,
869 RegistryHive
->HiveHeader
,
873 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
874 if (!NT_SUCCESS(Status
))
876 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
878 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
879 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
883 /* Read update counter */
884 RegistryHive
->UpdateCounter
= RegistryHive
->HiveHeader
->UpdateCounter1
;
886 Status
= NtQueryInformationFile(FileHandle
,
890 FileStandardInformation
);
891 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
892 if (!NT_SUCCESS(Status
) || fsi
.EndOfFile
.u
.LowPart
== 0)
894 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
896 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
897 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
901 RegistryHive
->FileSize
= fsi
.EndOfFile
.u
.LowPart
;
902 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ 4096) - 1;
904 DPRINT("Space needed for block list describing hive: 0x%x\n",
905 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
907 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
908 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
910 if (RegistryHive
->BlockList
== NULL
)
912 ExFreePool(RegistryHive
->BlockList
);
914 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
915 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
916 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 6.\n");
917 return STATUS_INSUFFICIENT_RESOURCES
;
920 RegistryHive
->BlockList
[0] = ExAllocatePool(PagedPool
,
921 RegistryHive
->FileSize
- 4096);
922 if (RegistryHive
->BlockList
[0] == NULL
)
924 ExFreePool(RegistryHive
->BlockList
);
926 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
927 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
928 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 8.\n");
929 return STATUS_INSUFFICIENT_RESOURCES
;
932 FileOffset
.u
.HighPart
= 0;
933 FileOffset
.u
.LowPart
= 4096;
935 DPRINT(" Attempting to NtReadFile(%d) for %d bytes into %p\n",
936 FileHandle
, RegistryHive
->FileSize
- 4096, (PVOID
)RegistryHive
->BlockList
[0]);
937 Status
= NtReadFile(FileHandle
,
942 (PVOID
) RegistryHive
->BlockList
[0],
943 RegistryHive
->FileSize
- 4096,
947 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
951 RegistryHive
->FreeListSize
= 0;
952 RegistryHive
->FreeListMax
= 0;
953 RegistryHive
->FreeList
= NULL
;
956 for (i
= 0; i
< RegistryHive
->BlockListSize
; i
++)
958 RegistryHive
->BlockList
[i
] = (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[0]) + BlockOffset
);
959 tmpBin
= (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[i
]));
960 if (tmpBin
->BlockId
!= REG_BIN_ID
)
962 DPRINT("Bad BlockId %x, offset %x\n", tmpBin
->BlockId
, BlockOffset
);
964 return STATUS_INSUFFICIENT_RESOURCES
;
967 assertmsg((tmpBin
->BlockSize
% 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin
->BlockSize
));
969 if (tmpBin
->BlockSize
> 4096)
971 for (j
= 1; j
< tmpBin
->BlockSize
/ 4096; j
++)
973 RegistryHive
->BlockList
[i
+ j
] = RegistryHive
->BlockList
[i
];
978 /* Search free blocks and add to list */
979 FreeOffset
= REG_HBIN_DATA_OFFSET
;
980 while (FreeOffset
< tmpBin
->BlockSize
)
982 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) RegistryHive
->BlockList
[i
] + FreeOffset
);
983 if (FreeBlock
->CellSize
> 0)
985 Status
= CmiAddFree(RegistryHive
,
987 RegistryHive
->BlockList
[i
]->BlockOffset
+ FreeOffset
,
990 if (!NT_SUCCESS(Status
))
996 FreeOffset
+= FreeBlock
->CellSize
;
1000 FreeOffset
-= FreeBlock
->CellSize
;
1003 BlockOffset
+= tmpBin
->BlockSize
;
1007 * Create block bitmap and clear all bits
1009 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
1010 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1011 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
1012 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
1014 /* Allocate bitmap */
1015 RegistryHive
->BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
1017 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
1018 RegistryHive
->BitmapBuffer
,
1021 /* Initialize bitmap */
1022 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
1023 RegistryHive
->HiveDirty
= FALSE
;
1025 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S, %d) - Finished.\n",
1026 RegistryHive
, Filename
, CreateNew
);
1028 return(STATUS_SUCCESS
);
1033 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive
)
1035 PKEY_CELL RootKeyCell
;
1037 RegistryHive
->Flags
|= HIVE_VOLATILE
;
1039 CmiCreateDefaultHiveHeader(RegistryHive
->HiveHeader
);
1041 RootKeyCell
= (PKEY_CELL
) ExAllocatePool(NonPagedPool
, sizeof(KEY_CELL
));
1043 if (RootKeyCell
== NULL
)
1044 return STATUS_INSUFFICIENT_RESOURCES
;
1046 CmiCreateDefaultRootKeyCell(RootKeyCell
);
1048 RegistryHive
->HiveHeader
->RootKeyCell
= (BLOCK_OFFSET
) RootKeyCell
;
1050 return STATUS_SUCCESS
;
1055 CmiCreateRegistryHive(PWSTR Filename
,
1056 PREGISTRY_HIVE
*RegistryHive
,
1059 PREGISTRY_HIVE Hive
;
1062 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename
);
1064 *RegistryHive
= NULL
;
1066 Hive
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_HIVE
));
1068 return(STATUS_INSUFFICIENT_RESOURCES
);
1070 DPRINT("Hive %x\n", Hive
);
1072 RtlZeroMemory(Hive
, sizeof(REGISTRY_HIVE
));
1074 Hive
->HiveHeader
= (PHIVE_HEADER
)
1075 ExAllocatePool(NonPagedPool
, sizeof(HIVE_HEADER
));
1077 if (Hive
->HiveHeader
== NULL
)
1080 return(STATUS_INSUFFICIENT_RESOURCES
);
1083 if (Filename
!= NULL
)
1085 Status
= CmiInitNonVolatileRegistryHive(Hive
, Filename
, CreateNew
);
1089 Status
= CmiInitVolatileRegistryHive(Hive
);
1092 if (!NT_SUCCESS(Status
))
1094 ExFreePool(Hive
->HiveHeader
);
1099 ExInitializeResourceLite(&Hive
->HiveResource
);
1101 /* Acquire hive list lock exclusively */
1102 ExAcquireResourceExclusiveLite(&CmiHiveListLock
, TRUE
);
1104 /* Add the new hive to the hive list */
1105 InsertTailList(&CmiHiveListHead
, &Hive
->HiveList
);
1107 /* Release hive list lock */
1108 ExReleaseResourceLite(&CmiHiveListLock
);
1110 VERIFY_REGISTRY_HIVE(Hive
);
1112 *RegistryHive
= Hive
;
1114 DPRINT("CmiCreateRegistryHive(Filename %S) - Finished.\n", Filename
);
1116 return(STATUS_SUCCESS
);
1121 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
1123 /* Acquire hive list lock exclusively */
1124 ExAcquireResourceExclusiveLite(&CmiHiveListLock
, TRUE
);
1126 /* Remove hive from hive list */
1127 RemoveEntryList(&RegistryHive
->HiveList
);
1129 /* Release hive list lock */
1130 ExReleaseResourceLite(&CmiHiveListLock
);
1133 /* FIXME: Remove attached keys and values */
1136 /* Release hive header */
1137 ExFreePool(RegistryHive
->HiveHeader
);
1140 ExFreePool(RegistryHive
);
1142 return(STATUS_SUCCESS
);
1147 CmiCalcChecksum(PULONG Buffer
)
1152 for (i
= 0; i
< 127; i
++)
1160 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
1162 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1163 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1164 OBJECT_ATTRIBUTES ObjectAttributes
;
1165 IO_STATUS_BLOCK IoStatusBlock
;
1167 LARGE_INTEGER FileOffset
;
1177 DPRINT("CmiStartLogUpdate() called\n");
1179 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1180 BufferSize
= sizeof(HIVE_HEADER
) +
1183 BufferSize
= ROUND_UP(BufferSize
, 4096);
1185 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1187 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1190 DPRINT("ExAllocatePool() failed\n");
1191 return(STATUS_INSUFFICIENT_RESOURCES
);
1194 /* Open log file for writing */
1195 InitializeObjectAttributes(&ObjectAttributes
,
1196 &RegistryHive
->LogFileName
,
1201 Status
= NtCreateFile(&FileHandle
,
1206 FILE_ATTRIBUTE_NORMAL
,
1209 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1212 if (!NT_SUCCESS(Status
))
1214 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1219 /* Update firt update counter and checksum */
1220 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1221 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1223 /* Copy hive header */
1224 RtlCopyMemory(Buffer
,
1225 RegistryHive
->HiveHeader
,
1226 sizeof(HIVE_HEADER
));
1227 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1234 RegistryHive
->DirtyBitMap
.Buffer
,
1237 /* Write hive block and block bitmap */
1238 FileOffset
.QuadPart
= 0ULL;
1239 Status
= NtWriteFile(FileHandle
,
1248 if (!NT_SUCCESS(Status
))
1250 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1251 NtClose(FileHandle
);
1257 /* Write dirty blocks */
1258 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1262 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1265 if (BlockIndex
== (ULONG
)-1)
1267 DPRINT("No more set bits\n");
1268 Status
= STATUS_SUCCESS
;
1272 DPRINT("Block %lu is dirty\n", BlockIndex
);
1274 BlockOffset
= RegistryHive
->BlockList
[BlockIndex
]->BlockOffset
;
1275 DPRINT("Block offset %lx\n", BlockOffset
);
1277 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
] + ((BlockIndex
* 4096) - BlockOffset
);
1278 DPRINT("BlockPtr %p\n", BlockPtr
);
1280 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1282 /* Write hive block */
1283 Status
= NtWriteFile(FileHandle
,
1292 if (!NT_SUCCESS(Status
))
1294 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1295 NtClose(FileHandle
);
1300 FileOffset
.QuadPart
+= 4096ULL;
1303 /* Truncate log file */
1304 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1305 Status
= NtSetInformationFile(FileHandle
,
1308 sizeof(FILE_END_OF_FILE_INFORMATION
),
1309 FileEndOfFileInformation
);
1310 if (!NT_SUCCESS(Status
))
1312 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1313 NtClose(FileHandle
);
1317 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1318 Status
= NtSetInformationFile(FileHandle
,
1320 &FileAllocationInfo
,
1321 sizeof(FILE_ALLOCATION_INFORMATION
),
1322 FileAllocationInformation
);
1323 if (!NT_SUCCESS(Status
))
1325 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1326 NtClose(FileHandle
);
1330 /* Flush the log file */
1331 Status
= NtFlushBuffersFile(FileHandle
,
1333 if (!NT_SUCCESS(Status
))
1335 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1338 NtClose(FileHandle
);
1345 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1347 OBJECT_ATTRIBUTES ObjectAttributes
;
1348 IO_STATUS_BLOCK IoStatusBlock
;
1350 LARGE_INTEGER FileOffset
;
1357 DPRINT("CmiFinishLogUpdate() called\n");
1359 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1360 BufferSize
= sizeof(HIVE_HEADER
) +
1363 BufferSize
= ROUND_UP(BufferSize
, 4096);
1365 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1367 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1370 DPRINT("ExAllocatePool() failed\n");
1371 return(STATUS_INSUFFICIENT_RESOURCES
);
1374 /* Open log file for writing */
1375 InitializeObjectAttributes(&ObjectAttributes
,
1376 &RegistryHive
->LogFileName
,
1381 Status
= NtCreateFile(&FileHandle
,
1386 FILE_ATTRIBUTE_NORMAL
,
1389 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1392 if (!NT_SUCCESS(Status
))
1394 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1399 /* Update first and second update counter and checksum */
1400 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1401 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1402 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1404 /* Copy hive header */
1405 RtlCopyMemory(Buffer
,
1406 RegistryHive
->HiveHeader
,
1407 sizeof(HIVE_HEADER
));
1408 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1410 /* Write empty block bitmap */
1418 /* Write hive block and block bitmap */
1419 FileOffset
.QuadPart
= 0ULL;
1420 Status
= NtWriteFile(FileHandle
,
1429 if (!NT_SUCCESS(Status
))
1431 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1432 NtClose(FileHandle
);
1439 /* Flush the log file */
1440 Status
= NtFlushBuffersFile(FileHandle
,
1442 if (!NT_SUCCESS(Status
))
1444 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1447 NtClose(FileHandle
);
1454 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1456 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1457 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1458 OBJECT_ATTRIBUTES ObjectAttributes
;
1459 IO_STATUS_BLOCK IoStatusBlock
;
1465 DPRINT("CmiFinishLogUpdate() called\n");
1467 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1468 BufferSize
= sizeof(HIVE_HEADER
) +
1471 BufferSize
= ROUND_UP(BufferSize
, 4096);
1473 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1475 /* Open log file for writing */
1476 InitializeObjectAttributes(&ObjectAttributes
,
1477 &RegistryHive
->LogFileName
,
1482 Status
= NtCreateFile(&FileHandle
,
1487 FILE_ATTRIBUTE_NORMAL
,
1490 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1493 if (!NT_SUCCESS(Status
))
1495 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1499 /* Truncate log file */
1500 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1501 Status
= NtSetInformationFile(FileHandle
,
1504 sizeof(FILE_END_OF_FILE_INFORMATION
),
1505 FileEndOfFileInformation
);
1506 if (!NT_SUCCESS(Status
))
1508 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1509 NtClose(FileHandle
);
1513 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1514 Status
= NtSetInformationFile(FileHandle
,
1516 &FileAllocationInfo
,
1517 sizeof(FILE_ALLOCATION_INFORMATION
),
1518 FileAllocationInformation
);
1519 if (!NT_SUCCESS(Status
))
1521 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1522 NtClose(FileHandle
);
1526 /* Flush the log file */
1527 Status
= NtFlushBuffersFile(FileHandle
,
1529 if (!NT_SUCCESS(Status
))
1531 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1534 NtClose(FileHandle
);
1541 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1543 OBJECT_ATTRIBUTES ObjectAttributes
;
1544 IO_STATUS_BLOCK IoStatusBlock
;
1546 LARGE_INTEGER FileOffset
;
1552 DPRINT("CmiStartHiveUpdate() called\n");
1554 /* Open hive for writing */
1555 InitializeObjectAttributes(&ObjectAttributes
,
1556 &RegistryHive
->HiveFileName
,
1561 Status
= NtCreateFile(&FileHandle
,
1566 FILE_ATTRIBUTE_NORMAL
,
1569 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1572 if (!NT_SUCCESS(Status
))
1574 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1578 /* Update firt update counter and checksum */
1579 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1580 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1582 /* Write hive block */
1583 FileOffset
.QuadPart
= 0ULL;
1584 Status
= NtWriteFile(FileHandle
,
1589 RegistryHive
->HiveHeader
,
1590 sizeof(HIVE_HEADER
),
1593 if (!NT_SUCCESS(Status
))
1595 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1596 NtClose(FileHandle
);
1603 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1606 if (BlockIndex
== (ULONG
)-1)
1608 DPRINT("No more set bits\n");
1609 Status
= STATUS_SUCCESS
;
1613 DPRINT("Block %lu is dirty\n", BlockIndex
);
1615 BlockOffset
= RegistryHive
->BlockList
[BlockIndex
]->BlockOffset
;
1616 DPRINT("Block offset %lx\n", BlockOffset
);
1618 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
] + ((BlockIndex
* 4096) - BlockOffset
);
1619 DPRINT("BlockPtr %p\n", BlockPtr
);
1621 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096ULL;
1622 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1625 /* Write hive block */
1626 Status
= NtWriteFile(FileHandle
,
1635 if (!NT_SUCCESS(Status
))
1637 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1638 NtClose(FileHandle
);
1645 Status
= NtFlushBuffersFile(FileHandle
,
1647 if (!NT_SUCCESS(Status
))
1649 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1652 NtClose(FileHandle
);
1659 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1661 OBJECT_ATTRIBUTES ObjectAttributes
;
1662 IO_STATUS_BLOCK IoStatusBlock
;
1663 LARGE_INTEGER FileOffset
;
1667 DPRINT("CmiFinishHiveUpdate() called\n");
1669 InitializeObjectAttributes(&ObjectAttributes
,
1670 &RegistryHive
->HiveFileName
,
1675 Status
= NtCreateFile(&FileHandle
,
1680 FILE_ATTRIBUTE_NORMAL
,
1683 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1686 if (!NT_SUCCESS(Status
))
1688 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1692 /* Update second update counter and checksum */
1693 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1694 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1695 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1697 /* Write hive block */
1698 FileOffset
.QuadPart
= 0ULL;
1699 Status
= NtWriteFile(FileHandle
,
1704 RegistryHive
->HiveHeader
,
1705 sizeof(HIVE_HEADER
),
1708 if (!NT_SUCCESS(Status
))
1710 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1711 NtClose(FileHandle
);
1715 Status
= NtFlushBuffersFile(FileHandle
,
1717 if (!NT_SUCCESS(Status
))
1719 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1722 NtClose(FileHandle
);
1729 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1733 DPRINT("CmiFlushRegistryHive() called\n");
1735 if (RegistryHive
->HiveDirty
== FALSE
)
1737 return(STATUS_SUCCESS
);
1740 DPRINT("Hive '%wZ' is dirty\n",
1741 &RegistryHive
->HiveFileName
);
1742 DPRINT("Log file: '%wZ'\n",
1743 &RegistryHive
->LogFileName
);
1745 /* Update hive header modification time */
1746 NtQuerySystemTime((PTIME
)&RegistryHive
->HiveHeader
->DateModified
);
1748 /* Start log update */
1749 Status
= CmiStartLogUpdate(RegistryHive
);
1750 if (!NT_SUCCESS(Status
))
1752 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1756 /* Finish log update */
1757 Status
= CmiFinishLogUpdate(RegistryHive
);
1758 if (!NT_SUCCESS(Status
))
1760 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1764 /* Start hive update */
1765 Status
= CmiStartHiveUpdate(RegistryHive
);
1766 if (!NT_SUCCESS(Status
))
1768 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1772 /* Finish the hive update */
1773 Status
= CmiFinishHiveUpdate(RegistryHive
);
1774 if (!NT_SUCCESS(Status
))
1776 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
1780 /* Cleanup log update */
1781 Status
= CmiCleanupLogUpdate(RegistryHive
);
1782 if (!NT_SUCCESS(Status
))
1784 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1788 /* Increment hive update counter */
1789 RegistryHive
->UpdateCounter
++;
1791 /* Clear dirty bitmap and dirty flag */
1792 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
1793 RegistryHive
->HiveDirty
= FALSE
;
1795 DPRINT("CmiFlushRegistryHive() done\n");
1797 return(STATUS_SUCCESS
);
1802 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive
,
1805 PHASH_TABLE_CELL HashBlock
;
1806 PKEY_CELL CurSubKeyCell
;
1810 VERIFY_KEY_CELL(KeyCell
);
1813 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1814 if (HashBlock
== NULL
)
1819 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1821 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
1823 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1824 HashBlock
->Table
[i
].KeyOffset
,
1826 if (MaxName
< CurSubKeyCell
->NameSize
)
1828 MaxName
= CurSubKeyCell
->NameSize
;
1830 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1834 CmiReleaseBlock(RegistryHive
, HashBlock
);
1841 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive
,
1844 PHASH_TABLE_CELL HashBlock
;
1845 PKEY_CELL CurSubKeyCell
;
1849 VERIFY_KEY_CELL(KeyCell
);
1852 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1853 if (HashBlock
== NULL
)
1858 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1860 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
1862 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1863 HashBlock
->Table
[i
].KeyOffset
,
1865 if (MaxClass
< CurSubKeyCell
->ClassSize
)
1867 MaxClass
= CurSubKeyCell
->ClassSize
;
1869 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1873 CmiReleaseBlock(RegistryHive
, HashBlock
);
1880 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
1883 PVALUE_LIST_CELL ValueListCell
;
1884 PVALUE_CELL CurValueCell
;
1888 VERIFY_KEY_CELL(KeyCell
);
1890 ValueListCell
= CmiGetBlock(RegistryHive
,
1891 KeyCell
->ValuesOffset
,
1894 if (ValueListCell
== NULL
)
1899 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1901 CurValueCell
= CmiGetBlock(RegistryHive
,
1902 ValueListCell
->Values
[i
],
1904 if (CurValueCell
!= NULL
&&
1905 MaxValueName
< CurValueCell
->NameSize
)
1907 MaxValueName
= CurValueCell
->NameSize
;
1909 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1912 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1914 return MaxValueName
;
1919 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
1922 PVALUE_LIST_CELL ValueListCell
;
1923 PVALUE_CELL CurValueCell
;
1927 VERIFY_KEY_CELL(KeyCell
);
1929 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1931 if (ValueListCell
== NULL
)
1936 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1938 CurValueCell
= CmiGetBlock(RegistryHive
,
1939 ValueListCell
->Values
[i
],NULL
);
1940 if ((CurValueCell
!= NULL
) &&
1941 (MaxValueData
< (CurValueCell
->DataSize
& LONG_MAX
)))
1943 MaxValueData
= CurValueCell
->DataSize
& LONG_MAX
;
1945 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1948 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1950 return MaxValueData
;
1955 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
1956 IN PKEY_CELL KeyCell
,
1957 OUT PKEY_CELL
*SubKeyCell
,
1958 OUT BLOCK_OFFSET
*BlockOffset
,
1960 IN ACCESS_MASK DesiredAccess
,
1961 IN ULONG Attributes
)
1963 PHASH_TABLE_CELL HashBlock
;
1964 PKEY_CELL CurSubKeyCell
;
1968 VERIFY_KEY_CELL(KeyCell
);
1970 //DPRINT("Scanning for sub key %s\n", KeyName);
1972 assert(RegistryHive
);
1974 KeyLength
= strlen(KeyName
);
1976 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1978 if (HashBlock
== NULL
)
1980 return STATUS_SUCCESS
;
1983 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
)
1984 && (i
< HashBlock
->HashTableSize
); i
++)
1986 if (Attributes
& OBJ_CASE_INSENSITIVE
)
1988 if ((HashBlock
->Table
[i
].KeyOffset
!= 0) &&
1989 (HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1) &&
1990 (_strnicmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4) == 0))
1992 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1993 HashBlock
->Table
[i
].KeyOffset
,
1995 if ((CurSubKeyCell
->NameSize
== KeyLength
)
1996 && (_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
) == 0))
1998 *SubKeyCell
= CurSubKeyCell
;
1999 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2004 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
2010 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2011 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2012 !strncmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4))
2014 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
2015 HashBlock
->Table
[i
].KeyOffset
,NULL
);
2016 if (CurSubKeyCell
->NameSize
== KeyLength
2017 && !_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
))
2019 *SubKeyCell
= CurSubKeyCell
;
2020 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2025 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
2031 CmiReleaseBlock(RegistryHive
, HashBlock
);
2033 return STATUS_SUCCESS
;
2038 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2041 PWSTR NewSubKeyName
,
2042 USHORT NewSubKeyNameSize
,
2044 PUNICODE_STRING Class
,
2045 ULONG CreateOptions
)
2047 PHASH_TABLE_CELL NewHashBlock
;
2048 PHASH_TABLE_CELL HashBlock
;
2049 BLOCK_OFFSET NKBOffset
;
2050 PKEY_CELL NewKeyCell
;
2056 KeyCell
= Parent
->KeyCell
;
2058 VERIFY_KEY_CELL(KeyCell
);
2060 if (NewSubKeyName
[0] == L
'\\')
2063 NameSize
= NewSubKeyNameSize
/ 2 - 1;
2067 NameSize
= NewSubKeyNameSize
/ 2;
2069 Status
= STATUS_SUCCESS
;
2071 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2072 Status
= CmiAllocateBlock(RegistryHive
,
2073 (PVOID
) &NewKeyCell
,
2077 if (NewKeyCell
== NULL
)
2079 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2083 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2084 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
2085 ZwQuerySystemTime((PTIME
) &NewKeyCell
->LastWriteTime
);
2086 NewKeyCell
->ParentKeyOffset
= -1;
2087 NewKeyCell
->NumberOfSubKeys
= 0;
2088 NewKeyCell
->HashTableOffset
= -1;
2089 NewKeyCell
->NumberOfValues
= 0;
2090 NewKeyCell
->ValuesOffset
= -1;
2091 NewKeyCell
->SecurityKeyOffset
= -1;
2092 NewKeyCell
->NameSize
= NameSize
;
2093 wcstombs(NewKeyCell
->Name
, NewSubKeyName
, NameSize
);
2094 NewKeyCell
->ClassNameOffset
= -1;
2096 VERIFY_KEY_CELL(NewKeyCell
);
2102 NewKeyCell
->ClassSize
= Class
->Length
+ sizeof(WCHAR
);
2103 Status
= CmiAllocateBlock(RegistryHive
,
2105 NewKeyCell
->ClassSize
,
2106 &NewKeyCell
->ClassNameOffset
);
2107 wcsncpy((PWSTR
) pClass
->Data
, Class
->Buffer
, Class
->Length
);
2108 ((PWSTR
) (pClass
->Data
))[Class
->Length
] = 0;
2112 if (!NT_SUCCESS(Status
))
2117 SubKey
->KeyCell
= NewKeyCell
;
2118 SubKey
->BlockOffset
= NKBOffset
;
2120 /* Don't modify hash table if key is volatile and parent is not */
2121 if (IsVolatileHive(RegistryHive
) && (!IsVolatileHive(Parent
->RegistryHive
)))
2126 if (KeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2128 Status
= CmiAllocateHashTableBlock(RegistryHive
,
2130 &KeyCell
->HashTableOffset
,
2131 REG_INIT_HASH_TABLE_SIZE
);
2132 if (!NT_SUCCESS(Status
))
2139 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2140 if (((KeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2142 BLOCK_OFFSET HTOffset
;
2144 /* Reallocate the hash table block */
2145 Status
= CmiAllocateHashTableBlock(RegistryHive
,
2148 HashBlock
->HashTableSize
+
2149 REG_EXTEND_HASH_TABLE_SIZE
);
2150 if (!NT_SUCCESS(Status
))
2155 RtlZeroMemory(&NewHashBlock
->Table
[0],
2156 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2157 RtlCopyMemory(&NewHashBlock
->Table
[0],
2158 &HashBlock
->Table
[0],
2159 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2160 CmiDestroyBlock(RegistryHive
,
2162 KeyCell
->HashTableOffset
);
2163 KeyCell
->HashTableOffset
= HTOffset
;
2164 HashBlock
= NewHashBlock
;
2168 Status
= CmiAddKeyToHashTable(RegistryHive
,
2172 if (NT_SUCCESS(Status
))
2174 KeyCell
->NumberOfSubKeys
++;
2182 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2183 PKEY_OBJECT ParentKey
,
2186 PHASH_TABLE_CELL HashBlock
;
2187 PVALUE_LIST_CELL ValueList
;
2188 PVALUE_CELL ValueCell
;
2189 PDATA_CELL DataCell
;
2192 DPRINT("CmiRemoveSubKey() called\n");
2194 /* Remove all values */
2195 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2197 /* Get pointer to the value list cell */
2198 ValueList
= CmiGetBlock(RegistryHive
,
2199 SubKey
->KeyCell
->ValuesOffset
,
2201 if (ValueList
!= NULL
)
2203 /* Enumerate all values */
2204 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2206 /* Get pointer to value cell */
2207 ValueCell
= CmiGetBlock(RegistryHive
,
2208 ValueList
->Values
[i
],
2210 if (ValueCell
!= NULL
)
2212 if (ValueCell
->DataSize
> 4)
2214 DataCell
= CmiGetBlock(RegistryHive
,
2215 ValueCell
->DataOffset
,
2217 if (DataCell
!= NULL
)
2219 /* Destroy data cell */
2220 CmiDestroyBlock(RegistryHive
,
2222 ValueCell
->DataOffset
);
2226 /* Destroy value cell */
2227 CmiDestroyBlock(RegistryHive
,
2229 ValueList
->Values
[i
]);
2234 /* Destroy value list cell */
2235 CmiDestroyBlock(RegistryHive
,
2237 SubKey
->KeyCell
->ValuesOffset
);
2239 SubKey
->KeyCell
->NumberOfValues
= 0;
2240 SubKey
->KeyCell
->ValuesOffset
= -1;
2243 /* Remove the key from the parent key's hash block */
2244 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2246 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
)
2247 HashBlock
= CmiGetBlock(RegistryHive
,
2248 ParentKey
->KeyCell
->HashTableOffset
,
2250 DPRINT("ParentKey HashBlock %p\n", HashBlock
)
2251 if (HashBlock
!= NULL
)
2253 CmiRemoveKeyFromHashTable(RegistryHive
,
2255 SubKey
->BlockOffset
);
2256 CmiMarkBlockDirty(RegistryHive
,
2257 ParentKey
->KeyCell
->HashTableOffset
);
2261 /* Remove the key's hash block */
2262 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2264 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
)
2265 HashBlock
= CmiGetBlock(RegistryHive
,
2266 SubKey
->KeyCell
->HashTableOffset
,
2268 DPRINT("SubKey HashBlock %p\n", HashBlock
)
2269 if (HashBlock
!= NULL
)
2271 CmiDestroyBlock(RegistryHive
,
2273 SubKey
->KeyCell
->HashTableOffset
);
2274 SubKey
->KeyCell
->HashTableOffset
= -1;
2278 /* Decrement the number of the parent key's sub keys */
2279 if (ParentKey
!= NULL
)
2281 DPRINT("ParentKey %p\n", ParentKey
)
2282 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2284 /* Remove the parent key's hash table */
2285 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2287 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
)
2288 HashBlock
= CmiGetBlock(RegistryHive
,
2289 ParentKey
->KeyCell
->HashTableOffset
,
2291 DPRINT("ParentKey HashBlock %p\n", HashBlock
)
2292 if (HashBlock
!= NULL
)
2294 CmiDestroyBlock(RegistryHive
,
2296 ParentKey
->KeyCell
->HashTableOffset
);
2297 ParentKey
->KeyCell
->HashTableOffset
= -1;
2301 NtQuerySystemTime((PTIME
)&ParentKey
->KeyCell
->LastWriteTime
);
2302 CmiMarkBlockDirty(RegistryHive
,
2303 ParentKey
->BlockOffset
);
2306 /* Destroy key cell */
2307 CmiDestroyBlock(RegistryHive
,
2309 SubKey
->BlockOffset
);
2310 SubKey
->BlockOffset
= -1;
2311 SubKey
->KeyCell
= NULL
;
2313 return(STATUS_SUCCESS
);
2318 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2319 IN PKEY_CELL KeyCell
,
2320 IN PUNICODE_STRING ValueName
,
2321 OUT PVALUE_CELL
*ValueCell
,
2322 OUT BLOCK_OFFSET
*VBOffset
)
2324 PVALUE_LIST_CELL ValueListCell
;
2325 PVALUE_CELL CurValueCell
;
2328 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2332 if (ValueListCell
== NULL
)
2334 DPRINT("ValueListCell is NULL\n");
2335 return STATUS_SUCCESS
;
2338 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2340 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2342 CurValueCell
= CmiGetBlock(RegistryHive
,
2343 ValueListCell
->Values
[i
],
2346 if ((CurValueCell
!= NULL
) &&
2347 CmiComparePackedNames(ValueName
,
2349 CurValueCell
->NameSize
,
2350 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
2352 *ValueCell
= CurValueCell
;
2354 *VBOffset
= ValueListCell
->Values
[i
];
2355 //DPRINT("Found value %s\n", ValueName);
2358 CmiReleaseBlock(RegistryHive
, CurValueCell
);
2361 CmiReleaseBlock(RegistryHive
, ValueListCell
);
2363 return STATUS_SUCCESS
;
2368 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2369 IN PKEY_CELL KeyCell
,
2371 OUT PVALUE_CELL
*ValueCell
)
2373 PVALUE_LIST_CELL ValueListCell
;
2374 PVALUE_CELL CurValueCell
;
2376 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2380 if (ValueListCell
== NULL
)
2382 return STATUS_NO_MORE_ENTRIES
;
2385 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2387 if (Index
>= KeyCell
->NumberOfValues
)
2389 return STATUS_NO_MORE_ENTRIES
;
2392 CurValueCell
= CmiGetBlock(RegistryHive
,
2393 ValueListCell
->Values
[Index
],
2396 if (CurValueCell
!= NULL
)
2398 *ValueCell
= CurValueCell
;
2401 CmiReleaseBlock(RegistryHive
, CurValueCell
);
2402 CmiReleaseBlock(RegistryHive
, ValueListCell
);
2404 return STATUS_SUCCESS
;
2409 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2410 IN PKEY_CELL KeyCell
,
2411 IN PUNICODE_STRING ValueName
,
2412 OUT PVALUE_CELL
*pValueCell
,
2413 OUT BLOCK_OFFSET
*pVBOffset
)
2415 PVALUE_LIST_CELL NewValueListCell
;
2416 PVALUE_LIST_CELL ValueListCell
;
2417 PVALUE_CELL NewValueCell
;
2418 BLOCK_OFFSET VLBOffset
;
2419 BLOCK_OFFSET VBOffset
;
2422 Status
= CmiAllocateValueCell(RegistryHive
,
2426 *pVBOffset
= VBOffset
;
2428 if (!NT_SUCCESS(Status
))
2433 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2435 if (ValueListCell
== NULL
)
2437 Status
= CmiAllocateBlock(RegistryHive
,
2438 (PVOID
) &ValueListCell
,
2439 sizeof(BLOCK_OFFSET
) * 3,
2442 if (!NT_SUCCESS(Status
))
2444 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2447 KeyCell
->ValuesOffset
= VLBOffset
;
2449 else if (KeyCell
->NumberOfValues
>=
2450 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - 4) / sizeof(BLOCK_OFFSET
)))
2452 Status
= CmiAllocateBlock(RegistryHive
,
2453 (PVOID
) &NewValueListCell
,
2454 (KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) *
2455 sizeof(BLOCK_OFFSET
),
2457 if (!NT_SUCCESS(Status
))
2459 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2463 RtlCopyMemory(&NewValueListCell
->Values
[0],
2464 &ValueListCell
->Values
[0],
2465 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2466 CmiDestroyBlock(RegistryHive
, ValueListCell
, KeyCell
->ValuesOffset
);
2467 KeyCell
->ValuesOffset
= VLBOffset
;
2468 ValueListCell
= NewValueListCell
;
2471 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2472 KeyCell
->NumberOfValues
,
2473 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2474 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - 4) / sizeof(BLOCK_OFFSET
),
2475 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - 4) / sizeof(BLOCK_OFFSET
));
2477 ValueListCell
->Values
[KeyCell
->NumberOfValues
] = VBOffset
;
2478 KeyCell
->NumberOfValues
++;
2479 CmiReleaseBlock(RegistryHive
, ValueListCell
);
2480 CmiReleaseBlock(RegistryHive
, NewValueCell
);
2481 *pValueCell
= NewValueCell
;
2483 return STATUS_SUCCESS
;
2488 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2489 IN PKEY_CELL KeyCell
,
2490 IN BLOCK_OFFSET KeyCellOffset
,
2491 IN PUNICODE_STRING ValueName
)
2493 PVALUE_LIST_CELL ValueListCell
;
2494 PVALUE_CELL CurValueCell
;
2497 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2499 if (ValueListCell
== NULL
)
2501 return STATUS_SUCCESS
;
2504 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2506 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2508 CurValueCell
= CmiGetBlock(RegistryHive
, ValueListCell
->Values
[i
], NULL
);
2510 if ((CurValueCell
!= NULL
) &&
2511 CmiComparePackedNames(ValueName
,
2513 CurValueCell
->NameSize
,
2514 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
2516 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->Values
[i
]);
2518 if ((KeyCell
->NumberOfValues
- 1) < i
)
2520 RtlCopyMemory(&ValueListCell
->Values
[i
],
2521 &ValueListCell
->Values
[i
+ 1],
2522 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2526 RtlZeroMemory(&ValueListCell
->Values
[i
], sizeof(BLOCK_OFFSET
));
2529 KeyCell
->NumberOfValues
-= 1;
2532 CmiReleaseBlock(RegistryHive
, CurValueCell
);
2535 CmiReleaseBlock(RegistryHive
, ValueListCell
);
2537 if (KeyCell
->NumberOfValues
== 0)
2539 CmiDestroyBlock(RegistryHive
,
2541 KeyCell
->ValuesOffset
);
2545 CmiMarkBlockDirty(RegistryHive
,
2546 KeyCell
->ValuesOffset
);
2549 CmiMarkBlockDirty(RegistryHive
,
2552 return STATUS_SUCCESS
;
2557 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive
,
2558 OUT PHASH_TABLE_CELL
*HashBlock
,
2559 OUT BLOCK_OFFSET
*HBOffset
,
2560 IN ULONG HashTableSize
)
2562 PHASH_TABLE_CELL NewHashBlock
;
2566 Status
= STATUS_SUCCESS
;
2568 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
2569 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
2570 Status
= CmiAllocateBlock(RegistryHive
,
2571 (PVOID
*) &NewHashBlock
,
2575 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
2577 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2581 NewHashBlock
->Id
= REG_HASH_TABLE_BLOCK_ID
;
2582 NewHashBlock
->HashTableSize
= HashTableSize
;
2583 *HashBlock
= NewHashBlock
;
2591 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
2592 PHASH_TABLE_CELL HashBlock
,
2595 BLOCK_OFFSET KeyOffset
;
2598 if (HashBlock
== NULL
)
2601 if (IsVolatileHive(RegistryHive
))
2603 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
2607 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
2608 KeyCell
= CmiGetBlock(RegistryHive
, KeyOffset
, NULL
);
2610 CmiLockBlock(RegistryHive
, KeyCell
);
2617 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
2618 PHASH_TABLE_CELL HashBlock
,
2619 PKEY_CELL NewKeyCell
,
2620 BLOCK_OFFSET NKBOffset
)
2624 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2626 if (HashBlock
->Table
[i
].KeyOffset
== 0)
2628 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
2629 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
, NewKeyCell
->Name
, 4);
2630 return STATUS_SUCCESS
;
2634 return STATUS_UNSUCCESSFUL
;
2639 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
2640 PHASH_TABLE_CELL HashBlock
,
2641 BLOCK_OFFSET NKBOffset
)
2645 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2647 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
2649 HashBlock
->Table
[i
].KeyOffset
= 0;
2650 RtlZeroMemory(&HashBlock
->Table
[i
].HashValue
, 4);
2651 return STATUS_SUCCESS
;
2655 return STATUS_UNSUCCESSFUL
;
2660 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
2661 PVALUE_CELL
*ValueCell
,
2662 BLOCK_OFFSET
*VBOffset
,
2663 IN PUNICODE_STRING ValueName
)
2665 PVALUE_CELL NewValueCell
;
2671 Status
= STATUS_SUCCESS
;
2673 NameSize
= CmiGetPackedNameLength(ValueName
,
2676 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
2678 Status
= CmiAllocateBlock(RegistryHive
,
2679 (PVOID
*) &NewValueCell
,
2680 sizeof(VALUE_CELL
) + NameSize
,
2682 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
2684 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2688 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
2689 NewValueCell
->NameSize
= NameSize
;
2692 /* Pack the value name */
2693 for (i
= 0; i
< NameSize
; i
++)
2694 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
2695 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
2699 /* Copy the value name */
2700 RtlCopyMemory(NewValueCell
->Name
,
2703 NewValueCell
->Flags
= 0;
2705 NewValueCell
->DataType
= 0;
2706 NewValueCell
->DataSize
= 0;
2707 NewValueCell
->DataOffset
= 0xffffffff;
2708 *ValueCell
= NewValueCell
;
2716 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
2717 PVALUE_CELL ValueCell
,
2718 BLOCK_OFFSET VBOffset
)
2724 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell
, VBOffset
);
2726 VERIFY_VALUE_CELL(ValueCell
);
2728 /* Destroy the data cell */
2729 if (ValueCell
->DataSize
> 4)
2731 pBlock
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, &pBin
);
2732 Status
= CmiDestroyBlock(RegistryHive
, pBlock
, ValueCell
->DataOffset
);
2733 if (!NT_SUCCESS(Status
))
2738 /* Update time of heap */
2739 if (IsPermanentHive(RegistryHive
))
2740 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2743 /* Destroy the value cell */
2744 Status
= CmiDestroyBlock(RegistryHive
, ValueCell
, VBOffset
);
2746 /* Update time of heap */
2747 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, VBOffset
, &pBin
))
2749 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2757 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
2759 BLOCK_OFFSET
*NewBlockOffset
)
2761 PCELL_HEADER tmpBlock
;
2762 PHBIN
* tmpBlockList
;
2765 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
2768 return STATUS_INSUFFICIENT_RESOURCES
;
2771 tmpBin
->BlockId
= REG_BIN_ID
;
2772 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
2773 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
2774 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
2775 tmpBin
->Unused1
= 0;
2776 ZwQuerySystemTime((PTIME
) &tmpBin
->DateModified
);
2777 tmpBin
->Unused2
= 0;
2779 /* Increase size of list of blocks */
2780 tmpBlockList
= ExAllocatePool(NonPagedPool
,
2781 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
2782 if (tmpBlockList
== NULL
)
2785 return STATUS_INSUFFICIENT_RESOURCES
;
2788 if (RegistryHive
->BlockListSize
> 0)
2790 memcpy(tmpBlockList
,
2791 RegistryHive
->BlockList
,
2792 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
2793 ExFreePool(RegistryHive
->BlockList
);
2796 RegistryHive
->BlockList
= tmpBlockList
;
2797 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
++] = tmpBin
;
2799 /* Initialize a free block in this heap : */
2800 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
2801 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
2803 /* Grow bitmap if necessary */
2804 if (IsVolatileHive(RegistryHive
) &&
2805 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
2807 PULONG BitmapBuffer
;
2810 DPRINT1("Grow hive bitmap\n");
2812 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
2813 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
2814 DPRINT1("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
2815 DPRINT1("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
2816 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
2818 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
2819 RtlCopyMemory(BitmapBuffer
,
2820 RegistryHive
->DirtyBitMap
.Buffer
,
2821 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
2822 ExFreePool(RegistryHive
->BitmapBuffer
);
2823 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
2824 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
2825 RegistryHive
->BitmapBuffer
,
2829 *NewBlock
= (PVOID
) tmpBlock
;
2832 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
2834 /* FIXME: set first dword to block_offset of another free bloc */
2836 /* Mark new bin dirty */
2837 CmiMarkBinDirty(RegistryHive
,
2838 tmpBin
->BlockOffset
);
2840 return STATUS_SUCCESS
;
2845 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive
,
2848 BLOCK_OFFSET
* pBlockOffset
)
2850 PCELL_HEADER NewBlock
;
2854 Status
= STATUS_SUCCESS
;
2856 /* Round to 16 bytes multiple */
2857 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
2859 /* Handle volatile hives first */
2860 if (IsVolatileHive(RegistryHive
))
2862 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
2864 if (NewBlock
== NULL
)
2866 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2870 RtlZeroMemory(NewBlock
, BlockSize
);
2871 NewBlock
->CellSize
= BlockSize
;
2872 CmiLockBlock(RegistryHive
, NewBlock
);
2875 *pBlockOffset
= (BLOCK_OFFSET
) NewBlock
;
2882 /* first search in free blocks */
2884 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
2886 if (RegistryHive
->FreeList
[i
]->CellSize
>= BlockSize
)
2890 NewBlock
= RegistryHive
->FreeList
[i
];
2892 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
2894 /* Update time of heap */
2895 Temp
= CmiGetBlock(RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
2899 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2900 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
2903 if ((i
+ 1) < RegistryHive
->FreeListSize
)
2905 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
2906 &RegistryHive
->FreeList
[i
+ 1],
2907 sizeof(RegistryHive
->FreeList
[0])
2908 * (RegistryHive
->FreeListSize
- i
- 1));
2909 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
2910 &RegistryHive
->FreeListOffset
[i
+ 1],
2911 sizeof(RegistryHive
->FreeListOffset
[0])
2912 * (RegistryHive
->FreeListSize
- i
- 1));
2914 RegistryHive
->FreeListSize
--;
2919 /* Need to extend hive file : */
2920 if (NewBlock
== NULL
)
2922 /* Add a new block */
2923 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewBlock
, pBlockOffset
);
2926 if (NT_SUCCESS(Status
))
2930 /* Split the block in two parts */
2931 if (NewBlock
->CellSize
> BlockSize
)
2933 NewBlock
= (PCELL_HEADER
) ((ULONG_PTR
) NewBlock
+BlockSize
);
2934 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- BlockSize
;
2935 CmiAddFree(RegistryHive
,
2937 *pBlockOffset
+ BlockSize
,
2939 CmiMarkBlockDirty(RegistryHive
,
2940 *pBlockOffset
+ BlockSize
);
2942 else if (NewBlock
->CellSize
< BlockSize
)
2944 return(STATUS_UNSUCCESSFUL
);
2947 RtlZeroMemory(*Block
, BlockSize
);
2948 ((PCELL_HEADER
) (*Block
))->CellSize
= -BlockSize
;
2949 CmiLockBlock(RegistryHive
, *Block
);
2958 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive
,
2960 BLOCK_OFFSET Offset
)
2965 Status
= STATUS_SUCCESS
;
2967 if (IsVolatileHive(RegistryHive
))
2969 CmiReleaseBlock(RegistryHive
, Block
);
2974 PCELL_HEADER pFree
= Block
;
2976 if (pFree
->CellSize
< 0)
2977 pFree
->CellSize
= -pFree
->CellSize
;
2979 /* Clear block (except the block size) */
2980 RtlZeroMemory(((PVOID
)pFree
) + sizeof(ULONG
),
2981 pFree
->CellSize
- sizeof(ULONG
));
2983 /* add block to the list of free blocks */
2984 CmiAddFree(RegistryHive
, Block
, Offset
, TRUE
);
2985 CmiReleaseBlock(RegistryHive
, Block
);
2987 /* Update time of heap */
2988 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, Offset
,&pBin
))
2989 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2991 CmiMarkBlockDirty(RegistryHive
, Offset
);
2993 /* FIXME: Set first dword to block_offset of another free block ? */
2994 /* FIXME: Concatenate with previous and next block if free */
3002 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3003 PCELL_HEADER FreeBlock
,
3004 BLOCK_OFFSET FreeOffset
)
3006 BLOCK_OFFSET BlockOffset
;
3007 BLOCK_OFFSET BinOffset
;
3013 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3014 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3016 CmiGetBlock(RegistryHive
,
3019 DPRINT("Bin %p\n", Bin
);
3023 BinOffset
= Bin
->BlockOffset
;
3024 BinSize
= Bin
->BlockSize
;
3025 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3027 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3029 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3030 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3031 if (BlockOffset
> BinOffset
&&
3032 BlockOffset
< BinOffset
+ BinSize
)
3034 DPRINT("Free block: Offset %lx Size %lx\n",
3035 BlockOffset
, BlockSize
);
3037 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3038 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3039 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3041 DPRINT("Merge current block with previous and next block\n");
3043 RegistryHive
->FreeList
[i
]->CellSize
+=
3044 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3046 FreeBlock
->CellSize
= 0;
3047 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3050 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3052 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3053 &RegistryHive
->FreeListOffset
[i
+ 2],
3054 sizeof(RegistryHive
->FreeListOffset
[0])
3055 * (RegistryHive
->FreeListSize
- i
- 2));
3057 RegistryHive
->FreeListSize
--;
3059 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3063 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3065 DPRINT("Merge current block with previous block\n");
3067 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3068 FreeBlock
->CellSize
= 0;
3070 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3074 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3076 DPRINT("Merge current block with next block\n");
3078 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3079 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3080 RegistryHive
->FreeList
[i
] = FreeBlock
;
3081 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3083 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3095 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3096 PCELL_HEADER FreeBlock
,
3097 BLOCK_OFFSET FreeOffset
,
3098 BOOLEAN MergeFreeBlocks
)
3100 PCELL_HEADER
*tmpList
;
3101 BLOCK_OFFSET
*tmpListOffset
;
3106 assert(RegistryHive
);
3109 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3110 FreeBlock
, FreeOffset
);
3112 /* Merge free blocks */
3113 if (MergeFreeBlocks
== TRUE
)
3115 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3116 return(STATUS_SUCCESS
);
3119 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3121 tmpList
= ExAllocatePool(PagedPool
,
3122 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3123 if (tmpList
== NULL
)
3124 return STATUS_INSUFFICIENT_RESOURCES
;
3126 tmpListOffset
= ExAllocatePool(PagedPool
,
3127 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
+ 32));
3129 if (tmpListOffset
== NULL
)
3131 ExFreePool(tmpList
);
3132 return STATUS_INSUFFICIENT_RESOURCES
;
3135 if (RegistryHive
->FreeListMax
)
3137 RtlMoveMemory(tmpList
,
3138 RegistryHive
->FreeList
,
3139 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3140 RtlMoveMemory(tmpListOffset
,
3141 RegistryHive
->FreeListOffset
,
3142 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
));
3143 ExFreePool(RegistryHive
->FreeList
);
3144 ExFreePool(RegistryHive
->FreeListOffset
);
3146 RegistryHive
->FreeList
= tmpList
;
3147 RegistryHive
->FreeListOffset
= tmpListOffset
;
3148 RegistryHive
->FreeListMax
+= 32;
3151 /* Add new offset to free list, maintaining list in ascending order */
3152 if ((RegistryHive
->FreeListSize
== 0)
3153 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3155 /* Add to end of list */
3156 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3157 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3159 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3161 /* Add to begin of list */
3162 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3163 &RegistryHive
->FreeList
[0],
3164 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3165 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3166 &RegistryHive
->FreeListOffset
[0],
3167 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3168 RegistryHive
->FreeList
[0] = FreeBlock
;
3169 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3170 RegistryHive
->FreeListSize
++;
3174 /* Search where to insert */
3176 maxInd
= RegistryHive
->FreeListSize
- 1;
3177 while ((maxInd
- minInd
) > 1)
3179 medInd
= (minInd
+ maxInd
) / 2;
3180 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3186 /* Insert before maxInd */
3187 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3188 &RegistryHive
->FreeList
[maxInd
],
3189 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3190 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3191 &RegistryHive
->FreeListOffset
[maxInd
],
3192 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3193 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3194 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3195 RegistryHive
->FreeListSize
++;
3198 return STATUS_SUCCESS
;
3203 CmiGetBlock(PREGISTRY_HIVE RegistryHive
,
3204 BLOCK_OFFSET BlockOffset
,
3210 if ((BlockOffset
== 0) || (BlockOffset
== (ULONG_PTR
) -1))
3213 if (IsVolatileHive(RegistryHive
))
3215 return (PVOID
) BlockOffset
;
3221 pBin
= RegistryHive
->BlockList
[BlockOffset
/ 4096];
3224 return((PVOID
)((ULONG_PTR
)pBin
+ (BlockOffset
- pBin
->BlockOffset
)));
3230 CmiLockBlock(PREGISTRY_HIVE RegistryHive
,
3233 if (IsPermanentHive(RegistryHive
))
3235 /* FIXME: Implement */
3241 CmiReleaseBlock(PREGISTRY_HIVE RegistryHive
,
3244 if (IsPermanentHive(RegistryHive
))
3246 /* FIXME: Implement */
3252 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3253 BLOCK_OFFSET BlockOffset
)
3260 if (IsVolatileHive(RegistryHive
))
3263 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3265 BlockNumber
= (ULONG
)BlockOffset
/ 4096;
3267 Cell
= CmiGetBlock(RegistryHive
,
3271 CellSize
= Cell
->CellSize
;
3273 CellSize
= -CellSize
;
3275 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, 4096) - ROUND_DOWN(BlockOffset
, 4096)) / 4096;
3277 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3280 (Cell
->CellSize
< 0) ? "used" : "free",
3283 RegistryHive
->HiveDirty
= TRUE
;
3284 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3291 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3292 BLOCK_OFFSET BinOffset
)
3298 if (IsVolatileHive(RegistryHive
))
3301 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3303 BlockNumber
= (ULONG
)BinOffset
/ 4096;
3305 Bin
= RegistryHive
->BlockList
[BlockNumber
];
3307 BlockCount
= Bin
->BlockSize
/ 4096;
3309 DPRINT(" BlockNumber %lu Size %lu BlockCount %lu\n",
3314 RegistryHive
->HiveDirty
= TRUE
;
3315 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3322 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3323 OUT PBOOLEAN Packable
)
3327 if (Packable
!= NULL
)
3330 for (i
= 0; i
< Name
->Length
; i
++)
3332 if (Name
->Buffer
[i
] > 0xFF)
3334 if (Packable
!= NULL
)
3336 return(Name
->Length
);
3340 return(Name
->Length
/ sizeof(WCHAR
));
3345 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3346 IN PCHAR NameBuffer
,
3347 IN USHORT NameBufferSize
,
3348 IN BOOLEAN NamePacked
)
3353 if (NamePacked
== TRUE
)
3355 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3358 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3360 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3366 if (Name
->Length
!= NameBufferSize
)
3369 UNameBuffer
= (PWCHAR
)NameBuffer
;
3371 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3373 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3383 CmiCopyPackedName(PWCHAR NameBuffer
,
3384 PCHAR PackedNameBuffer
,
3385 ULONG PackedNameSize
)
3389 for (i
= 0; i
< PackedNameSize
; i
++)
3390 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];