3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/regfile.c
6 * PURPOSE: Registry file manipulation routines
8 * PROGRAMMERS: No programmer listed.
13 #include <internal/debug.h>
18 /* uncomment to enable hive checks (incomplete and probably buggy) */
21 /* LOCAL MACROS *************************************************************/
23 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
25 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
27 BOOLEAN CmiDoVerify
= FALSE
;
30 CmiCalcChecksum(PULONG Buffer
);
32 /* FUNCTIONS ****************************************************************/
35 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header
)
38 RtlZeroMemory(Header
, sizeof(HIVE_HEADER
));
39 Header
->BlockId
= REG_HIVE_ID
;
40 Header
->UpdateCounter1
= 0;
41 Header
->UpdateCounter2
= 0;
42 Header
->DateModified
.u
.LowPart
= 0;
43 Header
->DateModified
.u
.HighPart
= 0;
49 Header
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
50 Header
->BlockSize
= REG_BLOCK_SIZE
;
57 CmiCreateDefaultBinHeader(PHBIN BinHeader
)
60 RtlZeroMemory(BinHeader
, sizeof(HBIN
));
61 BinHeader
->HeaderId
= REG_BIN_ID
;
62 BinHeader
->DateModified
.u
.LowPart
= 0;
63 BinHeader
->DateModified
.u
.HighPart
= 0;
64 BinHeader
->BinSize
= REG_BLOCK_SIZE
;
69 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
)
72 RtlZeroMemory(RootKeyCell
, sizeof(KEY_CELL
));
73 RootKeyCell
->CellSize
= -sizeof(KEY_CELL
);
74 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
75 RootKeyCell
->Flags
= REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
;
76 KeQuerySystemTime(&RootKeyCell
->LastWriteTime
);
77 RootKeyCell
->ParentKeyOffset
= 0;
78 RootKeyCell
->NumberOfSubKeys
= 0;
79 RootKeyCell
->HashTableOffset
= -1;
80 RootKeyCell
->NumberOfValues
= 0;
81 RootKeyCell
->ValueListOffset
= -1;
82 RootKeyCell
->SecurityKeyOffset
= 0;
83 RootKeyCell
->ClassNameOffset
= -1;
84 RootKeyCell
->NameSize
= 0;
85 RootKeyCell
->ClassSize
= 0;
90 CmiVerifyBinHeader(PHBIN BinHeader
)
97 if (BinHeader
->HeaderId
!= REG_BIN_ID
)
99 DbgPrint("Bin header ID is %.08x (should be %.08x)\n",
100 BinHeader
->HeaderId
, REG_BIN_ID
);
101 ASSERT(BinHeader
->HeaderId
== REG_BIN_ID
);
104 //BinHeader->DateModified.dwLowDateTime
106 //BinHeader->DateModified.dwHighDateTime
109 if (BinHeader
->BinSize
!= REG_BLOCK_SIZE
)
111 DbgPrint("BinSize is %.08x (should be a multiple of %.08x)\n",
112 BinHeader
->BinSize
, REG_BLOCK_SIZE
);
113 ASSERT(BinHeader
->BinSize
% REG_BLOCK_SIZE
== 0);
121 CmiVerifyKeyCell(PKEY_CELL KeyCell
)
128 if (KeyCell
->CellSize
== 0)
130 DbgPrint("CellSize is %d (must not be 0)\n",
132 ASSERT(KeyCell
->CellSize
!= 0);
135 if (KeyCell
->Id
!= REG_KEY_CELL_ID
)
137 DbgPrint("Id is %.08x (should be %.08x)\n",
138 KeyCell
->Id
, REG_KEY_CELL_ID
);
139 ASSERT(KeyCell
->Id
== REG_KEY_CELL_ID
);
144 //KeyCell->LastWriteTime;
146 if (KeyCell
->ParentKeyOffset
< 0)
148 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
149 KeyCell
->ParentKeyOffset
);
150 ASSERT(KeyCell
->ParentKeyOffset
>= 0);
153 if (KeyCell
->NumberOfSubKeys
< 0)
155 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
156 KeyCell
->NumberOfSubKeys
);
157 ASSERT(KeyCell
->NumberOfSubKeys
>= 0);
160 //KeyCell->HashTableOffset;
162 if (KeyCell
->NumberOfValues
< 0)
164 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
165 KeyCell
->NumberOfValues
);
166 ASSERT(KeyCell
->NumberOfValues
>= 0);
169 //KeyCell->ValuesOffset = -1;
171 if (KeyCell
->SecurityKeyOffset
< 0)
173 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
174 KeyCell
->SecurityKeyOffset
);
175 ASSERT(KeyCell
->SecurityKeyOffset
>= 0);
178 //KeyCell->ClassNameOffset = -1;
189 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell
)
194 CmiVerifyKeyCell(RootKeyCell
);
196 if (!(RootKeyCell
->Flags
& REG_KEY_ROOT_CELL
))
198 DbgPrint("Flags is %.08x (should be %.08x)\n",
199 RootKeyCell
->Flags
, REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
);
200 ASSERT(!(RootKeyCell
->Flags
& (REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
)));
208 CmiVerifyValueCell(PVALUE_CELL ValueCell
)
215 if (ValueCell
->CellSize
== 0)
217 DbgPrint("CellSize is %d (must not be 0)\n",
218 ValueCell
->CellSize
);
219 ASSERT(ValueCell
->CellSize
!= 0);
222 if (ValueCell
->Id
!= REG_VALUE_CELL_ID
)
224 DbgPrint("Id is %.08x (should be %.08x)\n",
225 ValueCell
->Id
, REG_VALUE_CELL_ID
);
226 ASSERT(ValueCell
->Id
== REG_VALUE_CELL_ID
);
229 //ValueCell->NameSize;
230 //ValueCell->LONG DataSize;
231 //ValueCell->DataOffset;
232 //ValueCell->ULONG DataType;
233 //ValueCell->USHORT Flags;
234 //ValueCell->USHORT Unused1;
235 //ValueCell->UCHAR Name[0];
241 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell
)
246 if (ValueListCell
->CellSize
== 0)
248 DbgPrint("CellSize is %d (must not be 0)\n",
249 ValueListCell
->CellSize
);
250 ASSERT(ValueListCell
->CellSize
!= 0);
258 CmiVerifyKeyObject(PKEY_OBJECT KeyObject
)
263 if (KeyObject
->RegistryHive
== NULL
)
265 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
266 KeyObject
->RegistryHive
);
267 ASSERT(KeyObject
->RegistryHive
!= NULL
);
270 if (KeyObject
->KeyCell
== NULL
)
272 DbgPrint("KeyCell is NULL (must not be NULL)\n",
274 ASSERT(KeyObject
->KeyCell
!= NULL
);
277 if (KeyObject
->ParentKey
== NULL
)
279 DbgPrint("ParentKey is NULL (must not be NULL)\n",
280 KeyObject
->ParentKey
);
281 ASSERT(KeyObject
->ParentKey
!= NULL
);
289 CmiVerifyHiveHeader(PHIVE_HEADER Header
)
294 if (Header
->BlockId
!= REG_HIVE_ID
)
296 DbgPrint("BlockId is %.08x (must be %.08x)\n",
299 ASSERT(Header
->BlockId
== REG_HIVE_ID
);
302 if (Header
->Unused3
!= 1)
304 DbgPrint("Unused3 is %.08x (must be 1)\n",
306 ASSERT(Header
->Unused3
== 1);
309 if (Header
->Unused4
!= 3)
311 DbgPrint("Unused4 is %.08x (must be 3)\n",
313 ASSERT(Header
->Unused4
== 3);
316 if (Header
->Unused5
!= 0)
318 DbgPrint("Unused5 is %.08x (must be 0)\n",
320 ASSERT(Header
->Unused5
== 0);
323 if (Header
->Unused6
!= 1)
325 DbgPrint("Unused6 is %.08x (must be 1)\n",
327 ASSERT(Header
->Unused6
== 1);
330 if (Header
->Unused7
!= 1)
332 DbgPrint("Unused7 is %.08x (must be 1)\n",
334 ASSERT(Header
->Unused7
== 1);
342 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive
)
347 CmiVerifyHiveHeader(RegistryHive
->HiveHeader
);
354 CmiCreateNewRegFile(HANDLE FileHandle
)
356 IO_STATUS_BLOCK IoStatusBlock
;
357 PCELL_HEADER FreeCell
;
358 PHIVE_HEADER HiveHeader
;
359 PKEY_CELL RootKeyCell
;
364 Buffer
= (PCHAR
) ExAllocatePool(NonPagedPool
, 2 * REG_BLOCK_SIZE
);
366 return STATUS_INSUFFICIENT_RESOURCES
;
368 RtlZeroMemory (Buffer
,
371 HiveHeader
= (PHIVE_HEADER
)Buffer
;
372 BinHeader
= (PHBIN
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
);
373 RootKeyCell
= (PKEY_CELL
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
);
374 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
376 CmiCreateDefaultHiveHeader(HiveHeader
);
377 CmiCreateDefaultBinHeader(BinHeader
);
378 CmiCreateDefaultRootKeyCell(RootKeyCell
);
381 BinHeader
->BinOffset
= 0;
383 /* Offset to root key block */
384 HiveHeader
->RootKeyOffset
= REG_HBIN_DATA_OFFSET
;
386 /* The rest of the block is free */
387 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
389 Status
= ZwWriteFile(FileHandle
,
401 ASSERTMSG(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
403 if (!NT_SUCCESS(Status
))
408 Status
= ZwFlushBuffersFile(FileHandle
,
417 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive
)
419 OBJECT_ATTRIBUTES ObjectAttributes
;
420 FILE_STANDARD_INFORMATION fsi
;
421 IO_STATUS_BLOCK IoStatusBlock
;
422 HANDLE HiveHandle
= INVALID_HANDLE_VALUE
;
423 HANDLE LogHandle
= INVALID_HANDLE_VALUE
;
424 PHIVE_HEADER HiveHeader
= NULL
;
425 PHIVE_HEADER LogHeader
= NULL
;
426 LARGE_INTEGER FileOffset
;
430 RTL_BITMAP BlockBitMap
;
433 DPRINT("CmiCheckAndFixHive() called\n");
435 /* Try to open the hive file */
436 InitializeObjectAttributes(&ObjectAttributes
,
437 &RegistryHive
->HiveFileName
,
438 OBJ_CASE_INSENSITIVE
,
442 Status
= ZwCreateFile(&HiveHandle
,
443 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
447 FILE_ATTRIBUTE_NORMAL
,
450 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
453 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
455 return(STATUS_SUCCESS
);
457 if (!NT_SUCCESS(Status
))
459 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
463 /* Try to open the log file */
464 InitializeObjectAttributes(&ObjectAttributes
,
465 &RegistryHive
->LogFileName
,
466 OBJ_CASE_INSENSITIVE
,
470 Status
= ZwCreateFile(&LogHandle
,
471 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
475 FILE_ATTRIBUTE_NORMAL
,
478 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
481 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
483 LogHandle
= INVALID_HANDLE_VALUE
;
485 else if (!NT_SUCCESS(Status
))
487 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
492 /* Allocate hive header */
493 HiveHeader
= ExAllocatePool(PagedPool
,
494 sizeof(HIVE_HEADER
));
495 if (HiveHeader
== NULL
)
497 DPRINT("ExAllocatePool() failed\n");
498 Status
= STATUS_INSUFFICIENT_RESOURCES
;
502 /* Read hive base block */
503 FileOffset
.QuadPart
= 0ULL;
504 Status
= ZwReadFile(HiveHandle
,
513 if (!NT_SUCCESS(Status
))
515 DPRINT("ZwReadFile() failed (Status %lx)\n", Status
);
519 if (LogHandle
== INVALID_HANDLE_VALUE
)
521 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
522 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
524 /* There is no way to fix the hive without log file - BSOD! */
525 DPRINT("Hive header inconsistent and no log file available!\n");
526 KEBUGCHECK(CONFIG_LIST_FAILED
);
529 Status
= STATUS_SUCCESS
;
534 /* Allocate hive header */
535 LogHeader
= ExAllocatePool(PagedPool
,
536 sizeof(HIVE_HEADER
));
537 if (LogHeader
== NULL
)
539 DPRINT("ExAllocatePool() failed\n");
540 Status
= STATUS_INSUFFICIENT_RESOURCES
;
544 /* Read log file header */
545 FileOffset
.QuadPart
= 0ULL;
546 Status
= ZwReadFile(LogHandle
,
555 if (!NT_SUCCESS(Status
))
557 DPRINT("ZwReadFile() failed (Status %lx)\n", Status
);
561 /* Check log file header integrity */
562 if (LogHeader
->Checksum
!= CmiCalcChecksum((PULONG
)LogHeader
) ||
563 LogHeader
->UpdateCounter1
!= LogHeader
->UpdateCounter2
)
565 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
566 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
568 DPRINT("Hive file and log file are inconsistent!\n");
569 KEBUGCHECK(CONFIG_LIST_FAILED
);
572 /* Log file damaged but hive is okay */
573 Status
= STATUS_SUCCESS
;
577 if (HiveHeader
->UpdateCounter1
== HiveHeader
->UpdateCounter2
&&
578 HiveHeader
->UpdateCounter1
== LogHeader
->UpdateCounter1
)
580 /* Hive and log file are up-to-date */
581 Status
= STATUS_SUCCESS
;
586 * Hive needs an update!
590 Status
= ZwQueryInformationFile(LogHandle
,
594 FileStandardInformation
);
595 if (!NT_SUCCESS(Status
))
597 DPRINT("ZwQueryInformationFile() failed (Status %lx)\n", Status
);
600 FileSize
= fsi
.EndOfFile
.u
.LowPart
;
602 /* Calculate bitmap and block size */
603 BitmapSize
= ROUND_UP((FileSize
/ REG_BLOCK_SIZE
) - 1, sizeof(ULONG
) * 8) / 8;
604 BufferSize
= sizeof(HIVE_HEADER
) +
607 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
609 /* Reallocate log header block */
610 ExFreePool(LogHeader
);
611 LogHeader
= ExAllocatePool(PagedPool
,
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
= ZwReadFile(LogHandle
,
631 if (!NT_SUCCESS(Status
))
633 DPRINT("ZwReadFile() failed (Status %lx)\n", Status
);
637 /* Initialize bitmap */
638 RtlInitializeBitMap(&BlockBitMap
,
639 (PVOID
)((ULONG_PTR
)LogHeader
+ REG_BLOCK_SIZE
+ sizeof(ULONG
)),
642 /* FIXME: Update dirty blocks */
645 /* FIXME: Update hive header */
648 Status
= STATUS_SUCCESS
;
652 /* Clean up the mess */
654 if (HiveHeader
!= NULL
)
655 ExFreePool(HiveHeader
);
657 if (LogHeader
!= NULL
)
658 ExFreePool(LogHeader
);
660 if (LogHandle
!= INVALID_HANDLE_VALUE
)
671 CmiImportHiveBins(PREGISTRY_HIVE Hive
,
674 BLOCK_OFFSET BlockOffset
;
681 while (BlockIndex
< Hive
->BlockListSize
)
683 Bin
= (PHBIN
)((ULONG_PTR
)ChunkPtr
+ BlockOffset
);
685 if (Bin
->HeaderId
!= REG_BIN_ID
)
687 DPRINT1 ("Bad bin header id %x, offset %x\n", Bin
->HeaderId
, BlockOffset
);
688 return STATUS_REGISTRY_CORRUPT
;
691 ASSERTMSG((Bin
->BinSize
% REG_BLOCK_SIZE
) == 0,
692 ("Bin size (0x%.08x) must be multiple of 4K\n",
695 /* Allocate the hive block */
696 Hive
->BlockList
[BlockIndex
].Bin
= ExAllocatePool (PagedPool
,
698 if (Hive
->BlockList
[BlockIndex
].Bin
== NULL
)
700 DPRINT1 ("ExAllocatePool() failed\n");
701 return STATUS_INSUFFICIENT_RESOURCES
;
703 Hive
->BlockList
[BlockIndex
].Block
= (PVOID
)Hive
->BlockList
[BlockIndex
].Bin
;
706 RtlCopyMemory (Hive
->BlockList
[BlockIndex
].Bin
,
710 if (Bin
->BinSize
> REG_BLOCK_SIZE
)
712 for (j
= 1; j
< Bin
->BinSize
/ REG_BLOCK_SIZE
; j
++)
714 Hive
->BlockList
[BlockIndex
+ j
].Bin
= Hive
->BlockList
[BlockIndex
].Bin
;
715 Hive
->BlockList
[BlockIndex
+ j
].Block
=
716 (PVOID
)((ULONG_PTR
)Hive
->BlockList
[BlockIndex
].Bin
+ (j
* REG_BLOCK_SIZE
));
720 BlockIndex
+= Bin
->BinSize
/ REG_BLOCK_SIZE
;
721 BlockOffset
+= Bin
->BinSize
;
724 return STATUS_SUCCESS
;
729 CmiFreeHiveBins (PREGISTRY_HIVE Hive
)
735 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
737 if (Hive
->BlockList
[i
].Bin
== NULL
)
740 if (Hive
->BlockList
[i
].Bin
!= Bin
)
742 Bin
= Hive
->BlockList
[i
].Bin
;
743 ExFreePool (Hive
->BlockList
[i
].Bin
);
745 Hive
->BlockList
[i
].Bin
= NULL
;
746 Hive
->BlockList
[i
].Block
= NULL
;
752 CmiCreateHiveFreeCellList(PREGISTRY_HIVE Hive
)
754 BLOCK_OFFSET BlockOffset
;
755 PCELL_HEADER FreeBlock
;
761 /* Initialize the free cell list */
762 Hive
->FreeListSize
= 0;
763 Hive
->FreeListMax
= 0;
764 Hive
->FreeList
= NULL
;
765 Hive
->FreeListOffset
= NULL
;
769 while (BlockIndex
< Hive
->BlockListSize
)
771 Bin
= Hive
->BlockList
[BlockIndex
].Bin
;
773 /* Search free blocks and add to list */
774 FreeOffset
= REG_HBIN_DATA_OFFSET
;
775 while (FreeOffset
< Bin
->BinSize
)
777 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) Bin
+ FreeOffset
);
778 if (FreeBlock
->CellSize
> 0)
780 Status
= CmiAddFree(Hive
,
782 Bin
->BinOffset
+ FreeOffset
,
785 if (!NT_SUCCESS(Status
))
790 FreeOffset
+= FreeBlock
->CellSize
;
794 FreeOffset
-= FreeBlock
->CellSize
;
798 BlockIndex
+= Bin
->BinSize
/ REG_BLOCK_SIZE
;
799 BlockOffset
+= Bin
->BinSize
;
802 return STATUS_SUCCESS
;
807 CmiFreeHiveFreeCellList(PREGISTRY_HIVE Hive
)
809 ExFreePool (Hive
->FreeList
);
810 ExFreePool (Hive
->FreeListOffset
);
812 Hive
->FreeListSize
= 0;
813 Hive
->FreeListMax
= 0;
814 Hive
->FreeList
= NULL
;
815 Hive
->FreeListOffset
= NULL
;
820 CmiCreateHiveBitmap(PREGISTRY_HIVE Hive
)
824 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
825 BitmapSize
= ROUND_UP(Hive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
826 DPRINT("Hive->BlockListSize: %lu\n", Hive
->BlockListSize
);
827 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
829 /* Allocate bitmap */
830 Hive
->BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
832 if (Hive
->BitmapBuffer
== NULL
)
834 return STATUS_INSUFFICIENT_RESOURCES
;
837 RtlInitializeBitMap(&Hive
->DirtyBitMap
,
841 /* Initialize bitmap */
842 RtlClearAllBits(&Hive
->DirtyBitMap
);
843 Hive
->HiveDirty
= FALSE
;
845 return STATUS_SUCCESS
;
850 CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive
,
853 OBJECT_ATTRIBUTES ObjectAttributes
;
854 ULONG CreateDisposition
;
855 IO_STATUS_BLOCK IoSB
;
857 PSECTION_OBJECT SectionObject
;
862 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) called\n",
863 RegistryHive
, Filename
);
865 /* Duplicate Filename */
866 Status
= RtlpCreateUnicodeString(&RegistryHive
->HiveFileName
,
867 Filename
, NonPagedPool
);
868 if (!NT_SUCCESS(Status
))
870 DPRINT("RtlpCreateUnicodeString() failed (Status %lx)\n", Status
);
874 /* Create log file name */
875 RegistryHive
->LogFileName
.Length
= (wcslen(Filename
) + 4) * sizeof(WCHAR
);
876 RegistryHive
->LogFileName
.MaximumLength
= RegistryHive
->LogFileName
.Length
+ sizeof(WCHAR
);
877 RegistryHive
->LogFileName
.Buffer
= ExAllocatePool(NonPagedPool
,
878 RegistryHive
->LogFileName
.MaximumLength
);
879 if (RegistryHive
->LogFileName
.Buffer
== NULL
)
881 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
882 DPRINT("ExAllocatePool() failed\n");
883 return(STATUS_INSUFFICIENT_RESOURCES
);
885 wcscpy(RegistryHive
->LogFileName
.Buffer
,
887 wcscat(RegistryHive
->LogFileName
.Buffer
,
891 /* Check and eventually fix a hive */
892 Status
= CmiCheckAndFixHive(RegistryHive
);
893 if (!NT_SUCCESS(Status
))
895 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
896 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
897 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status
);
902 InitializeObjectAttributes(&ObjectAttributes
,
903 &RegistryHive
->HiveFileName
,
904 OBJ_CASE_INSENSITIVE
,
908 CreateDisposition
= FILE_OPEN_IF
;
909 Status
= ZwCreateFile(&FileHandle
,
914 FILE_ATTRIBUTE_NORMAL
,
917 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
920 if (!NT_SUCCESS(Status
))
922 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
923 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
924 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
928 if (IoSB
.Information
!= FILE_OPENED
)
930 Status
= CmiCreateNewRegFile(FileHandle
);
931 if (!NT_SUCCESS(Status
))
933 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status
);
935 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
936 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
941 /* Create the hive section */
942 Status
= MmCreateSection(&SectionObject
,
950 if (!NT_SUCCESS(Status
))
952 DPRINT1("MmCreateSection() failed (Status %lx)\n", Status
);
953 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
954 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
958 /* Map the hive file */
961 Status
= MmMapViewOfSection(SectionObject
,
962 PsGetCurrentProcess(),
971 if (!NT_SUCCESS(Status
))
973 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status
);
974 ObDereferenceObject(SectionObject
);
975 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
976 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
980 DPRINT("ViewBase %p ViewSize %lx\n", ViewBase
, ViewSize
);
982 /* Copy hive header and initalize hive */
983 RtlCopyMemory (RegistryHive
->HiveHeader
,
985 sizeof(HIVE_HEADER
));
986 RegistryHive
->FileSize
= ViewSize
;
987 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ REG_BLOCK_SIZE
) - 1;
988 RegistryHive
->UpdateCounter
= RegistryHive
->HiveHeader
->UpdateCounter1
;
990 /* Allocate hive block list */
991 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
992 RegistryHive
->BlockListSize
* sizeof(BLOCK_LIST_ENTRY
));
993 if (RegistryHive
->BlockList
== NULL
)
995 DPRINT1("Failed to allocate the hive block list\n");
996 MmUnmapViewOfSection(PsGetCurrentProcess(),
998 ObDereferenceObject(SectionObject
);
999 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1000 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1001 ZwClose(FileHandle
);
1002 return STATUS_INSUFFICIENT_RESOURCES
;
1004 RtlZeroMemory (RegistryHive
->BlockList
,
1005 RegistryHive
->BlockListSize
* sizeof(BLOCK_LIST_ENTRY
));
1007 /* Import the hive bins */
1008 Status
= CmiImportHiveBins (RegistryHive
,
1009 ViewBase
+ REG_BLOCK_SIZE
);
1010 if (!NT_SUCCESS(Status
))
1012 ExFreePool(RegistryHive
->BlockList
);
1013 MmUnmapViewOfSection(PsGetCurrentProcess(),
1015 ObDereferenceObject(SectionObject
);
1016 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1017 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1018 ZwClose(FileHandle
);
1022 /* Unmap and dereference the hive section */
1023 MmUnmapViewOfSection(PsGetCurrentProcess(),
1025 ObDereferenceObject(SectionObject
);
1027 /* Close the hive file */
1028 ZwClose(FileHandle
);
1030 /* Initialize the free cell list */
1031 Status
= CmiCreateHiveFreeCellList (RegistryHive
);
1032 if (!NT_SUCCESS(Status
))
1034 CmiFreeHiveBins(RegistryHive
);
1035 ExFreePool(RegistryHive
->BlockList
);
1036 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1037 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1041 /* Create the block bitmap */
1042 Status
= CmiCreateHiveBitmap (RegistryHive
);
1043 if (!NT_SUCCESS(Status
))
1045 CmiFreeHiveFreeCellList(RegistryHive
);
1046 CmiFreeHiveBins(RegistryHive
);
1047 ExFreePool(RegistryHive
->BlockList
);
1048 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1049 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1053 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n",
1054 RegistryHive
, Filename
);
1056 return STATUS_SUCCESS
;
1061 CmiCreateVolatileHive(PREGISTRY_HIVE
*RegistryHive
)
1063 PKEY_CELL RootKeyCell
;
1064 PREGISTRY_HIVE Hive
;
1066 *RegistryHive
= NULL
;
1068 Hive
= ExAllocatePool (NonPagedPool
,
1069 sizeof(REGISTRY_HIVE
));
1071 return STATUS_INSUFFICIENT_RESOURCES
;
1073 RtlZeroMemory (Hive
,
1074 sizeof(REGISTRY_HIVE
));
1076 DPRINT("Hive %x\n", Hive
);
1078 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1079 sizeof(HIVE_HEADER
));
1080 if (Hive
->HiveHeader
== NULL
)
1083 return STATUS_INSUFFICIENT_RESOURCES
;
1085 RtlZeroMemory (Hive
->HiveHeader
,
1086 sizeof(HIVE_HEADER
));
1088 Hive
->Flags
= (HIVE_NO_FILE
| HIVE_POINTER
);
1090 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1092 RootKeyCell
= (PKEY_CELL
)ExAllocatePool (NonPagedPool
,
1094 if (RootKeyCell
== NULL
)
1096 ExFreePool(Hive
->HiveHeader
);
1098 return STATUS_INSUFFICIENT_RESOURCES
;
1101 CmiCreateDefaultRootKeyCell (RootKeyCell
);
1102 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)RootKeyCell
;
1104 /* Acquire hive list lock exclusively */
1105 KeEnterCriticalRegion();
1106 ExAcquireResourceExclusiveLite (&CmiRegistryLock
, TRUE
);
1108 /* Add the new hive to the hive list */
1109 InsertTailList (&CmiHiveListHead
,
1112 /* Release hive list lock */
1113 ExReleaseResourceLite (&CmiRegistryLock
);
1114 KeLeaveCriticalRegion();
1116 VERIFY_REGISTRY_HIVE (Hive
);
1118 *RegistryHive
= Hive
;
1120 return STATUS_SUCCESS
;
1125 CmiCreateTempHive(PREGISTRY_HIVE
*RegistryHive
)
1128 PCELL_HEADER FreeCell
;
1129 PREGISTRY_HIVE Hive
;
1132 DPRINT ("CmiCreateTempHive() called\n");
1134 *RegistryHive
= NULL
;
1136 Hive
= ExAllocatePool (NonPagedPool
,
1137 sizeof(REGISTRY_HIVE
));
1140 DPRINT1 ("Failed to allocate registry hive block\n");
1141 return STATUS_INSUFFICIENT_RESOURCES
;
1143 RtlZeroMemory (Hive
,
1144 sizeof(REGISTRY_HIVE
));
1146 DPRINT ("Hive %x\n", Hive
);
1148 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1150 if (Hive
->HiveHeader
== NULL
)
1152 DPRINT1 ("Failed to allocate hive header block\n");
1154 return STATUS_INSUFFICIENT_RESOURCES
;
1156 RtlZeroMemory (Hive
->HiveHeader
,
1159 DPRINT ("HiveHeader %x\n", Hive
->HiveHeader
);
1161 Hive
->Flags
= HIVE_NO_FILE
;
1163 RtlInitUnicodeString (&Hive
->HiveFileName
,
1165 RtlInitUnicodeString (&Hive
->LogFileName
,
1168 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1170 /* Allocate hive block list */
1171 Hive
->BlockList
= ExAllocatePool (NonPagedPool
,
1172 sizeof(PBLOCK_LIST_ENTRY
));
1173 if (Hive
->BlockList
== NULL
)
1175 DPRINT1 ("Failed to allocate hive block list\n");
1176 ExFreePool(Hive
->HiveHeader
);
1178 return STATUS_INSUFFICIENT_RESOURCES
;
1181 /* Allocate first Bin */
1182 Hive
->BlockList
[0].Bin
= ExAllocatePool (NonPagedPool
,
1184 if (Hive
->BlockList
[0].Bin
== NULL
)
1186 DPRINT1 ("Failed to allocate first bin\n");
1187 ExFreePool(Hive
->BlockList
);
1188 ExFreePool(Hive
->HiveHeader
);
1190 return STATUS_INSUFFICIENT_RESOURCES
;
1192 Hive
->BlockList
[0].Block
= (PVOID
)Hive
->BlockList
[0].Bin
;
1194 Hive
->FileSize
= 2* REG_BLOCK_SIZE
;
1195 Hive
->BlockListSize
= 1;
1196 Hive
->UpdateCounter
= Hive
->HiveHeader
->UpdateCounter1
;
1199 BinHeader
= Hive
->BlockList
[0].Bin
;
1200 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)BinHeader
+ REG_HBIN_DATA_OFFSET
);
1202 CmiCreateDefaultBinHeader (BinHeader
);
1205 BinHeader
->BinOffset
= 0;
1207 /* Offset to root key block */
1208 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
1210 /* The rest of the block is free */
1211 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
1213 /* Create the free cell list */
1214 Status
= CmiCreateHiveFreeCellList (Hive
);
1215 if (Hive
->BlockList
[0].Bin
== NULL
)
1217 DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status
);
1218 ExFreePool(Hive
->BlockList
[0].Bin
);
1219 ExFreePool(Hive
->BlockList
);
1220 ExFreePool(Hive
->HiveHeader
);
1225 /* Acquire hive list lock exclusively */
1226 KeEnterCriticalRegion();
1227 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1229 /* Add the new hive to the hive list */
1230 InsertTailList (&CmiHiveListHead
,
1233 /* Release hive list lock */
1234 ExReleaseResourceLite(&CmiRegistryLock
);
1235 KeLeaveCriticalRegion();
1237 VERIFY_REGISTRY_HIVE (Hive
);
1239 *RegistryHive
= Hive
;
1241 return STATUS_SUCCESS
;
1246 CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1247 IN PUNICODE_STRING FileName
,
1250 PREGISTRY_HIVE Hive
;
1253 DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName
);
1255 if (Flags
& ~REG_NO_LAZY_FLUSH
)
1256 return STATUS_INVALID_PARAMETER
;
1258 Hive
= ExAllocatePool (NonPagedPool
,
1259 sizeof(REGISTRY_HIVE
));
1262 DPRINT1 ("Failed to allocate hive header.\n");
1263 return STATUS_INSUFFICIENT_RESOURCES
;
1265 RtlZeroMemory (Hive
,
1266 sizeof(REGISTRY_HIVE
));
1268 DPRINT ("Hive %x\n", Hive
);
1269 Hive
->Flags
= (Flags
& REG_NO_LAZY_FLUSH
) ? HIVE_NO_SYNCH
: 0;
1271 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool(NonPagedPool
,
1272 sizeof(HIVE_HEADER
));
1273 if (Hive
->HiveHeader
== NULL
)
1275 DPRINT1 ("Failed to allocate hive header.\n");
1277 return STATUS_INSUFFICIENT_RESOURCES
;
1280 RtlZeroMemory (Hive
->HiveHeader
,
1281 sizeof(HIVE_HEADER
));
1283 Status
= CmiInitNonVolatileRegistryHive (Hive
,
1285 if (!NT_SUCCESS (Status
))
1287 DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status
);
1288 ExFreePool (Hive
->HiveHeader
);
1293 /* Add the new hive to the hive list */
1294 InsertTailList (&CmiHiveListHead
,
1297 VERIFY_REGISTRY_HIVE(Hive
);
1299 Status
= CmiConnectHive (KeyObjectAttributes
,
1301 if (!NT_SUCCESS(Status
))
1303 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status
);
1304 // CmiRemoveRegistryHive (Hive);
1307 DPRINT ("CmiLoadHive() done\n");
1314 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
1316 if (RegistryHive
->Flags
& HIVE_POINTER
)
1317 return STATUS_UNSUCCESSFUL
;
1319 /* Remove hive from hive list */
1320 RemoveEntryList (&RegistryHive
->HiveList
);
1322 /* Release file names */
1323 RtlFreeUnicodeString (&RegistryHive
->HiveFileName
);
1324 RtlFreeUnicodeString (&RegistryHive
->LogFileName
);
1326 /* Release hive bitmap */
1327 ExFreePool (RegistryHive
->BitmapBuffer
);
1329 /* Release free cell list */
1330 ExFreePool (RegistryHive
->FreeList
);
1331 ExFreePool (RegistryHive
->FreeListOffset
);
1333 /* Release bins and bin list */
1334 CmiFreeHiveBins (RegistryHive
);
1335 ExFreePool (RegistryHive
->BlockList
);
1337 /* Release hive header */
1338 ExFreePool (RegistryHive
->HiveHeader
);
1341 ExFreePool (RegistryHive
);
1343 return STATUS_SUCCESS
;
1348 CmiCalcChecksum(PULONG Buffer
)
1353 for (i
= 0; i
< 127; i
++)
1361 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
1363 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1364 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1365 OBJECT_ATTRIBUTES ObjectAttributes
;
1366 IO_STATUS_BLOCK IoStatusBlock
;
1368 LARGE_INTEGER FileOffset
;
1378 DPRINT("CmiStartLogUpdate() called\n");
1380 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1381 BufferSize
= sizeof(HIVE_HEADER
) +
1384 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1386 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1388 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
,
1392 DPRINT("ExAllocatePool() failed\n");
1393 return(STATUS_INSUFFICIENT_RESOURCES
);
1395 RtlZeroMemory (Buffer
,
1398 /* Open log file for writing */
1399 InitializeObjectAttributes(&ObjectAttributes
,
1400 &RegistryHive
->LogFileName
,
1401 OBJ_CASE_INSENSITIVE
,
1405 Status
= ZwCreateFile(&FileHandle
,
1410 FILE_ATTRIBUTE_NORMAL
,
1413 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1416 if (!NT_SUCCESS(Status
))
1418 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1423 /* Update firt update counter and checksum */
1424 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1425 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1427 /* Copy hive header */
1428 RtlCopyMemory(Buffer
,
1429 RegistryHive
->HiveHeader
,
1430 sizeof(HIVE_HEADER
));
1431 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1438 RegistryHive
->DirtyBitMap
.Buffer
,
1441 /* Write hive block and block bitmap */
1442 FileOffset
.QuadPart
= (ULONGLONG
)0;
1443 Status
= ZwWriteFile(FileHandle
,
1452 if (!NT_SUCCESS(Status
))
1454 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1455 ZwClose(FileHandle
);
1461 /* Write dirty blocks */
1462 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1464 while (BlockIndex
< RegistryHive
->BlockListSize
)
1466 LastIndex
= BlockIndex
;
1467 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1470 if (BlockIndex
== (ULONG
)-1 || BlockIndex
< LastIndex
)
1472 DPRINT("No more set bits\n");
1473 Status
= STATUS_SUCCESS
;
1477 DPRINT("Block %lu is dirty\n", BlockIndex
);
1479 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1480 DPRINT("BlockPtr %p\n", BlockPtr
);
1481 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1483 /* Write hive block */
1484 Status
= ZwWriteFile(FileHandle
,
1493 if (!NT_SUCCESS(Status
))
1495 DPRINT1("ZwWriteFile() failed (Status %lx)\n", Status
);
1496 ZwClose(FileHandle
);
1501 FileOffset
.QuadPart
+= (ULONGLONG
)REG_BLOCK_SIZE
;
1504 /* Truncate log file */
1505 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1506 Status
= ZwSetInformationFile(FileHandle
,
1509 sizeof(FILE_END_OF_FILE_INFORMATION
),
1510 FileEndOfFileInformation
);
1511 if (!NT_SUCCESS(Status
))
1513 DPRINT("ZwSetInformationFile() failed (Status %lx)\n", Status
);
1514 ZwClose(FileHandle
);
1518 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1519 Status
= ZwSetInformationFile(FileHandle
,
1521 &FileAllocationInfo
,
1522 sizeof(FILE_ALLOCATION_INFORMATION
),
1523 FileAllocationInformation
);
1524 if (!NT_SUCCESS(Status
))
1526 DPRINT("ZwSetInformationFile() failed (Status %lx)\n", Status
);
1527 ZwClose(FileHandle
);
1531 /* Flush the log file */
1532 Status
= ZwFlushBuffersFile(FileHandle
,
1534 if (!NT_SUCCESS(Status
))
1536 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1539 ZwClose(FileHandle
);
1546 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1548 OBJECT_ATTRIBUTES ObjectAttributes
;
1549 IO_STATUS_BLOCK IoStatusBlock
;
1551 LARGE_INTEGER FileOffset
;
1558 DPRINT("CmiFinishLogUpdate() called\n");
1560 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1561 BufferSize
= sizeof(HIVE_HEADER
) +
1564 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1566 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1568 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1571 DPRINT("ExAllocatePool() failed\n");
1572 return(STATUS_INSUFFICIENT_RESOURCES
);
1575 /* Open log file for writing */
1576 InitializeObjectAttributes(&ObjectAttributes
,
1577 &RegistryHive
->LogFileName
,
1578 OBJ_CASE_INSENSITIVE
,
1582 Status
= ZwCreateFile(&FileHandle
,
1587 FILE_ATTRIBUTE_NORMAL
,
1590 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1593 if (!NT_SUCCESS(Status
))
1595 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1600 /* Update first and second update counter and checksum */
1601 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1602 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1603 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1605 /* Copy hive header */
1606 RtlCopyMemory(Buffer
,
1607 RegistryHive
->HiveHeader
,
1608 sizeof(HIVE_HEADER
));
1609 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1611 /* Write empty block bitmap */
1619 /* Write hive block and block bitmap */
1620 FileOffset
.QuadPart
= (ULONGLONG
)0;
1621 Status
= ZwWriteFile(FileHandle
,
1630 if (!NT_SUCCESS(Status
))
1632 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1633 ZwClose(FileHandle
);
1640 /* Flush the log file */
1641 Status
= ZwFlushBuffersFile(FileHandle
,
1643 if (!NT_SUCCESS(Status
))
1645 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1648 ZwClose(FileHandle
);
1655 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1657 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1658 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1659 OBJECT_ATTRIBUTES ObjectAttributes
;
1660 IO_STATUS_BLOCK IoStatusBlock
;
1666 DPRINT("CmiCleanupLogUpdate() called\n");
1668 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1669 BufferSize
= sizeof(HIVE_HEADER
) +
1672 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1674 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1676 /* Open log file for writing */
1677 InitializeObjectAttributes(&ObjectAttributes
,
1678 &RegistryHive
->LogFileName
,
1679 OBJ_CASE_INSENSITIVE
,
1683 Status
= ZwCreateFile(&FileHandle
,
1688 FILE_ATTRIBUTE_NORMAL
,
1691 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1694 if (!NT_SUCCESS(Status
))
1696 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1700 /* Truncate log file */
1701 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1702 Status
= ZwSetInformationFile(FileHandle
,
1705 sizeof(FILE_END_OF_FILE_INFORMATION
),
1706 FileEndOfFileInformation
);
1707 if (!NT_SUCCESS(Status
))
1709 DPRINT("ZwSetInformationFile() failed (Status %lx)\n", Status
);
1710 ZwClose(FileHandle
);
1714 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1715 Status
= ZwSetInformationFile(FileHandle
,
1717 &FileAllocationInfo
,
1718 sizeof(FILE_ALLOCATION_INFORMATION
),
1719 FileAllocationInformation
);
1720 if (!NT_SUCCESS(Status
))
1722 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1723 ZwClose(FileHandle
);
1727 /* Flush the log file */
1728 Status
= ZwFlushBuffersFile(FileHandle
,
1730 if (!NT_SUCCESS(Status
))
1732 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1735 ZwClose(FileHandle
);
1742 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1744 OBJECT_ATTRIBUTES ObjectAttributes
;
1745 IO_STATUS_BLOCK IoStatusBlock
;
1747 LARGE_INTEGER FileOffset
;
1753 DPRINT("CmiStartHiveUpdate() called\n");
1755 /* Open hive for writing */
1756 InitializeObjectAttributes(&ObjectAttributes
,
1757 &RegistryHive
->HiveFileName
,
1758 OBJ_CASE_INSENSITIVE
,
1762 Status
= ZwCreateFile(&FileHandle
,
1767 FILE_ATTRIBUTE_NORMAL
,
1770 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1773 if (!NT_SUCCESS(Status
))
1775 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1779 /* Update firt update counter and checksum */
1780 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1781 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1783 /* Write hive block */
1784 FileOffset
.QuadPart
= (ULONGLONG
)0;
1785 Status
= ZwWriteFile(FileHandle
,
1790 RegistryHive
->HiveHeader
,
1791 sizeof(HIVE_HEADER
),
1794 if (!NT_SUCCESS(Status
))
1796 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1797 ZwClose(FileHandle
);
1802 while (BlockIndex
< RegistryHive
->BlockListSize
)
1804 LastIndex
= BlockIndex
;
1805 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1808 if (BlockIndex
== (ULONG
)-1 || BlockIndex
< LastIndex
)
1810 DPRINT("No more set bits\n");
1811 Status
= STATUS_SUCCESS
;
1815 DPRINT("Block %lu is dirty\n", BlockIndex
);
1817 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1818 DPRINT(" BlockPtr %p\n", BlockPtr
);
1820 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
1821 DPRINT(" File offset %I64x\n", FileOffset
.QuadPart
);
1823 /* Write hive block */
1824 Status
= ZwWriteFile(FileHandle
,
1833 if (!NT_SUCCESS(Status
))
1835 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1836 ZwClose(FileHandle
);
1843 Status
= ZwFlushBuffersFile(FileHandle
,
1845 if (!NT_SUCCESS(Status
))
1847 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1850 ZwClose(FileHandle
);
1857 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1859 OBJECT_ATTRIBUTES ObjectAttributes
;
1860 IO_STATUS_BLOCK IoStatusBlock
;
1861 LARGE_INTEGER FileOffset
;
1865 DPRINT("CmiFinishHiveUpdate() called\n");
1867 InitializeObjectAttributes(&ObjectAttributes
,
1868 &RegistryHive
->HiveFileName
,
1869 OBJ_CASE_INSENSITIVE
,
1873 Status
= ZwCreateFile(&FileHandle
,
1878 FILE_ATTRIBUTE_NORMAL
,
1881 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1884 if (!NT_SUCCESS(Status
))
1886 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1890 /* Update second update counter and checksum */
1891 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1892 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1893 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1895 /* Write hive block */
1896 FileOffset
.QuadPart
= (ULONGLONG
)0;
1897 Status
= ZwWriteFile(FileHandle
,
1902 RegistryHive
->HiveHeader
,
1903 sizeof(HIVE_HEADER
),
1906 if (!NT_SUCCESS(Status
))
1908 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1909 ZwClose(FileHandle
);
1913 Status
= ZwFlushBuffersFile(FileHandle
,
1915 if (!NT_SUCCESS(Status
))
1917 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1920 ZwClose(FileHandle
);
1927 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1931 DPRINT("CmiFlushRegistryHive() called\n");
1933 if (RegistryHive
->HiveDirty
== FALSE
)
1935 return(STATUS_SUCCESS
);
1938 DPRINT("Hive '%wZ' is dirty\n",
1939 &RegistryHive
->HiveFileName
);
1940 DPRINT("Log file: '%wZ'\n",
1941 &RegistryHive
->LogFileName
);
1943 /* Update hive header modification time */
1944 KeQuerySystemTime(&RegistryHive
->HiveHeader
->DateModified
);
1946 /* Start log update */
1947 Status
= CmiStartLogUpdate(RegistryHive
);
1948 if (!NT_SUCCESS(Status
))
1950 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1954 /* Finish log update */
1955 Status
= CmiFinishLogUpdate(RegistryHive
);
1956 if (!NT_SUCCESS(Status
))
1958 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1962 /* Start hive update */
1963 Status
= CmiStartHiveUpdate(RegistryHive
);
1964 if (!NT_SUCCESS(Status
))
1966 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1970 /* Finish the hive update */
1971 Status
= CmiFinishHiveUpdate(RegistryHive
);
1972 if (!NT_SUCCESS(Status
))
1974 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
1978 /* Cleanup log update */
1979 Status
= CmiCleanupLogUpdate(RegistryHive
);
1980 if (!NT_SUCCESS(Status
))
1982 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1986 /* Increment hive update counter */
1987 RegistryHive
->UpdateCounter
++;
1989 /* Clear dirty bitmap and dirty flag */
1990 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
1991 RegistryHive
->HiveDirty
= FALSE
;
1993 DPRINT("CmiFlushRegistryHive() done\n");
1995 return(STATUS_SUCCESS
);
2000 CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject
)
2007 VERIFY_KEY_OBJECT(KeyObject
);
2009 KeyCell
= KeyObject
->KeyCell
;
2010 VERIFY_KEY_CELL(KeyCell
);
2012 SubKeyCount
= (KeyCell
== NULL
) ? 0 : KeyCell
->NumberOfSubKeys
;
2014 /* Search for volatile or 'foreign' keys */
2015 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2017 CurKey
= KeyObject
->SubKeys
[i
];
2018 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2019 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2030 CmiGetMaxNameLength(PKEY_OBJECT KeyObject
)
2032 PHASH_TABLE_CELL HashBlock
;
2034 PKEY_CELL CurSubKeyCell
;
2040 VERIFY_KEY_OBJECT(KeyObject
);
2042 KeyCell
= KeyObject
->KeyCell
;
2043 VERIFY_KEY_CELL(KeyCell
);
2046 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2047 KeyCell
->HashTableOffset
,
2049 if (HashBlock
== NULL
)
2051 DPRINT("CmiGetBlock() failed\n");
2055 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2057 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2059 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2060 HashBlock
->Table
[i
].KeyOffset
,
2062 if (CurSubKeyCell
== NULL
)
2064 DPRINT("CmiGetBlock() failed\n");
2068 NameSize
= CurSubKeyCell
->NameSize
;
2069 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2071 NameSize
*= sizeof(WCHAR
);
2074 if (NameSize
> MaxName
)
2082 DPRINT ("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2083 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2085 CurKey
= KeyObject
->SubKeys
[i
];
2086 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2087 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2089 CurSubKeyCell
= CurKey
->KeyCell
;
2090 if (CurSubKeyCell
== NULL
)
2092 DPRINT("CmiGetBlock() failed\n");
2096 if ((CurSubKeyCell
->Flags
& REG_KEY_ROOT_CELL
) == REG_KEY_ROOT_CELL
)
2098 /* Use name of the key object */
2099 NameSize
= CurKey
->Name
.Length
;
2103 /* Use name of the key cell */
2104 NameSize
= CurSubKeyCell
->NameSize
;
2105 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2107 NameSize
*= sizeof(WCHAR
);
2110 DPRINT ("NameSize %lu\n", NameSize
);
2112 if (NameSize
> MaxName
)
2119 DPRINT ("MaxName %lu\n", MaxName
);
2126 CmiGetMaxClassLength(PKEY_OBJECT KeyObject
)
2128 PHASH_TABLE_CELL HashBlock
;
2130 PKEY_CELL CurSubKeyCell
;
2135 VERIFY_KEY_OBJECT(KeyObject
);
2137 KeyCell
= KeyObject
->KeyCell
;
2138 VERIFY_KEY_CELL(KeyCell
);
2141 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2142 KeyCell
->HashTableOffset
,
2144 if (HashBlock
== NULL
)
2146 DPRINT("CmiGetBlock() failed\n");
2150 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2152 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2154 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2155 HashBlock
->Table
[i
].KeyOffset
,
2157 if (CurSubKeyCell
== NULL
)
2159 DPRINT("CmiGetBlock() failed\n");
2163 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2165 MaxClass
= CurSubKeyCell
->ClassSize
;
2171 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2172 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2174 CurKey
= KeyObject
->SubKeys
[i
];
2175 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2176 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2178 CurSubKeyCell
= CurKey
->KeyCell
;
2179 if (CurSubKeyCell
== NULL
)
2181 DPRINT("CmiGetBlock() failed\n");
2185 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2187 MaxClass
= CurSubKeyCell
->ClassSize
;
2197 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
2200 PVALUE_LIST_CELL ValueListCell
;
2201 PVALUE_CELL CurValueCell
;
2206 VERIFY_KEY_CELL(KeyCell
);
2209 ValueListCell
= CmiGetCell (RegistryHive
,
2210 KeyCell
->ValueListOffset
,
2212 if (ValueListCell
== NULL
)
2214 DPRINT("CmiGetBlock() failed\n");
2218 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2220 CurValueCell
= CmiGetCell (RegistryHive
,
2221 ValueListCell
->ValueOffset
[i
],
2223 if (CurValueCell
== NULL
)
2225 DPRINT("CmiGetBlock() failed\n");
2228 if (CurValueCell
!= NULL
)
2230 Size
= CurValueCell
->NameSize
;
2231 if (CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
2233 Size
*= sizeof(WCHAR
);
2235 if (MaxValueName
< Size
)
2237 MaxValueName
= Size
;
2242 return MaxValueName
;
2247 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
2250 PVALUE_LIST_CELL ValueListCell
;
2251 PVALUE_CELL CurValueCell
;
2255 VERIFY_KEY_CELL(KeyCell
);
2258 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2259 if (ValueListCell
== NULL
)
2264 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2266 CurValueCell
= CmiGetCell (RegistryHive
,
2267 ValueListCell
->ValueOffset
[i
],NULL
);
2268 if ((CurValueCell
!= NULL
) &&
2269 (MaxValueData
< (LONG
)(CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2271 MaxValueData
= CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2275 return MaxValueData
;
2280 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
2281 IN PKEY_CELL KeyCell
,
2282 OUT PKEY_CELL
*SubKeyCell
,
2283 OUT BLOCK_OFFSET
*BlockOffset
,
2284 IN PUNICODE_STRING KeyName
,
2285 IN ACCESS_MASK DesiredAccess
,
2286 IN ULONG Attributes
)
2288 PHASH_TABLE_CELL HashBlock
;
2289 PKEY_CELL CurSubKeyCell
;
2292 VERIFY_KEY_CELL(KeyCell
);
2294 DPRINT("Scanning for sub key %wZ\n", KeyName
);
2296 ASSERT(RegistryHive
);
2300 /* The key does not have any subkeys */
2301 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
2303 return STATUS_SUCCESS
;
2306 /* Get hash table */
2307 HashBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2308 if (HashBlock
== NULL
)
2310 DPRINT("CmiGetBlock() failed\n");
2311 return STATUS_UNSUCCESSFUL
;
2314 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
) && (i
< HashBlock
->HashTableSize
); i
++)
2316 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2318 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2319 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1 &&
2320 (HashBlock
->Table
[i
].HashValue
== 0 ||
2321 CmiCompareHashI(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2323 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2324 HashBlock
->Table
[i
].KeyOffset
,
2326 if (CurSubKeyCell
== NULL
)
2328 DPRINT("CmiGetBlock() failed\n");
2329 return STATUS_UNSUCCESSFUL
;
2332 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2334 *SubKeyCell
= CurSubKeyCell
;
2335 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2342 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2343 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2344 (HashBlock
->Table
[i
].HashValue
== 0 ||
2345 CmiCompareHash(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2347 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2348 HashBlock
->Table
[i
].KeyOffset
,
2350 if (CurSubKeyCell
== NULL
)
2352 DPRINT("CmiGetBlock() failed\n");
2353 return STATUS_UNSUCCESSFUL
;
2356 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2358 *SubKeyCell
= CurSubKeyCell
;
2359 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2366 return STATUS_SUCCESS
;
2371 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2372 PKEY_OBJECT ParentKey
,
2374 PUNICODE_STRING SubKeyName
,
2376 PUNICODE_STRING Class
,
2377 ULONG CreateOptions
)
2379 PHASH_TABLE_CELL HashBlock
;
2380 BLOCK_OFFSET NKBOffset
;
2381 PKEY_CELL NewKeyCell
;
2383 PKEY_CELL ParentKeyCell
;
2384 PDATA_CELL ClassCell
;
2391 ParentKeyCell
= ParentKey
->KeyCell
;
2393 VERIFY_KEY_CELL(ParentKeyCell
);
2395 /* Skip leading backslash */
2396 if (SubKeyName
->Buffer
[0] == L
'\\')
2398 NamePtr
= &SubKeyName
->Buffer
[1];
2399 NameSize
= SubKeyName
->Length
- sizeof(WCHAR
);
2403 NamePtr
= SubKeyName
->Buffer
;
2404 NameSize
= SubKeyName
->Length
;
2407 /* Check whether key name can be packed */
2409 for (i
= 0; i
< NameSize
/ sizeof(WCHAR
); i
++)
2411 if (NamePtr
[i
] & 0xFF00)
2418 /* Adjust name size */
2421 NameSize
= NameSize
/ sizeof(WCHAR
);
2424 DPRINT("Key %S Length %lu %s\n", NamePtr
, NameSize
, (Packable
)?"True":"False");
2426 Status
= STATUS_SUCCESS
;
2428 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2429 Status
= CmiAllocateCell (RegistryHive
,
2431 (PVOID
) &NewKeyCell
,
2433 if (NewKeyCell
== NULL
)
2435 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2439 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2440 NewKeyCell
->Flags
= 0;
2441 KeQuerySystemTime(&NewKeyCell
->LastWriteTime
);
2442 NewKeyCell
->ParentKeyOffset
= -1;
2443 NewKeyCell
->NumberOfSubKeys
= 0;
2444 NewKeyCell
->HashTableOffset
= -1;
2445 NewKeyCell
->NumberOfValues
= 0;
2446 NewKeyCell
->ValueListOffset
= -1;
2447 NewKeyCell
->SecurityKeyOffset
= -1;
2448 NewKeyCell
->ClassNameOffset
= -1;
2450 /* Pack the key name */
2451 NewKeyCell
->NameSize
= NameSize
;
2454 NewKeyCell
->Flags
|= REG_KEY_NAME_PACKED
;
2455 for (i
= 0; i
< NameSize
; i
++)
2457 NewKeyCell
->Name
[i
] = (CHAR
)(NamePtr
[i
] & 0x00FF);
2462 RtlCopyMemory(NewKeyCell
->Name
,
2467 VERIFY_KEY_CELL(NewKeyCell
);
2471 NewKeyCell
->ClassSize
= Class
->Length
;
2472 Status
= CmiAllocateCell (RegistryHive
,
2473 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
2475 &NewKeyCell
->ClassNameOffset
);
2476 RtlCopyMemory (ClassCell
->Data
,
2482 if (!NT_SUCCESS(Status
))
2487 SubKey
->KeyCell
= NewKeyCell
;
2488 SubKey
->KeyCellOffset
= NKBOffset
;
2490 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2491 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(ParentKey
->RegistryHive
)))
2496 if (ParentKeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2498 Status
= CmiAllocateHashTableCell (RegistryHive
,
2500 &ParentKeyCell
->HashTableOffset
,
2501 REG_INIT_HASH_TABLE_SIZE
);
2502 if (!NT_SUCCESS(Status
))
2509 HashBlock
= CmiGetCell (RegistryHive
,
2510 ParentKeyCell
->HashTableOffset
,
2512 if (HashBlock
== NULL
)
2514 DPRINT("CmiGetCell() failed\n");
2515 return STATUS_UNSUCCESSFUL
;
2518 if (((ParentKeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2520 PHASH_TABLE_CELL NewHashBlock
;
2521 BLOCK_OFFSET HTOffset
;
2523 /* Reallocate the hash table cell */
2524 Status
= CmiAllocateHashTableCell (RegistryHive
,
2527 HashBlock
->HashTableSize
+
2528 REG_EXTEND_HASH_TABLE_SIZE
);
2529 if (!NT_SUCCESS(Status
))
2534 RtlZeroMemory(&NewHashBlock
->Table
[0],
2535 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2536 RtlCopyMemory(&NewHashBlock
->Table
[0],
2537 &HashBlock
->Table
[0],
2538 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2539 CmiDestroyCell (RegistryHive
,
2541 ParentKeyCell
->HashTableOffset
);
2542 ParentKeyCell
->HashTableOffset
= HTOffset
;
2543 HashBlock
= NewHashBlock
;
2547 Status
= CmiAddKeyToHashTable(RegistryHive
,
2549 ParentKeyCell
->HashTableOffset
,
2552 if (NT_SUCCESS(Status
))
2554 ParentKeyCell
->NumberOfSubKeys
++;
2557 KeQuerySystemTime (&ParentKeyCell
->LastWriteTime
);
2558 CmiMarkBlockDirty (RegistryHive
, ParentKey
->KeyCellOffset
);
2565 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2566 PKEY_OBJECT ParentKey
,
2569 PHASH_TABLE_CELL HashBlock
;
2570 PVALUE_LIST_CELL ValueList
;
2571 PVALUE_CELL ValueCell
;
2572 PDATA_CELL DataCell
;
2575 DPRINT("CmiRemoveSubKey() called\n");
2577 /* Remove all values */
2578 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2580 /* Get pointer to the value list cell */
2581 ValueList
= CmiGetCell (RegistryHive
,
2582 SubKey
->KeyCell
->ValueListOffset
,
2584 if (ValueList
== NULL
)
2586 DPRINT("CmiGetCell() failed\n");
2587 return STATUS_UNSUCCESSFUL
;
2590 /* Enumerate all values */
2591 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2593 /* Get pointer to value cell */
2594 ValueCell
= CmiGetCell(RegistryHive
,
2595 ValueList
->ValueOffset
[i
],
2597 if (ValueCell
== NULL
)
2599 DPRINT("CmiGetCell() failed\n");
2600 return STATUS_UNSUCCESSFUL
;
2603 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
)
2604 && ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
2606 DataCell
= CmiGetCell (RegistryHive
,
2607 ValueCell
->DataOffset
,
2609 if (DataCell
== NULL
)
2611 DPRINT("CmiGetCell() failed\n");
2612 return STATUS_UNSUCCESSFUL
;
2615 if (DataCell
!= NULL
)
2617 /* Destroy data cell */
2618 CmiDestroyCell (RegistryHive
,
2620 ValueCell
->DataOffset
);
2624 /* Destroy value cell */
2625 CmiDestroyCell (RegistryHive
,
2627 ValueList
->ValueOffset
[i
]);
2630 /* Destroy value list cell */
2631 CmiDestroyCell (RegistryHive
,
2633 SubKey
->KeyCell
->ValueListOffset
);
2635 SubKey
->KeyCell
->NumberOfValues
= 0;
2636 SubKey
->KeyCell
->ValueListOffset
= (BLOCK_OFFSET
)-1;
2638 CmiMarkBlockDirty(RegistryHive
,
2639 SubKey
->KeyCellOffset
);
2642 /* Remove the key from the parent key's hash block */
2643 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2645 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2646 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2647 ParentKey
->KeyCell
->HashTableOffset
,
2649 if (HashBlock
== NULL
)
2651 DPRINT("CmiGetCell() failed\n");
2652 return STATUS_UNSUCCESSFUL
;
2654 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2655 if (HashBlock
!= NULL
)
2657 CmiRemoveKeyFromHashTable(ParentKey
->RegistryHive
,
2659 SubKey
->KeyCellOffset
);
2660 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2661 ParentKey
->KeyCell
->HashTableOffset
);
2665 /* Remove the key's hash block */
2666 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2668 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
);
2669 HashBlock
= CmiGetCell (RegistryHive
,
2670 SubKey
->KeyCell
->HashTableOffset
,
2672 if (HashBlock
== NULL
)
2674 DPRINT("CmiGetCell() failed\n");
2675 return STATUS_UNSUCCESSFUL
;
2677 DPRINT("SubKey HashBlock %p\n", HashBlock
);
2678 if (HashBlock
!= NULL
)
2680 CmiDestroyCell (RegistryHive
,
2682 SubKey
->KeyCell
->HashTableOffset
);
2683 SubKey
->KeyCell
->HashTableOffset
= -1;
2687 /* Decrement the number of the parent key's sub keys */
2688 if (ParentKey
!= NULL
)
2690 DPRINT("ParentKey %p\n", ParentKey
);
2691 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2693 /* Remove the parent key's hash table */
2694 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2696 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2697 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2698 ParentKey
->KeyCell
->HashTableOffset
,
2700 if (HashBlock
== NULL
)
2702 DPRINT("CmiGetCell() failed\n");
2703 return STATUS_UNSUCCESSFUL
;
2705 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2706 if (HashBlock
!= NULL
)
2708 CmiDestroyCell (ParentKey
->RegistryHive
,
2710 ParentKey
->KeyCell
->HashTableOffset
);
2711 ParentKey
->KeyCell
->HashTableOffset
= (BLOCK_OFFSET
)-1;
2715 KeQuerySystemTime(&ParentKey
->KeyCell
->LastWriteTime
);
2716 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2717 ParentKey
->KeyCellOffset
);
2720 /* Destroy key cell */
2721 CmiDestroyCell (RegistryHive
,
2723 SubKey
->KeyCellOffset
);
2724 SubKey
->KeyCell
= NULL
;
2725 SubKey
->KeyCellOffset
= (BLOCK_OFFSET
)-1;
2727 DPRINT("CmiRemoveSubKey() done\n");
2729 return STATUS_SUCCESS
;
2734 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2735 IN PKEY_CELL KeyCell
,
2736 IN PUNICODE_STRING ValueName
,
2737 OUT PVALUE_CELL
*ValueCell
,
2738 OUT BLOCK_OFFSET
*ValueCellOffset
)
2740 PVALUE_LIST_CELL ValueListCell
;
2741 PVALUE_CELL CurValueCell
;
2745 if (ValueCellOffset
!= NULL
)
2746 *ValueCellOffset
= (BLOCK_OFFSET
)-1;
2748 /* The key does not have any values */
2749 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2751 return STATUS_OBJECT_NAME_NOT_FOUND
;
2754 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2755 if (ValueListCell
== NULL
)
2757 DPRINT("ValueListCell is NULL\n");
2758 return STATUS_UNSUCCESSFUL
;
2761 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2763 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2765 CurValueCell
= CmiGetCell (RegistryHive
,
2766 ValueListCell
->ValueOffset
[i
],
2768 if (CurValueCell
== NULL
)
2770 DPRINT("CmiGetBlock() failed\n");
2771 return STATUS_UNSUCCESSFUL
;
2774 if ((CurValueCell
!= NULL
) &&
2775 CmiComparePackedNames(ValueName
,
2777 CurValueCell
->NameSize
,
2778 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2780 *ValueCell
= CurValueCell
;
2781 if (ValueCellOffset
!= NULL
)
2782 *ValueCellOffset
= ValueListCell
->ValueOffset
[i
];
2783 //DPRINT("Found value %s\n", ValueName);
2784 return STATUS_SUCCESS
;
2788 return STATUS_OBJECT_NAME_NOT_FOUND
;
2793 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2794 IN PKEY_CELL KeyCell
,
2796 OUT PVALUE_CELL
*ValueCell
)
2798 PVALUE_LIST_CELL ValueListCell
;
2799 PVALUE_CELL CurValueCell
;
2803 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2805 return STATUS_NO_MORE_ENTRIES
;
2808 if (Index
>= KeyCell
->NumberOfValues
)
2810 return STATUS_NO_MORE_ENTRIES
;
2814 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2815 if (ValueListCell
== NULL
)
2817 DPRINT("CmiGetBlock() failed\n");
2818 return STATUS_UNSUCCESSFUL
;
2821 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2824 CurValueCell
= CmiGetCell (RegistryHive
,
2825 ValueListCell
->ValueOffset
[Index
],
2827 if (CurValueCell
== NULL
)
2829 DPRINT("CmiGetBlock() failed\n");
2830 return STATUS_UNSUCCESSFUL
;
2833 *ValueCell
= CurValueCell
;
2835 return STATUS_SUCCESS
;
2840 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2841 IN PKEY_CELL KeyCell
,
2842 IN BLOCK_OFFSET KeyCellOffset
,
2843 IN PUNICODE_STRING ValueName
,
2844 OUT PVALUE_CELL
*pValueCell
,
2845 OUT BLOCK_OFFSET
*pValueCellOffset
)
2847 PVALUE_LIST_CELL NewValueListCell
;
2848 PVALUE_LIST_CELL ValueListCell
;
2849 PVALUE_CELL NewValueCell
;
2850 BLOCK_OFFSET NewValueListCellOffset
;
2851 BLOCK_OFFSET ValueListCellOffset
;
2852 BLOCK_OFFSET NewValueCellOffset
;
2856 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG
)KeyCell
->ValueListOffset
);
2858 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2859 if (ValueListCell
== NULL
)
2861 CellSize
= sizeof(VALUE_LIST_CELL
) +
2862 (3 * sizeof(BLOCK_OFFSET
));
2863 Status
= CmiAllocateCell (RegistryHive
,
2865 (PVOID
) &ValueListCell
,
2866 &ValueListCellOffset
);
2867 if (!NT_SUCCESS(Status
))
2872 KeyCell
->ValueListOffset
= ValueListCellOffset
;
2873 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2874 CmiMarkBlockDirty(RegistryHive
, ValueListCellOffset
);
2876 else if (KeyCell
->NumberOfValues
>=
2877 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
)))
2880 CellSize
= sizeof(VALUE_LIST_CELL
) +
2881 ((KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) * sizeof(BLOCK_OFFSET
));
2883 CellSize
= 2 * (ULONG
)ABS_VALUE(ValueListCell
->CellSize
);
2884 Status
= CmiAllocateCell (RegistryHive
,
2886 (PVOID
) &NewValueListCell
,
2887 &NewValueListCellOffset
);
2888 if (!NT_SUCCESS(Status
))
2893 RtlCopyMemory(&NewValueListCell
->ValueOffset
[0],
2894 &ValueListCell
->ValueOffset
[0],
2895 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2896 CmiDestroyCell (RegistryHive
, ValueListCell
, KeyCell
->ValueListOffset
);
2897 CmiMarkBlockDirty (RegistryHive
, KeyCell
->ValueListOffset
);
2899 KeyCell
->ValueListOffset
= NewValueListCellOffset
;
2900 ValueListCell
= NewValueListCell
;
2901 CmiMarkBlockDirty (RegistryHive
, KeyCellOffset
);
2902 CmiMarkBlockDirty (RegistryHive
, NewValueListCellOffset
);
2905 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2906 KeyCell
->NumberOfValues
,
2907 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2908 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
),
2909 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
));
2911 Status
= CmiAllocateValueCell(RegistryHive
,
2913 &NewValueCellOffset
,
2915 if (!NT_SUCCESS(Status
))
2920 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = NewValueCellOffset
;
2921 KeyCell
->NumberOfValues
++;
2923 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2924 CmiMarkBlockDirty(RegistryHive
, KeyCell
->ValueListOffset
);
2925 CmiMarkBlockDirty(RegistryHive
, NewValueCellOffset
);
2927 *pValueCell
= NewValueCell
;
2928 *pValueCellOffset
= NewValueCellOffset
;
2930 return STATUS_SUCCESS
;
2935 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2936 IN PKEY_CELL KeyCell
,
2937 IN BLOCK_OFFSET KeyCellOffset
,
2938 IN PUNICODE_STRING ValueName
)
2940 PVALUE_LIST_CELL ValueListCell
;
2941 PVALUE_CELL CurValueCell
;
2945 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2946 if (ValueListCell
== NULL
)
2948 DPRINT1("CmiGetBlock() failed\n");
2949 return STATUS_SUCCESS
;
2952 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2954 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2956 CurValueCell
= CmiGetCell (RegistryHive
, ValueListCell
->ValueOffset
[i
], NULL
);
2957 if (CurValueCell
== NULL
)
2959 DPRINT1("CmiGetBlock() failed\n");
2960 return STATUS_UNSUCCESSFUL
;
2963 if (CmiComparePackedNames(ValueName
,
2965 CurValueCell
->NameSize
,
2966 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2968 Status
= CmiDestroyValueCell(RegistryHive
,
2970 ValueListCell
->ValueOffset
[i
]);
2971 if (CurValueCell
== NULL
)
2973 DPRINT1("CmiDestroyValueCell() failed\n");
2977 if (i
< (KeyCell
->NumberOfValues
- 1))
2979 RtlMoveMemory(&ValueListCell
->ValueOffset
[i
],
2980 &ValueListCell
->ValueOffset
[i
+ 1],
2981 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2983 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
- 1] = 0;
2986 KeyCell
->NumberOfValues
--;
2988 if (KeyCell
->NumberOfValues
== 0)
2990 CmiDestroyCell(RegistryHive
,
2992 KeyCell
->ValueListOffset
);
2993 KeyCell
->ValueListOffset
= -1;
2997 CmiMarkBlockDirty(RegistryHive
,
2998 KeyCell
->ValueListOffset
);
3001 CmiMarkBlockDirty(RegistryHive
,
3004 return STATUS_SUCCESS
;
3008 DPRINT("Couldn't find the desired value\n");
3010 return STATUS_OBJECT_NAME_NOT_FOUND
;
3015 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive
,
3016 OUT PHASH_TABLE_CELL
*HashBlock
,
3017 OUT BLOCK_OFFSET
*HBOffset
,
3018 IN ULONG SubKeyCount
)
3020 PHASH_TABLE_CELL NewHashBlock
;
3024 Status
= STATUS_SUCCESS
;
3026 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
3027 (SubKeyCount
* sizeof(HASH_RECORD
));
3028 Status
= CmiAllocateCell (RegistryHive
,
3030 (PVOID
*) &NewHashBlock
,
3033 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
3035 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3039 ASSERT(SubKeyCount
<= 0xffff); /* should really be USHORT_MAX or similar */
3040 NewHashBlock
->Id
= REG_HASH_TABLE_CELL_ID
;
3041 NewHashBlock
->HashTableSize
= (USHORT
)SubKeyCount
;
3042 *HashBlock
= NewHashBlock
;
3050 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
3051 PHASH_TABLE_CELL HashBlock
,
3054 BLOCK_OFFSET KeyOffset
;
3057 if (HashBlock
== NULL
)
3060 if (IsPointerHive(RegistryHive
))
3062 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
3066 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
3067 KeyCell
= CmiGetCell (RegistryHive
, KeyOffset
, NULL
);
3075 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
3076 PHASH_TABLE_CELL HashCell
,
3077 BLOCK_OFFSET HashCellOffset
,
3078 PKEY_CELL NewKeyCell
,
3079 BLOCK_OFFSET NKBOffset
)
3083 for (i
= 0; i
< HashCell
->HashTableSize
; i
++)
3085 if (HashCell
->Table
[i
].KeyOffset
== 0)
3087 HashCell
->Table
[i
].KeyOffset
= NKBOffset
;
3088 HashCell
->Table
[i
].HashValue
= 0;
3089 if (NewKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3091 RtlCopyMemory(&HashCell
->Table
[i
].HashValue
,
3093 min(NewKeyCell
->NameSize
, sizeof(ULONG
)));
3095 CmiMarkBlockDirty(RegistryHive
, HashCellOffset
);
3096 return STATUS_SUCCESS
;
3100 return STATUS_UNSUCCESSFUL
;
3105 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
3106 PHASH_TABLE_CELL HashBlock
,
3107 BLOCK_OFFSET NKBOffset
)
3111 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3113 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
3115 HashBlock
->Table
[i
].KeyOffset
= 0;
3116 HashBlock
->Table
[i
].HashValue
= 0;
3117 return STATUS_SUCCESS
;
3121 return STATUS_UNSUCCESSFUL
;
3126 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
3127 PVALUE_CELL
*ValueCell
,
3128 BLOCK_OFFSET
*VBOffset
,
3129 IN PUNICODE_STRING ValueName
)
3131 PVALUE_CELL NewValueCell
;
3137 Status
= STATUS_SUCCESS
;
3139 NameSize
= CmiGetPackedNameLength(ValueName
,
3142 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
3144 Status
= CmiAllocateCell (RegistryHive
,
3145 sizeof(VALUE_CELL
) + NameSize
,
3146 (PVOID
*) &NewValueCell
,
3148 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
3150 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3154 ASSERT(NameSize
<= 0xffff); /* should really be USHORT_MAX or similar */
3155 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
3156 NewValueCell
->NameSize
= (USHORT
)NameSize
;
3159 /* Pack the value name */
3160 for (i
= 0; i
< NameSize
; i
++)
3161 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
3162 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
3166 /* Copy the value name */
3167 RtlCopyMemory(NewValueCell
->Name
,
3170 NewValueCell
->Flags
= 0;
3172 NewValueCell
->DataType
= 0;
3173 NewValueCell
->DataSize
= 0;
3174 NewValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
3175 *ValueCell
= NewValueCell
;
3183 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
3184 PVALUE_CELL ValueCell
,
3185 BLOCK_OFFSET ValueCellOffset
)
3191 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n",
3192 ValueCell
, ValueCellOffset
);
3194 VERIFY_VALUE_CELL(ValueCell
);
3196 /* Destroy the data cell */
3197 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
)
3198 && ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
3200 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, &Bin
);
3201 if (DataCell
== NULL
)
3203 DPRINT("CmiGetCell() failed\n");
3204 return STATUS_UNSUCCESSFUL
;
3207 Status
= CmiDestroyCell (RegistryHive
, DataCell
, ValueCell
->DataOffset
);
3208 if (!NT_SUCCESS(Status
))
3213 /* Update time of heap */
3214 if (!IsNoFileHive(RegistryHive
))
3215 KeQuerySystemTime(&Bin
->DateModified
);
3218 /* Destroy the value cell */
3219 Status
= CmiDestroyCell (RegistryHive
, ValueCell
, ValueCellOffset
);
3221 /* Update time of heap */
3222 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, ValueCellOffset
, &Bin
))
3224 KeQuerySystemTime(&Bin
->DateModified
);
3232 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
3235 BLOCK_OFFSET
*NewBlockOffset
)
3237 PBLOCK_LIST_ENTRY BlockList
;
3238 PCELL_HEADER tmpBlock
;
3243 DPRINT ("CmiAddBin (BlockCount %lu)\n", BlockCount
);
3245 BinSize
= BlockCount
* REG_BLOCK_SIZE
;
3246 tmpBin
= ExAllocatePool(PagedPool
, BinSize
);
3249 return STATUS_INSUFFICIENT_RESOURCES
;
3251 RtlZeroMemory (tmpBin
,
3254 tmpBin
->HeaderId
= REG_BIN_ID
;
3255 tmpBin
->BinOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
3256 RegistryHive
->FileSize
+= BinSize
;
3257 tmpBin
->BinSize
= BinSize
;
3258 tmpBin
->Unused1
= 0;
3259 KeQuerySystemTime(&tmpBin
->DateModified
);
3260 tmpBin
->Unused2
= 0;
3262 DPRINT (" BinOffset %lx BinSize %lx\n", tmpBin
->BinOffset
,tmpBin
->BinSize
);
3264 /* Allocate new block list */
3265 BlockList
= ExAllocatePool(NonPagedPool
,
3266 sizeof(BLOCK_LIST_ENTRY
) * (RegistryHive
->BlockListSize
+ BlockCount
));
3267 if (BlockList
== NULL
)
3270 return STATUS_INSUFFICIENT_RESOURCES
;
3273 if (RegistryHive
->BlockListSize
> 0)
3275 RtlCopyMemory (BlockList
,
3276 RegistryHive
->BlockList
,
3277 sizeof(BLOCK_LIST_ENTRY
) * RegistryHive
->BlockListSize
);
3278 ExFreePool(RegistryHive
->BlockList
);
3281 RegistryHive
->BlockList
= BlockList
;
3282 for (i
= 0; i
< BlockCount
; i
++)
3284 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Block
=
3285 (PVOID
)((ULONG_PTR
)tmpBin
+ (i
* REG_BLOCK_SIZE
));
3286 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Bin
= tmpBin
;
3288 RegistryHive
->BlockListSize
+= BlockCount
;
3290 /* Initialize a free block in this heap : */
3291 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
3292 tmpBlock
->CellSize
= (BinSize
- REG_HBIN_DATA_OFFSET
);
3294 /* Grow bitmap if necessary */
3295 if (IsNoFileHive(RegistryHive
) &&
3296 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
3298 PULONG BitmapBuffer
;
3301 DPRINT("Grow hive bitmap\n");
3303 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3304 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
3305 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
3306 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
3307 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
3309 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
3310 RtlCopyMemory(BitmapBuffer
,
3311 RegistryHive
->DirtyBitMap
.Buffer
,
3312 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
3313 ExFreePool(RegistryHive
->BitmapBuffer
);
3314 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
3315 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
3316 RegistryHive
->BitmapBuffer
,
3320 *NewBlock
= (PVOID
) tmpBlock
;
3323 *NewBlockOffset
= tmpBin
->BinOffset
+ REG_HBIN_DATA_OFFSET
;
3325 /* Mark new bin dirty */
3326 CmiMarkBinDirty(RegistryHive
,
3329 return STATUS_SUCCESS
;
3334 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
3337 BLOCK_OFFSET
*CellOffset
)
3339 PCELL_HEADER NewCell
;
3345 /* Round to 16 bytes multiple */
3346 CellSize
= ROUND_UP(CellSize
, 16);
3348 /* Handle volatile hives first */
3349 if (IsPointerHive(RegistryHive
))
3351 NewCell
= ExAllocatePool(NonPagedPool
, CellSize
);
3352 if (NewCell
== NULL
)
3354 return STATUS_INSUFFICIENT_RESOURCES
;
3357 RtlZeroMemory (NewCell
,
3359 NewCell
->CellSize
= -CellSize
;
3362 if (CellOffset
!= NULL
)
3363 *CellOffset
= (BLOCK_OFFSET
) NewCell
;
3367 /* first search in free blocks */
3369 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3371 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
3373 NewCell
= RegistryHive
->FreeList
[i
];
3374 if (CellOffset
!= NULL
)
3375 *CellOffset
= RegistryHive
->FreeListOffset
[i
];
3377 /* Update time of heap */
3378 Temp
= CmiGetCell (RegistryHive
,
3379 RegistryHive
->FreeListOffset
[i
],
3383 DPRINT("CmiGetBlock() failed\n");
3384 return STATUS_UNSUCCESSFUL
;
3387 KeQuerySystemTime(&Bin
->DateModified
);
3388 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
3390 if ((i
+ 1) < RegistryHive
->FreeListSize
)
3392 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
3393 &RegistryHive
->FreeList
[i
+ 1],
3394 sizeof(RegistryHive
->FreeList
[0])
3395 * (RegistryHive
->FreeListSize
- i
- 1));
3396 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
3397 &RegistryHive
->FreeListOffset
[i
+ 1],
3398 sizeof(RegistryHive
->FreeListOffset
[0])
3399 * (RegistryHive
->FreeListSize
- i
- 1));
3401 RegistryHive
->FreeListSize
--;
3406 /* Need to extend hive file : */
3407 if (NewCell
== NULL
)
3410 Status
= CmiAddBin(RegistryHive
,
3411 ((CellSize
+ sizeof(HBIN
) - 1) / REG_BLOCK_SIZE
) + 1,
3414 if (!NT_SUCCESS(Status
))
3420 /* Split the block in two parts */
3421 if (NewCell
->CellSize
> CellSize
)
3423 NewCell
= (PCELL_HEADER
) ((ULONG_PTR
) NewCell
+ CellSize
);
3424 NewCell
->CellSize
= ((PCELL_HEADER
) (*Cell
))->CellSize
- CellSize
;
3425 CmiAddFree(RegistryHive
,
3427 *CellOffset
+ CellSize
,
3429 CmiMarkBlockDirty(RegistryHive
,
3430 *CellOffset
+ CellSize
);
3432 else if (NewCell
->CellSize
< CellSize
)
3434 return STATUS_UNSUCCESSFUL
;
3437 RtlZeroMemory(*Cell
,
3439 ((PCELL_HEADER
) (*Cell
))->CellSize
= -CellSize
;
3442 return STATUS_SUCCESS
;
3447 CmiDestroyCell (PREGISTRY_HIVE RegistryHive
,
3449 BLOCK_OFFSET CellOffset
)
3454 Status
= STATUS_SUCCESS
;
3456 if (IsPointerHive(RegistryHive
))
3462 PCELL_HEADER pFree
= Cell
;
3464 if (pFree
->CellSize
< 0)
3465 pFree
->CellSize
= -pFree
->CellSize
;
3467 /* Clear block (except the block size) */
3468 RtlZeroMemory(((char*)pFree
) + sizeof(ULONG
),
3469 pFree
->CellSize
- sizeof(ULONG
));
3471 /* Add block to the list of free blocks */
3472 CmiAddFree(RegistryHive
, Cell
, CellOffset
, TRUE
);
3474 /* Update time of heap */
3475 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, CellOffset
,&pBin
))
3476 KeQuerySystemTime(&pBin
->DateModified
);
3478 CmiMarkBlockDirty(RegistryHive
, CellOffset
);
3486 CmiGetCell (PREGISTRY_HIVE RegistryHive
,
3487 BLOCK_OFFSET CellOffset
,
3497 if (CellOffset
== (BLOCK_OFFSET
)-1)
3502 if (IsPointerHive (RegistryHive
))
3504 return (PVOID
)CellOffset
;
3507 if (CellOffset
> RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
)
3509 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3510 CellOffset
, RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
);
3514 pBin
= RegistryHive
->BlockList
[CellOffset
/ REG_BLOCK_SIZE
].Bin
;
3525 return((PVOID
)((ULONG_PTR
)pBin
+ (CellOffset
- pBin
->BinOffset
)));
3530 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3531 PCELL_HEADER FreeBlock
,
3532 BLOCK_OFFSET FreeOffset
)
3534 BLOCK_OFFSET BlockOffset
;
3535 BLOCK_OFFSET BinOffset
;
3541 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3542 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3544 CmiGetCell (RegistryHive
,
3547 DPRINT("Bin %p\n", Bin
);
3551 BinOffset
= Bin
->BinOffset
;
3552 BinSize
= Bin
->BinSize
;
3553 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3555 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3557 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3558 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3559 if (BlockOffset
> BinOffset
&&
3560 BlockOffset
< BinOffset
+ BinSize
)
3562 DPRINT("Free block: Offset %lx Size %lx\n",
3563 BlockOffset
, BlockSize
);
3565 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3566 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3567 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3569 DPRINT("Merge current block with previous and next block\n");
3571 RegistryHive
->FreeList
[i
]->CellSize
+=
3572 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3574 FreeBlock
->CellSize
= 0;
3575 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3578 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3580 RtlMoveMemory(&RegistryHive
->FreeList
[i
+ 1],
3581 &RegistryHive
->FreeList
[i
+ 2],
3582 sizeof(RegistryHive
->FreeList
[0])
3583 * (RegistryHive
->FreeListSize
- i
- 2));
3584 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3585 &RegistryHive
->FreeListOffset
[i
+ 2],
3586 sizeof(RegistryHive
->FreeListOffset
[0])
3587 * (RegistryHive
->FreeListSize
- i
- 2));
3589 RegistryHive
->FreeListSize
--;
3591 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3595 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3597 DPRINT("Merge current block with previous block\n");
3599 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3600 FreeBlock
->CellSize
= 0;
3602 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3606 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3608 DPRINT("Merge current block with next block\n");
3610 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3611 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3612 RegistryHive
->FreeList
[i
] = FreeBlock
;
3613 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3615 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3627 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3628 PCELL_HEADER FreeBlock
,
3629 BLOCK_OFFSET FreeOffset
,
3630 BOOLEAN MergeFreeBlocks
)
3632 PCELL_HEADER
*tmpList
;
3633 BLOCK_OFFSET
*tmpListOffset
;
3638 ASSERT(RegistryHive
);
3641 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3642 FreeBlock
, FreeOffset
);
3644 /* Merge free blocks */
3645 if (MergeFreeBlocks
== TRUE
)
3647 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3648 return(STATUS_SUCCESS
);
3651 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3653 tmpList
= ExAllocatePool(PagedPool
,
3654 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3655 if (tmpList
== NULL
)
3656 return STATUS_INSUFFICIENT_RESOURCES
;
3658 tmpListOffset
= ExAllocatePool(PagedPool
,
3659 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3661 if (tmpListOffset
== NULL
)
3663 ExFreePool(tmpList
);
3664 return STATUS_INSUFFICIENT_RESOURCES
;
3667 if (RegistryHive
->FreeListMax
)
3669 RtlMoveMemory(tmpList
,
3670 RegistryHive
->FreeList
,
3671 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3672 RtlMoveMemory(tmpListOffset
,
3673 RegistryHive
->FreeListOffset
,
3674 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3675 ExFreePool(RegistryHive
->FreeList
);
3676 ExFreePool(RegistryHive
->FreeListOffset
);
3678 RegistryHive
->FreeList
= tmpList
;
3679 RegistryHive
->FreeListOffset
= tmpListOffset
;
3680 RegistryHive
->FreeListMax
+= 32;
3683 /* Add new offset to free list, maintaining list in ascending order */
3684 if ((RegistryHive
->FreeListSize
== 0)
3685 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3687 /* Add to end of list */
3688 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3689 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3691 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3693 /* Add to begin of list */
3694 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3695 &RegistryHive
->FreeList
[0],
3696 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3697 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3698 &RegistryHive
->FreeListOffset
[0],
3699 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3700 RegistryHive
->FreeList
[0] = FreeBlock
;
3701 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3702 RegistryHive
->FreeListSize
++;
3706 /* Search where to insert */
3708 maxInd
= RegistryHive
->FreeListSize
- 1;
3709 while ((maxInd
- minInd
) > 1)
3711 medInd
= (minInd
+ maxInd
) / 2;
3712 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3718 /* Insert before maxInd */
3719 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3720 &RegistryHive
->FreeList
[maxInd
],
3721 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3722 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3723 &RegistryHive
->FreeListOffset
[maxInd
],
3724 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3725 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3726 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3727 RegistryHive
->FreeListSize
++;
3730 return STATUS_SUCCESS
;
3735 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3736 BLOCK_OFFSET BlockOffset
)
3743 if (IsNoFileHive(RegistryHive
))
3746 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3748 BlockNumber
= (ULONG
)BlockOffset
/ REG_BLOCK_SIZE
;
3750 Cell
= CmiGetCell (RegistryHive
,
3754 CellSize
= Cell
->CellSize
;
3756 CellSize
= -CellSize
;
3758 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, REG_BLOCK_SIZE
) -
3759 ROUND_DOWN(BlockOffset
, REG_BLOCK_SIZE
)) / REG_BLOCK_SIZE
;
3761 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3764 (Cell
->CellSize
< 0) ? "used" : "free",
3767 RegistryHive
->HiveDirty
= TRUE
;
3768 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3775 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3776 BLOCK_OFFSET BinOffset
)
3782 if (IsNoFileHive(RegistryHive
))
3785 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3787 BlockNumber
= (ULONG
)BinOffset
/ REG_BLOCK_SIZE
;
3789 Bin
= RegistryHive
->BlockList
[BlockNumber
].Bin
;
3791 BlockCount
= Bin
->BinSize
/ REG_BLOCK_SIZE
;
3793 DPRINT(" BlockNumber %lu BinSize %lu BlockCount %lu\n",
3798 RegistryHive
->HiveDirty
= TRUE
;
3799 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3806 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3807 OUT PBOOLEAN Packable
)
3811 if (Packable
!= NULL
)
3814 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3816 if (Name
->Buffer
[i
] & 0xFF00)
3818 if (Packable
!= NULL
)
3820 return Name
->Length
;
3824 return (Name
->Length
/ sizeof(WCHAR
));
3829 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3830 IN PUCHAR NameBuffer
,
3831 IN USHORT NameBufferSize
,
3832 IN BOOLEAN NamePacked
)
3837 if (NamePacked
== TRUE
)
3839 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3842 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3844 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3850 if (Name
->Length
!= NameBufferSize
)
3853 UNameBuffer
= (PWCHAR
)NameBuffer
;
3855 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3857 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3867 CmiCopyPackedName(PWCHAR NameBuffer
,
3868 PUCHAR PackedNameBuffer
,
3869 ULONG PackedNameSize
)
3873 for (i
= 0; i
< PackedNameSize
; i
++)
3874 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];
3879 CmiCompareHash(PUNICODE_STRING KeyName
,
3884 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3885 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3886 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3887 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3889 return (strncmp(Buffer
, HashString
, 4) == 0);
3894 CmiCompareHashI(PUNICODE_STRING KeyName
,
3899 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3900 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3901 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3902 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3904 return (_strnicmp(Buffer
, HashString
, 4) == 0);
3909 CmiCompareKeyNames(PUNICODE_STRING KeyName
,
3915 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3917 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3919 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3922 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3924 if (KeyName
->Buffer
[i
] != (WCHAR
)KeyCell
->Name
[i
])
3930 if (KeyName
->Length
!= KeyCell
->NameSize
)
3933 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3934 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3936 if (KeyName
->Buffer
[i
] != UnicodeName
[i
])
3946 CmiCompareKeyNamesI(PUNICODE_STRING KeyName
,
3952 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3954 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3956 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3959 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3961 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3962 RtlUpcaseUnicodeChar((WCHAR
)KeyCell
->Name
[i
]))
3968 if (KeyName
->Length
!= KeyCell
->NameSize
)
3971 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3972 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3974 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3975 RtlUpcaseUnicodeChar(UnicodeName
[i
]))
3985 CmiCopyKey (PREGISTRY_HIVE DstHive
,
3986 PKEY_CELL DstKeyCell
,
3987 PREGISTRY_HIVE SrcHive
,
3988 PKEY_CELL SrcKeyCell
)
3990 PKEY_CELL NewKeyCell
;
3991 ULONG NewKeyCellSize
;
3992 BLOCK_OFFSET NewKeyCellOffset
;
3993 PHASH_TABLE_CELL NewHashTableCell
;
3994 ULONG NewHashTableSize
;
3995 BLOCK_OFFSET NewHashTableOffset
;
3999 DPRINT ("CmiCopyKey() called\n");
4001 if (DstKeyCell
== NULL
)
4003 /* Allocate and copy key cell */
4004 NewKeyCellSize
= sizeof(KEY_CELL
) + SrcKeyCell
->NameSize
;
4005 Status
= CmiAllocateCell (DstHive
,
4007 (PVOID
) &NewKeyCell
,
4009 if (!NT_SUCCESS(Status
))
4011 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4014 if (NewKeyCell
== NULL
)
4016 DPRINT1 ("Failed to allocate a key cell\n");
4017 return STATUS_INSUFFICIENT_RESOURCES
;
4020 RtlCopyMemory (NewKeyCell
,
4024 DstHive
->HiveHeader
->RootKeyOffset
= NewKeyCellOffset
;
4026 /* Copy class name */
4027 if (SrcKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4029 PDATA_CELL SrcClassNameCell
;
4030 PDATA_CELL NewClassNameCell
;
4031 BLOCK_OFFSET NewClassNameOffset
;
4033 SrcClassNameCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ClassNameOffset
, NULL
),
4035 NewKeyCell
->ClassSize
= SrcKeyCell
->ClassSize
;
4036 Status
= CmiAllocateCell (DstHive
,
4037 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
4038 (PVOID
)&NewClassNameCell
,
4039 &NewClassNameOffset
);
4040 if (!NT_SUCCESS(Status
))
4042 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4046 RtlCopyMemory (NewClassNameCell
,
4048 NewKeyCell
->ClassSize
);
4049 NewKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4054 NewKeyCell
= DstKeyCell
;
4057 /* Allocate hash table */
4058 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4060 NewHashTableSize
= ROUND_UP(SrcKeyCell
->NumberOfSubKeys
+ 1, 4) - 1;
4061 Status
= CmiAllocateHashTableCell (DstHive
,
4063 &NewHashTableOffset
,
4065 if (!NT_SUCCESS(Status
))
4067 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status
);
4070 NewKeyCell
->HashTableOffset
= NewHashTableOffset
;
4073 /* Allocate and copy value list and values */
4074 if (SrcKeyCell
->NumberOfValues
!= 0)
4076 PVALUE_LIST_CELL NewValueListCell
;
4077 PVALUE_LIST_CELL SrcValueListCell
;
4078 PVALUE_CELL NewValueCell
;
4079 PVALUE_CELL SrcValueCell
;
4080 PDATA_CELL SrcValueDataCell
;
4081 PDATA_CELL NewValueDataCell
;
4082 BLOCK_OFFSET ValueCellOffset
;
4083 BLOCK_OFFSET ValueDataCellOffset
;
4084 ULONG NewValueListCellSize
;
4085 ULONG NewValueCellSize
;
4088 NewValueListCellSize
=
4089 ROUND_UP(SrcKeyCell
->NumberOfValues
, 4) * sizeof(BLOCK_OFFSET
);
4090 Status
= CmiAllocateCell (DstHive
,
4091 NewValueListCellSize
,
4092 (PVOID
)&NewValueListCell
,
4093 &NewKeyCell
->ValueListOffset
);
4094 if (!NT_SUCCESS(Status
))
4096 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4100 RtlZeroMemory (NewValueListCell
,
4101 NewValueListCellSize
);
4104 SrcValueListCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ValueListOffset
, NULL
);
4105 for (i
= 0; i
< SrcKeyCell
->NumberOfValues
; i
++)
4107 /* Copy value cell */
4108 SrcValueCell
= CmiGetCell (SrcHive
, SrcValueListCell
->ValueOffset
[i
], NULL
);
4110 NewValueCellSize
= sizeof(VALUE_CELL
) + SrcValueCell
->NameSize
;
4111 Status
= CmiAllocateCell (DstHive
,
4113 (PVOID
*) &NewValueCell
,
4115 if (!NT_SUCCESS(Status
))
4117 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4121 NewValueListCell
->ValueOffset
[i
] = ValueCellOffset
;
4122 RtlCopyMemory (NewValueCell
,
4126 /* Copy value data cell */
4127 if (SrcValueCell
->DataSize
> (LONG
) sizeof(PVOID
))
4129 SrcValueDataCell
= CmiGetCell (SrcHive
, SrcValueCell
->DataOffset
, NULL
);
4131 Status
= CmiAllocateCell (DstHive
,
4132 sizeof(CELL_HEADER
) + SrcValueCell
->DataSize
,
4133 (PVOID
*) &NewValueDataCell
,
4134 &ValueDataCellOffset
);
4135 if (!NT_SUCCESS(Status
))
4137 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4140 RtlCopyMemory (NewValueDataCell
,
4142 SrcValueCell
->DataSize
);
4143 NewValueCell
->DataOffset
= ValueDataCellOffset
;
4149 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4151 PHASH_TABLE_CELL SrcHashTableCell
;
4152 PKEY_CELL SrcSubKeyCell
;
4153 PKEY_CELL NewSubKeyCell
;
4154 ULONG NewSubKeyCellSize
;
4155 BLOCK_OFFSET NewSubKeyCellOffset
;
4156 PHASH_RECORD SrcHashRecord
;
4158 SrcHashTableCell
= CmiGetCell (SrcHive
,
4159 SrcKeyCell
->HashTableOffset
,
4162 for (i
= 0; i
< SrcKeyCell
->NumberOfSubKeys
; i
++)
4164 SrcHashRecord
= &SrcHashTableCell
->Table
[i
];
4165 SrcSubKeyCell
= CmiGetCell (SrcHive
, SrcHashRecord
->KeyOffset
, NULL
);
4167 /* Allocate and copy key cell */
4168 NewSubKeyCellSize
= sizeof(KEY_CELL
) + SrcSubKeyCell
->NameSize
;
4169 Status
= CmiAllocateCell (DstHive
,
4171 (PVOID
)&NewSubKeyCell
,
4172 &NewSubKeyCellOffset
);
4173 if (!NT_SUCCESS(Status
))
4175 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4178 if (NewKeyCell
== NULL
)
4180 DPRINT1 ("Failed to allocate a sub key cell\n");
4181 return STATUS_INSUFFICIENT_RESOURCES
;
4184 NewHashTableCell
->Table
[i
].KeyOffset
= NewSubKeyCellOffset
;
4185 NewHashTableCell
->Table
[i
].HashValue
= SrcHashRecord
->HashValue
;
4187 RtlCopyMemory (NewSubKeyCell
,
4191 /* Copy class name */
4192 if (SrcSubKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4194 PDATA_CELL SrcClassNameCell
;
4195 PDATA_CELL NewClassNameCell
;
4196 BLOCK_OFFSET NewClassNameOffset
;
4198 SrcClassNameCell
= CmiGetCell (SrcHive
,
4199 SrcSubKeyCell
->ClassNameOffset
,
4202 NewSubKeyCell
->ClassSize
= SrcSubKeyCell
->ClassSize
;
4203 Status
= CmiAllocateCell (DstHive
,
4204 sizeof(CELL_HEADER
) + NewSubKeyCell
->ClassSize
,
4205 (PVOID
)&NewClassNameCell
,
4206 &NewClassNameOffset
);
4207 if (!NT_SUCCESS(Status
))
4209 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4213 NewSubKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4214 RtlCopyMemory (NewClassNameCell
,
4216 NewSubKeyCell
->ClassSize
);
4219 /* Copy subkey data and subkeys */
4220 Status
= CmiCopyKey (DstHive
,
4224 if (!NT_SUCCESS(Status
))
4226 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4232 return STATUS_SUCCESS
;
4237 CmiSaveTempHive (PREGISTRY_HIVE Hive
,
4240 IO_STATUS_BLOCK IoStatusBlock
;
4241 LARGE_INTEGER FileOffset
;
4246 DPRINT ("CmiSaveTempHive() called\n");
4248 Hive
->HiveHeader
->Checksum
= CmiCalcChecksum ((PULONG
)Hive
->HiveHeader
);
4250 /* Write hive block */
4251 FileOffset
.QuadPart
= (ULONGLONG
)0;
4252 Status
= ZwWriteFile (FileHandle
,
4258 sizeof(HIVE_HEADER
),
4261 if (!NT_SUCCESS(Status
))
4263 DPRINT1 ("ZwWriteFile() failed (Status %lx)\n", Status
);
4267 DPRINT ("Saving %lu blocks\n", Hive
->BlockListSize
);
4268 for (BlockIndex
= 0; BlockIndex
< Hive
->BlockListSize
; BlockIndex
++)
4270 BlockPtr
= Hive
->BlockList
[BlockIndex
].Block
;
4271 DPRINT ("BlockPtr %p\n", BlockPtr
);
4273 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
4274 DPRINT ("File offset %I64x\n", FileOffset
.QuadPart
);
4276 /* Write hive block */
4277 Status
= ZwWriteFile (FileHandle
,
4286 if (!NT_SUCCESS(Status
))
4288 DPRINT1 ("ZwWriteFile() failed (Status %lx)\n", Status
);
4293 Status
= ZwFlushBuffersFile (FileHandle
,
4295 if (!NT_SUCCESS(Status
))
4297 DPRINT1 ("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
4300 DPRINT ("CmiSaveTempHive() done\n");