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 ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
25 BOOLEAN CmiDoVerify
= FALSE
;
28 CmiCalcChecksum(PULONG Buffer
);
30 /* FUNCTIONS ****************************************************************/
33 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header
)
36 RtlZeroMemory(Header
, sizeof(HIVE_HEADER
));
37 Header
->BlockId
= REG_HIVE_ID
;
38 Header
->UpdateCounter1
= 0;
39 Header
->UpdateCounter2
= 0;
40 Header
->DateModified
.u
.LowPart
= 0;
41 Header
->DateModified
.u
.HighPart
= 0;
42 Header
->MajorVersion
= 1;
43 Header
->MinorVersion
= 3;
47 Header
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
48 Header
->BlockSize
= REG_BLOCK_SIZE
;
54 CmiCreateDefaultBinHeader(PHBIN BinHeader
)
57 RtlZeroMemory(BinHeader
, sizeof(HBIN
));
58 BinHeader
->HeaderId
= REG_BIN_ID
;
59 BinHeader
->DateModified
.u
.LowPart
= 0;
60 BinHeader
->DateModified
.u
.HighPart
= 0;
61 BinHeader
->BinSize
= REG_BLOCK_SIZE
;
66 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
)
69 RtlZeroMemory(RootKeyCell
, sizeof(KEY_CELL
));
70 RootKeyCell
->CellSize
= -sizeof(KEY_CELL
);
71 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
72 RootKeyCell
->Flags
= REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
;
73 KeQuerySystemTime(&RootKeyCell
->LastWriteTime
);
74 RootKeyCell
->ParentKeyOffset
= 0;
75 RootKeyCell
->NumberOfSubKeys
= 0;
76 RootKeyCell
->HashTableOffset
= -1;
77 RootKeyCell
->NumberOfValues
= 0;
78 RootKeyCell
->ValueListOffset
= -1;
79 RootKeyCell
->SecurityKeyOffset
= 0;
80 RootKeyCell
->ClassNameOffset
= -1;
81 RootKeyCell
->NameSize
= 0;
82 RootKeyCell
->ClassSize
= 0;
87 CmiVerifyBinHeader(PHBIN BinHeader
)
94 if (BinHeader
->HeaderId
!= REG_BIN_ID
)
96 DbgPrint("Bin header ID is %.08x (should be %.08x)\n",
97 BinHeader
->HeaderId
, REG_BIN_ID
);
98 ASSERT(BinHeader
->HeaderId
== REG_BIN_ID
);
101 //BinHeader->DateModified.dwLowDateTime
103 //BinHeader->DateModified.dwHighDateTime
106 if (BinHeader
->BinSize
!= REG_BLOCK_SIZE
)
108 DbgPrint("BinSize is %.08x (should be a multiple of %.08x)\n",
109 BinHeader
->BinSize
, REG_BLOCK_SIZE
);
110 ASSERT(BinHeader
->BinSize
% REG_BLOCK_SIZE
== 0);
118 CmiVerifyKeyCell(PKEY_CELL KeyCell
)
125 if (KeyCell
->CellSize
== 0)
127 DbgPrint("CellSize is %d (must not be 0)\n",
129 ASSERT(KeyCell
->CellSize
!= 0);
132 if (KeyCell
->Id
!= REG_KEY_CELL_ID
)
134 DbgPrint("Id is %.08x (should be %.08x)\n",
135 KeyCell
->Id
, REG_KEY_CELL_ID
);
136 ASSERT(KeyCell
->Id
== REG_KEY_CELL_ID
);
141 //KeyCell->LastWriteTime;
143 if (KeyCell
->ParentKeyOffset
< 0)
145 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
146 KeyCell
->ParentKeyOffset
);
147 ASSERT(KeyCell
->ParentKeyOffset
>= 0);
150 if (KeyCell
->NumberOfSubKeys
< 0)
152 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
153 KeyCell
->NumberOfSubKeys
);
154 ASSERT(KeyCell
->NumberOfSubKeys
>= 0);
157 //KeyCell->HashTableOffset;
159 if (KeyCell
->NumberOfValues
< 0)
161 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
162 KeyCell
->NumberOfValues
);
163 ASSERT(KeyCell
->NumberOfValues
>= 0);
166 //KeyCell->ValuesOffset = -1;
168 if (KeyCell
->SecurityKeyOffset
< 0)
170 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
171 KeyCell
->SecurityKeyOffset
);
172 ASSERT(KeyCell
->SecurityKeyOffset
>= 0);
175 //KeyCell->ClassNameOffset = -1;
186 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell
)
191 CmiVerifyKeyCell(RootKeyCell
);
193 if (!(RootKeyCell
->Flags
& REG_KEY_ROOT_CELL
))
195 DbgPrint("Flags is %.08x (should be %.08x)\n",
196 RootKeyCell
->Flags
, REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
);
197 ASSERT(!(RootKeyCell
->Flags
& (REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
)));
205 CmiVerifyValueCell(PVALUE_CELL ValueCell
)
212 if (ValueCell
->CellSize
== 0)
214 DbgPrint("CellSize is %d (must not be 0)\n",
215 ValueCell
->CellSize
);
216 ASSERT(ValueCell
->CellSize
!= 0);
219 if (ValueCell
->Id
!= REG_VALUE_CELL_ID
)
221 DbgPrint("Id is %.08x (should be %.08x)\n",
222 ValueCell
->Id
, REG_VALUE_CELL_ID
);
223 ASSERT(ValueCell
->Id
== REG_VALUE_CELL_ID
);
226 //ValueCell->NameSize;
227 //ValueCell->LONG DataSize;
228 //ValueCell->DataOffset;
229 //ValueCell->ULONG DataType;
230 //ValueCell->USHORT Flags;
231 //ValueCell->USHORT Unused1;
232 //ValueCell->UCHAR Name[0];
238 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell
)
243 if (ValueListCell
->CellSize
== 0)
245 DbgPrint("CellSize is %d (must not be 0)\n",
246 ValueListCell
->CellSize
);
247 ASSERT(ValueListCell
->CellSize
!= 0);
255 CmiVerifyKeyObject(PKEY_OBJECT KeyObject
)
260 if (KeyObject
->RegistryHive
== NULL
)
262 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
263 KeyObject
->RegistryHive
);
264 ASSERT(KeyObject
->RegistryHive
!= NULL
);
267 if (KeyObject
->KeyCell
== NULL
)
269 DbgPrint("KeyCell is NULL (must not be NULL)\n",
271 ASSERT(KeyObject
->KeyCell
!= NULL
);
274 if (KeyObject
->ParentKey
== NULL
)
276 DbgPrint("ParentKey is NULL (must not be NULL)\n",
277 KeyObject
->ParentKey
);
278 ASSERT(KeyObject
->ParentKey
!= NULL
);
286 CmiVerifyHiveHeader(PHIVE_HEADER Header
)
291 if (Header
->BlockId
!= REG_HIVE_ID
)
293 DbgPrint("BlockId is %.08x (must be %.08x)\n",
296 ASSERT(Header
->BlockId
== REG_HIVE_ID
);
299 if (Header
->MajorVersion
!= 1)
301 DbgPrint("MajorVersion is %.08x (must be 1)\n",
302 Header
->MajorVersion
);
303 ASSERT(Header
->MajorVersion
== 1);
306 if (Header
->MinorVersion
!= 3)
308 DbgPrint("MinorVersion is %.08x (must be 3)\n",
309 Header
->MajorVersion
);
310 ASSERT(Header
->MajorVersion
== 3);
313 if (Header
->Type
!= 0)
315 DbgPrint("Type is %.08x (must be 0)\n",
317 ASSERT(Header
->Type
== 0);
320 if (Header
->Format
!= 1)
322 DbgPrint("Format is %.08x (must be 1)\n",
324 ASSERT(Header
->Format
== 1);
327 if (Header
->Unused7
!= 1)
329 DbgPrint("Unused7 is %.08x (must be 1)\n",
331 ASSERT(Header
->Unused7
== 1);
339 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive
)
344 CmiVerifyHiveHeader(RegistryHive
->HiveHeader
);
351 CmiCreateNewRegFile(HANDLE FileHandle
)
353 IO_STATUS_BLOCK IoStatusBlock
;
354 PCELL_HEADER FreeCell
;
355 PHIVE_HEADER HiveHeader
;
356 PKEY_CELL RootKeyCell
;
361 Buffer
= (PCHAR
) ExAllocatePool(NonPagedPool
, 2 * REG_BLOCK_SIZE
);
363 return STATUS_INSUFFICIENT_RESOURCES
;
365 RtlZeroMemory (Buffer
,
368 HiveHeader
= (PHIVE_HEADER
)Buffer
;
369 BinHeader
= (PHBIN
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
);
370 RootKeyCell
= (PKEY_CELL
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
);
371 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
373 CmiCreateDefaultHiveHeader(HiveHeader
);
374 CmiCreateDefaultBinHeader(BinHeader
);
375 CmiCreateDefaultRootKeyCell(RootKeyCell
);
378 BinHeader
->BinOffset
= 0;
380 /* Offset to root key block */
381 HiveHeader
->RootKeyOffset
= REG_HBIN_DATA_OFFSET
;
383 /* The rest of the block is free */
384 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
386 Status
= ZwWriteFile(FileHandle
,
398 if (!NT_SUCCESS(Status
))
403 Status
= ZwFlushBuffersFile(FileHandle
,
412 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive
)
414 OBJECT_ATTRIBUTES ObjectAttributes
;
415 FILE_STANDARD_INFORMATION fsi
;
416 IO_STATUS_BLOCK IoStatusBlock
;
417 HANDLE HiveHandle
= INVALID_HANDLE_VALUE
;
418 HANDLE LogHandle
= INVALID_HANDLE_VALUE
;
419 PHIVE_HEADER HiveHeader
= NULL
;
420 PHIVE_HEADER LogHeader
= NULL
;
421 LARGE_INTEGER FileOffset
;
425 RTL_BITMAP BlockBitMap
;
428 DPRINT("CmiCheckAndFixHive() called\n");
430 /* Try to open the hive file */
431 InitializeObjectAttributes(&ObjectAttributes
,
432 &RegistryHive
->HiveFileName
,
433 OBJ_CASE_INSENSITIVE
,
437 Status
= ZwCreateFile(&HiveHandle
,
438 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
442 FILE_ATTRIBUTE_NORMAL
,
445 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
448 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
450 return(STATUS_SUCCESS
);
452 if (!NT_SUCCESS(Status
))
454 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
458 /* Try to open the log file */
459 InitializeObjectAttributes(&ObjectAttributes
,
460 &RegistryHive
->LogFileName
,
461 OBJ_CASE_INSENSITIVE
,
465 Status
= ZwCreateFile(&LogHandle
,
466 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
470 FILE_ATTRIBUTE_NORMAL
,
473 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
476 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
478 LogHandle
= INVALID_HANDLE_VALUE
;
480 else if (!NT_SUCCESS(Status
))
482 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
487 /* Allocate hive header */
488 HiveHeader
= ExAllocatePool(PagedPool
,
489 sizeof(HIVE_HEADER
));
490 if (HiveHeader
== NULL
)
492 DPRINT("ExAllocatePool() failed\n");
493 Status
= STATUS_INSUFFICIENT_RESOURCES
;
497 /* Read hive base block */
498 FileOffset
.QuadPart
= 0ULL;
499 Status
= ZwReadFile(HiveHandle
,
508 if (!NT_SUCCESS(Status
))
510 DPRINT("ZwReadFile() failed (Status %lx)\n", Status
);
514 if (LogHandle
== INVALID_HANDLE_VALUE
)
516 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
517 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
519 /* There is no way to fix the hive without log file - BSOD! */
520 DPRINT("Hive header inconsistent and no log file available!\n");
521 KEBUGCHECK(CONFIG_LIST_FAILED
);
524 Status
= STATUS_SUCCESS
;
529 /* Allocate hive header */
530 LogHeader
= ExAllocatePool(PagedPool
,
531 sizeof(HIVE_HEADER
));
532 if (LogHeader
== NULL
)
534 DPRINT("ExAllocatePool() failed\n");
535 Status
= STATUS_INSUFFICIENT_RESOURCES
;
539 /* Read log file header */
540 FileOffset
.QuadPart
= 0ULL;
541 Status
= ZwReadFile(LogHandle
,
550 if (!NT_SUCCESS(Status
))
552 DPRINT("ZwReadFile() failed (Status %lx)\n", Status
);
556 /* Check log file header integrity */
557 if (LogHeader
->Checksum
!= CmiCalcChecksum((PULONG
)LogHeader
) ||
558 LogHeader
->UpdateCounter1
!= LogHeader
->UpdateCounter2
)
560 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
561 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
563 DPRINT("Hive file and log file are inconsistent!\n");
564 KEBUGCHECK(CONFIG_LIST_FAILED
);
567 /* Log file damaged but hive is okay */
568 Status
= STATUS_SUCCESS
;
572 if (HiveHeader
->UpdateCounter1
== HiveHeader
->UpdateCounter2
&&
573 HiveHeader
->UpdateCounter1
== LogHeader
->UpdateCounter1
)
575 /* Hive and log file are up-to-date */
576 Status
= STATUS_SUCCESS
;
581 * Hive needs an update!
585 Status
= ZwQueryInformationFile(LogHandle
,
589 FileStandardInformation
);
590 if (!NT_SUCCESS(Status
))
592 DPRINT("ZwQueryInformationFile() failed (Status %lx)\n", Status
);
595 FileSize
= fsi
.EndOfFile
.u
.LowPart
;
597 /* Calculate bitmap and block size */
598 BitmapSize
= ROUND_UP((FileSize
/ REG_BLOCK_SIZE
) - 1, sizeof(ULONG
) * 8) / 8;
599 BufferSize
= sizeof(HIVE_HEADER
) +
602 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
604 /* Reallocate log header block */
605 ExFreePool(LogHeader
);
606 LogHeader
= ExAllocatePool(PagedPool
,
608 if (LogHeader
== NULL
)
610 DPRINT("ExAllocatePool() failed\n");
611 Status
= STATUS_INSUFFICIENT_RESOURCES
;
615 /* Read log file header */
616 FileOffset
.QuadPart
= 0ULL;
617 Status
= ZwReadFile(LogHandle
,
626 if (!NT_SUCCESS(Status
))
628 DPRINT("ZwReadFile() failed (Status %lx)\n", Status
);
632 /* Initialize bitmap */
633 RtlInitializeBitMap(&BlockBitMap
,
634 (PVOID
)((ULONG_PTR
)LogHeader
+ REG_BLOCK_SIZE
+ sizeof(ULONG
)),
637 /* FIXME: Update dirty blocks */
640 /* FIXME: Update hive header */
643 Status
= STATUS_SUCCESS
;
647 /* Clean up the mess */
649 if (HiveHeader
!= NULL
)
650 ExFreePool(HiveHeader
);
652 if (LogHeader
!= NULL
)
653 ExFreePool(LogHeader
);
655 if (LogHandle
!= INVALID_HANDLE_VALUE
)
666 CmiImportHiveBins(PREGISTRY_HIVE Hive
,
669 BLOCK_OFFSET BlockOffset
;
676 while (BlockIndex
< Hive
->BlockListSize
)
678 Bin
= (PHBIN
)((ULONG_PTR
)ChunkPtr
+ BlockOffset
);
680 if (Bin
->HeaderId
!= REG_BIN_ID
)
682 DPRINT1 ("Bad bin header id %x, offset %x\n", Bin
->HeaderId
, BlockOffset
);
683 return STATUS_REGISTRY_CORRUPT
;
686 ASSERTMSG("Bin size must be multiple of 4K\n",
687 (Bin
->BinSize
% REG_BLOCK_SIZE
) == 0);
689 /* Allocate the hive block */
690 Hive
->BlockList
[BlockIndex
].Bin
= ExAllocatePool (PagedPool
,
692 if (Hive
->BlockList
[BlockIndex
].Bin
== NULL
)
694 DPRINT1 ("ExAllocatePool() failed\n");
695 return STATUS_INSUFFICIENT_RESOURCES
;
697 Hive
->BlockList
[BlockIndex
].Block
= (PVOID
)Hive
->BlockList
[BlockIndex
].Bin
;
700 RtlCopyMemory (Hive
->BlockList
[BlockIndex
].Bin
,
704 if (Bin
->BinSize
> REG_BLOCK_SIZE
)
706 for (j
= 1; j
< Bin
->BinSize
/ REG_BLOCK_SIZE
; j
++)
708 Hive
->BlockList
[BlockIndex
+ j
].Bin
= Hive
->BlockList
[BlockIndex
].Bin
;
709 Hive
->BlockList
[BlockIndex
+ j
].Block
=
710 (PVOID
)((ULONG_PTR
)Hive
->BlockList
[BlockIndex
].Bin
+ (j
* REG_BLOCK_SIZE
));
714 BlockIndex
+= Bin
->BinSize
/ REG_BLOCK_SIZE
;
715 BlockOffset
+= Bin
->BinSize
;
718 return STATUS_SUCCESS
;
723 CmiFreeHiveBins (PREGISTRY_HIVE Hive
)
729 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
731 if (Hive
->BlockList
[i
].Bin
== NULL
)
734 if (Hive
->BlockList
[i
].Bin
!= Bin
)
736 Bin
= Hive
->BlockList
[i
].Bin
;
737 ExFreePool (Hive
->BlockList
[i
].Bin
);
739 Hive
->BlockList
[i
].Bin
= NULL
;
740 Hive
->BlockList
[i
].Block
= NULL
;
746 CmiCreateHiveFreeCellList(PREGISTRY_HIVE Hive
)
748 BLOCK_OFFSET BlockOffset
;
749 PCELL_HEADER FreeBlock
;
755 /* Initialize the free cell list */
756 Hive
->FreeListSize
= 0;
757 Hive
->FreeListMax
= 0;
758 Hive
->FreeList
= NULL
;
759 Hive
->FreeListOffset
= NULL
;
763 while (BlockIndex
< Hive
->BlockListSize
)
765 Bin
= Hive
->BlockList
[BlockIndex
].Bin
;
767 /* Search free blocks and add to list */
768 FreeOffset
= REG_HBIN_DATA_OFFSET
;
769 while (FreeOffset
< Bin
->BinSize
)
771 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) Bin
+ FreeOffset
);
772 if (FreeBlock
->CellSize
> 0)
774 Status
= CmiAddFree(Hive
,
776 Bin
->BinOffset
+ FreeOffset
,
779 if (!NT_SUCCESS(Status
))
784 FreeOffset
+= FreeBlock
->CellSize
;
788 FreeOffset
-= FreeBlock
->CellSize
;
792 BlockIndex
+= Bin
->BinSize
/ REG_BLOCK_SIZE
;
793 BlockOffset
+= Bin
->BinSize
;
796 return STATUS_SUCCESS
;
801 CmiFreeHiveFreeCellList(PREGISTRY_HIVE Hive
)
803 ExFreePool (Hive
->FreeList
);
804 ExFreePool (Hive
->FreeListOffset
);
806 Hive
->FreeListSize
= 0;
807 Hive
->FreeListMax
= 0;
808 Hive
->FreeList
= NULL
;
809 Hive
->FreeListOffset
= NULL
;
814 CmiCreateHiveBitmap(PREGISTRY_HIVE Hive
)
818 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
819 BitmapSize
= ROUND_UP(Hive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
820 DPRINT("Hive->BlockListSize: %lu\n", Hive
->BlockListSize
);
821 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
823 /* Allocate bitmap */
824 Hive
->BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
826 if (Hive
->BitmapBuffer
== NULL
)
828 return STATUS_INSUFFICIENT_RESOURCES
;
831 RtlInitializeBitMap(&Hive
->DirtyBitMap
,
835 /* Initialize bitmap */
836 RtlClearAllBits(&Hive
->DirtyBitMap
);
837 Hive
->HiveDirty
= FALSE
;
839 return STATUS_SUCCESS
;
844 CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive
,
847 OBJECT_ATTRIBUTES ObjectAttributes
;
848 ULONG CreateDisposition
;
849 IO_STATUS_BLOCK IoSB
;
851 PSECTION_OBJECT SectionObject
;
856 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) called\n",
857 RegistryHive
, Filename
);
859 /* Duplicate Filename */
860 Status
= RtlCreateUnicodeString(&RegistryHive
->HiveFileName
,
862 if (!NT_SUCCESS(Status
))
864 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status
);
868 /* Create log file name */
869 RegistryHive
->LogFileName
.Length
= (wcslen(Filename
) + 4) * sizeof(WCHAR
);
870 RegistryHive
->LogFileName
.MaximumLength
= RegistryHive
->LogFileName
.Length
+ sizeof(WCHAR
);
871 RegistryHive
->LogFileName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
872 RegistryHive
->LogFileName
.MaximumLength
,
873 TAG('U', 'S', 'T', 'R'));
874 if (RegistryHive
->LogFileName
.Buffer
== NULL
)
876 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
877 DPRINT("ExAllocatePool() failed\n");
878 return(STATUS_INSUFFICIENT_RESOURCES
);
880 wcscpy(RegistryHive
->LogFileName
.Buffer
,
882 wcscat(RegistryHive
->LogFileName
.Buffer
,
886 /* Check and eventually fix a hive */
887 Status
= CmiCheckAndFixHive(RegistryHive
);
888 if (!NT_SUCCESS(Status
))
890 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
891 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
892 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status
);
897 InitializeObjectAttributes(&ObjectAttributes
,
898 &RegistryHive
->HiveFileName
,
899 OBJ_CASE_INSENSITIVE
,
903 CreateDisposition
= FILE_OPEN_IF
;
904 Status
= ZwCreateFile(&FileHandle
,
909 FILE_ATTRIBUTE_NORMAL
,
912 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
915 if (!NT_SUCCESS(Status
))
917 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
918 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
919 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
923 if (IoSB
.Information
!= FILE_OPENED
)
925 Status
= CmiCreateNewRegFile(FileHandle
);
926 if (!NT_SUCCESS(Status
))
928 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status
);
930 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
931 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
936 /* Create the hive section */
937 Status
= MmCreateSection(&SectionObject
,
945 if (!NT_SUCCESS(Status
))
947 DPRINT1("MmCreateSection() failed (Status %lx)\n", Status
);
948 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
949 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
953 /* Map the hive file */
956 Status
= MmMapViewOfSection(SectionObject
,
957 PsGetCurrentProcess(),
966 if (!NT_SUCCESS(Status
))
968 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status
);
969 ObDereferenceObject(SectionObject
);
970 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
971 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
975 DPRINT("ViewBase %p ViewSize %lx\n", ViewBase
, ViewSize
);
977 /* Copy hive header and initalize hive */
978 RtlCopyMemory (RegistryHive
->HiveHeader
,
980 sizeof(HIVE_HEADER
));
981 RegistryHive
->FileSize
= ViewSize
;
982 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ REG_BLOCK_SIZE
) - 1;
983 RegistryHive
->UpdateCounter
= RegistryHive
->HiveHeader
->UpdateCounter1
;
985 /* Allocate hive block list */
986 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
987 RegistryHive
->BlockListSize
* sizeof(BLOCK_LIST_ENTRY
));
988 if (RegistryHive
->BlockList
== NULL
)
990 DPRINT1("Failed to allocate the hive block list\n");
991 MmUnmapViewOfSection(PsGetCurrentProcess(),
993 ObDereferenceObject(SectionObject
);
994 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
995 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
997 return STATUS_INSUFFICIENT_RESOURCES
;
999 RtlZeroMemory (RegistryHive
->BlockList
,
1000 RegistryHive
->BlockListSize
* sizeof(BLOCK_LIST_ENTRY
));
1002 /* Import the hive bins */
1003 Status
= CmiImportHiveBins (RegistryHive
,
1004 ViewBase
+ REG_BLOCK_SIZE
);
1005 if (!NT_SUCCESS(Status
))
1007 ExFreePool(RegistryHive
->BlockList
);
1008 MmUnmapViewOfSection(PsGetCurrentProcess(),
1010 ObDereferenceObject(SectionObject
);
1011 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1012 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1013 ZwClose(FileHandle
);
1017 /* Unmap and dereference the hive section */
1018 MmUnmapViewOfSection(PsGetCurrentProcess(),
1020 ObDereferenceObject(SectionObject
);
1022 /* Close the hive file */
1023 ZwClose(FileHandle
);
1025 /* Initialize the free cell list */
1026 Status
= CmiCreateHiveFreeCellList (RegistryHive
);
1027 if (!NT_SUCCESS(Status
))
1029 CmiFreeHiveBins(RegistryHive
);
1030 ExFreePool(RegistryHive
->BlockList
);
1031 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1032 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1036 /* Create the block bitmap */
1037 Status
= CmiCreateHiveBitmap (RegistryHive
);
1038 if (!NT_SUCCESS(Status
))
1040 CmiFreeHiveFreeCellList(RegistryHive
);
1041 CmiFreeHiveBins(RegistryHive
);
1042 ExFreePool(RegistryHive
->BlockList
);
1043 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1044 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1048 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n",
1049 RegistryHive
, Filename
);
1051 return STATUS_SUCCESS
;
1056 CmiCreateVolatileHive(PREGISTRY_HIVE
*RegistryHive
)
1058 PKEY_CELL RootKeyCell
;
1059 PREGISTRY_HIVE Hive
;
1061 *RegistryHive
= NULL
;
1063 Hive
= ExAllocatePool (NonPagedPool
,
1064 sizeof(REGISTRY_HIVE
));
1066 return STATUS_INSUFFICIENT_RESOURCES
;
1068 RtlZeroMemory (Hive
,
1069 sizeof(REGISTRY_HIVE
));
1071 DPRINT("Hive 0x%p\n", Hive
);
1073 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1074 sizeof(HIVE_HEADER
));
1075 if (Hive
->HiveHeader
== NULL
)
1078 return STATUS_INSUFFICIENT_RESOURCES
;
1080 RtlZeroMemory (Hive
->HiveHeader
,
1081 sizeof(HIVE_HEADER
));
1083 Hive
->Flags
= (HIVE_NO_FILE
| HIVE_POINTER
);
1085 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1087 RootKeyCell
= (PKEY_CELL
)ExAllocatePool (NonPagedPool
,
1089 if (RootKeyCell
== NULL
)
1091 ExFreePool(Hive
->HiveHeader
);
1093 return STATUS_INSUFFICIENT_RESOURCES
;
1096 CmiCreateDefaultRootKeyCell (RootKeyCell
);
1097 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)RootKeyCell
;
1099 /* Acquire hive list lock exclusively */
1100 KeEnterCriticalRegion();
1101 ExAcquireResourceExclusiveLite (&CmiRegistryLock
, TRUE
);
1103 /* Add the new hive to the hive list */
1104 InsertTailList (&CmiHiveListHead
,
1107 /* Release hive list lock */
1108 ExReleaseResourceLite (&CmiRegistryLock
);
1109 KeLeaveCriticalRegion();
1111 VERIFY_REGISTRY_HIVE (Hive
);
1113 *RegistryHive
= Hive
;
1115 return STATUS_SUCCESS
;
1120 CmiCreateTempHive(PREGISTRY_HIVE
*RegistryHive
)
1123 PCELL_HEADER FreeCell
;
1124 PREGISTRY_HIVE Hive
;
1127 DPRINT ("CmiCreateTempHive() called\n");
1129 *RegistryHive
= NULL
;
1131 Hive
= ExAllocatePool (NonPagedPool
,
1132 sizeof(REGISTRY_HIVE
));
1135 DPRINT1 ("Failed to allocate registry hive block\n");
1136 return STATUS_INSUFFICIENT_RESOURCES
;
1138 RtlZeroMemory (Hive
,
1139 sizeof(REGISTRY_HIVE
));
1141 DPRINT ("Hive 0x%p\n", Hive
);
1143 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1145 if (Hive
->HiveHeader
== NULL
)
1147 DPRINT1 ("Failed to allocate hive header block\n");
1149 return STATUS_INSUFFICIENT_RESOURCES
;
1151 RtlZeroMemory (Hive
->HiveHeader
,
1154 DPRINT ("HiveHeader 0x%p\n", Hive
->HiveHeader
);
1156 Hive
->Flags
= HIVE_NO_FILE
;
1158 RtlInitUnicodeString (&Hive
->HiveFileName
,
1160 RtlInitUnicodeString (&Hive
->LogFileName
,
1163 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1165 /* Allocate hive block list */
1166 Hive
->BlockList
= ExAllocatePool (NonPagedPool
,
1167 sizeof(PBLOCK_LIST_ENTRY
));
1168 if (Hive
->BlockList
== NULL
)
1170 DPRINT1 ("Failed to allocate hive block list\n");
1171 ExFreePool(Hive
->HiveHeader
);
1173 return STATUS_INSUFFICIENT_RESOURCES
;
1176 /* Allocate first Bin */
1177 Hive
->BlockList
[0].Bin
= ExAllocatePool (NonPagedPool
,
1179 if (Hive
->BlockList
[0].Bin
== NULL
)
1181 DPRINT1 ("Failed to allocate first bin\n");
1182 ExFreePool(Hive
->BlockList
);
1183 ExFreePool(Hive
->HiveHeader
);
1185 return STATUS_INSUFFICIENT_RESOURCES
;
1187 Hive
->BlockList
[0].Block
= (PVOID
)Hive
->BlockList
[0].Bin
;
1189 Hive
->FileSize
= 2* REG_BLOCK_SIZE
;
1190 Hive
->BlockListSize
= 1;
1191 Hive
->UpdateCounter
= Hive
->HiveHeader
->UpdateCounter1
;
1194 BinHeader
= Hive
->BlockList
[0].Bin
;
1195 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)BinHeader
+ REG_HBIN_DATA_OFFSET
);
1197 CmiCreateDefaultBinHeader (BinHeader
);
1200 BinHeader
->BinOffset
= 0;
1202 /* Offset to root key block */
1203 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
1205 /* The rest of the block is free */
1206 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
1208 /* Create the free cell list */
1209 Status
= CmiCreateHiveFreeCellList (Hive
);
1210 if (Hive
->BlockList
[0].Bin
== NULL
)
1212 DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status
);
1213 ExFreePool(Hive
->BlockList
[0].Bin
);
1214 ExFreePool(Hive
->BlockList
);
1215 ExFreePool(Hive
->HiveHeader
);
1220 /* Acquire hive list lock exclusively */
1221 KeEnterCriticalRegion();
1222 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1224 /* Add the new hive to the hive list */
1225 InsertTailList (&CmiHiveListHead
,
1228 /* Release hive list lock */
1229 ExReleaseResourceLite(&CmiRegistryLock
);
1230 KeLeaveCriticalRegion();
1232 VERIFY_REGISTRY_HIVE (Hive
);
1234 *RegistryHive
= Hive
;
1236 return STATUS_SUCCESS
;
1241 CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1242 IN PUNICODE_STRING FileName
,
1245 PREGISTRY_HIVE Hive
;
1248 DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName
);
1250 if (Flags
& ~REG_NO_LAZY_FLUSH
)
1251 return STATUS_INVALID_PARAMETER
;
1253 Hive
= ExAllocatePool (NonPagedPool
,
1254 sizeof(REGISTRY_HIVE
));
1257 DPRINT1 ("Failed to allocate hive header.\n");
1258 return STATUS_INSUFFICIENT_RESOURCES
;
1260 RtlZeroMemory (Hive
,
1261 sizeof(REGISTRY_HIVE
));
1263 DPRINT ("Hive 0x%p\n", Hive
);
1264 Hive
->Flags
= (Flags
& REG_NO_LAZY_FLUSH
) ? HIVE_NO_SYNCH
: 0;
1266 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool(NonPagedPool
,
1267 sizeof(HIVE_HEADER
));
1268 if (Hive
->HiveHeader
== NULL
)
1270 DPRINT1 ("Failed to allocate hive header.\n");
1272 return STATUS_INSUFFICIENT_RESOURCES
;
1275 RtlZeroMemory (Hive
->HiveHeader
,
1276 sizeof(HIVE_HEADER
));
1278 Status
= CmiInitNonVolatileRegistryHive (Hive
,
1280 if (!NT_SUCCESS (Status
))
1282 DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status
);
1283 ExFreePool (Hive
->HiveHeader
);
1288 /* Add the new hive to the hive list */
1289 InsertTailList (&CmiHiveListHead
,
1292 VERIFY_REGISTRY_HIVE(Hive
);
1294 Status
= CmiConnectHive (KeyObjectAttributes
,
1296 if (!NT_SUCCESS(Status
))
1298 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status
);
1299 // CmiRemoveRegistryHive (Hive);
1302 DPRINT ("CmiLoadHive() done\n");
1309 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
1311 if (RegistryHive
->Flags
& HIVE_POINTER
)
1312 return STATUS_UNSUCCESSFUL
;
1314 /* Remove hive from hive list */
1315 RemoveEntryList (&RegistryHive
->HiveList
);
1317 /* Release file names */
1318 RtlFreeUnicodeString (&RegistryHive
->HiveFileName
);
1319 RtlFreeUnicodeString (&RegistryHive
->LogFileName
);
1321 /* Release hive bitmap */
1322 ExFreePool (RegistryHive
->BitmapBuffer
);
1324 /* Release free cell list */
1325 ExFreePool (RegistryHive
->FreeList
);
1326 ExFreePool (RegistryHive
->FreeListOffset
);
1328 /* Release bins and bin list */
1329 CmiFreeHiveBins (RegistryHive
);
1330 ExFreePool (RegistryHive
->BlockList
);
1332 /* Release hive header */
1333 ExFreePool (RegistryHive
->HiveHeader
);
1336 ExFreePool (RegistryHive
);
1338 return STATUS_SUCCESS
;
1343 CmiCalcChecksum(PULONG Buffer
)
1348 for (i
= 0; i
< 127; i
++)
1356 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
1358 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1359 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1360 OBJECT_ATTRIBUTES ObjectAttributes
;
1361 IO_STATUS_BLOCK IoStatusBlock
;
1363 LARGE_INTEGER FileOffset
;
1373 DPRINT("CmiStartLogUpdate() called\n");
1375 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1376 BufferSize
= sizeof(HIVE_HEADER
) +
1379 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1381 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1383 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
,
1387 DPRINT("ExAllocatePool() failed\n");
1388 return(STATUS_INSUFFICIENT_RESOURCES
);
1390 RtlZeroMemory (Buffer
,
1393 /* Open log file for writing */
1394 InitializeObjectAttributes(&ObjectAttributes
,
1395 &RegistryHive
->LogFileName
,
1396 OBJ_CASE_INSENSITIVE
,
1400 Status
= ZwCreateFile(&FileHandle
,
1405 FILE_ATTRIBUTE_NORMAL
,
1408 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1411 if (!NT_SUCCESS(Status
))
1413 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1418 /* Update firt update counter and checksum */
1419 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1420 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1422 /* Copy hive header */
1423 RtlCopyMemory(Buffer
,
1424 RegistryHive
->HiveHeader
,
1425 sizeof(HIVE_HEADER
));
1426 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1433 RegistryHive
->DirtyBitMap
.Buffer
,
1436 /* Write hive block and block bitmap */
1437 FileOffset
.QuadPart
= (ULONGLONG
)0;
1438 Status
= ZwWriteFile(FileHandle
,
1447 if (!NT_SUCCESS(Status
))
1449 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1450 ZwClose(FileHandle
);
1456 /* Write dirty blocks */
1457 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1459 while (BlockIndex
< RegistryHive
->BlockListSize
)
1461 LastIndex
= BlockIndex
;
1462 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1465 if (BlockIndex
== (ULONG
)-1 || BlockIndex
< LastIndex
)
1467 DPRINT("No more set bits\n");
1468 Status
= STATUS_SUCCESS
;
1472 DPRINT("Block %lu is dirty\n", BlockIndex
);
1474 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1475 DPRINT("BlockPtr %p\n", BlockPtr
);
1476 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1478 /* Write hive block */
1479 Status
= ZwWriteFile(FileHandle
,
1488 if (!NT_SUCCESS(Status
))
1490 DPRINT1("ZwWriteFile() failed (Status %lx)\n", Status
);
1491 ZwClose(FileHandle
);
1496 FileOffset
.QuadPart
+= (ULONGLONG
)REG_BLOCK_SIZE
;
1499 /* Truncate log file */
1500 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1501 Status
= ZwSetInformationFile(FileHandle
,
1504 sizeof(FILE_END_OF_FILE_INFORMATION
),
1505 FileEndOfFileInformation
);
1506 if (!NT_SUCCESS(Status
))
1508 DPRINT("ZwSetInformationFile() failed (Status %lx)\n", Status
);
1509 ZwClose(FileHandle
);
1513 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1514 Status
= ZwSetInformationFile(FileHandle
,
1516 &FileAllocationInfo
,
1517 sizeof(FILE_ALLOCATION_INFORMATION
),
1518 FileAllocationInformation
);
1519 if (!NT_SUCCESS(Status
))
1521 DPRINT("ZwSetInformationFile() failed (Status %lx)\n", Status
);
1522 ZwClose(FileHandle
);
1526 /* Flush the log file */
1527 Status
= ZwFlushBuffersFile(FileHandle
,
1529 if (!NT_SUCCESS(Status
))
1531 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1534 ZwClose(FileHandle
);
1541 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1543 OBJECT_ATTRIBUTES ObjectAttributes
;
1544 IO_STATUS_BLOCK IoStatusBlock
;
1546 LARGE_INTEGER FileOffset
;
1553 DPRINT("CmiFinishLogUpdate() called\n");
1555 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1556 BufferSize
= sizeof(HIVE_HEADER
) +
1559 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1561 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1563 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1566 DPRINT("ExAllocatePool() failed\n");
1567 return(STATUS_INSUFFICIENT_RESOURCES
);
1570 /* Open log file for writing */
1571 InitializeObjectAttributes(&ObjectAttributes
,
1572 &RegistryHive
->LogFileName
,
1573 OBJ_CASE_INSENSITIVE
,
1577 Status
= ZwCreateFile(&FileHandle
,
1582 FILE_ATTRIBUTE_NORMAL
,
1585 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1588 if (!NT_SUCCESS(Status
))
1590 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1595 /* Update first and second update counter and checksum */
1596 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1597 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1598 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1600 /* Copy hive header */
1601 RtlCopyMemory(Buffer
,
1602 RegistryHive
->HiveHeader
,
1603 sizeof(HIVE_HEADER
));
1604 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1606 /* Write empty block bitmap */
1614 /* Write hive block and block bitmap */
1615 FileOffset
.QuadPart
= (ULONGLONG
)0;
1616 Status
= ZwWriteFile(FileHandle
,
1625 if (!NT_SUCCESS(Status
))
1627 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1628 ZwClose(FileHandle
);
1635 /* Flush the log file */
1636 Status
= ZwFlushBuffersFile(FileHandle
,
1638 if (!NT_SUCCESS(Status
))
1640 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1643 ZwClose(FileHandle
);
1650 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1652 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1653 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1654 OBJECT_ATTRIBUTES ObjectAttributes
;
1655 IO_STATUS_BLOCK IoStatusBlock
;
1661 DPRINT("CmiCleanupLogUpdate() called\n");
1663 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1664 BufferSize
= sizeof(HIVE_HEADER
) +
1667 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1669 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1671 /* Open log file for writing */
1672 InitializeObjectAttributes(&ObjectAttributes
,
1673 &RegistryHive
->LogFileName
,
1674 OBJ_CASE_INSENSITIVE
,
1678 Status
= ZwCreateFile(&FileHandle
,
1683 FILE_ATTRIBUTE_NORMAL
,
1686 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1689 if (!NT_SUCCESS(Status
))
1691 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1695 /* Truncate log file */
1696 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1697 Status
= ZwSetInformationFile(FileHandle
,
1700 sizeof(FILE_END_OF_FILE_INFORMATION
),
1701 FileEndOfFileInformation
);
1702 if (!NT_SUCCESS(Status
))
1704 DPRINT("ZwSetInformationFile() failed (Status %lx)\n", Status
);
1705 ZwClose(FileHandle
);
1709 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1710 Status
= ZwSetInformationFile(FileHandle
,
1712 &FileAllocationInfo
,
1713 sizeof(FILE_ALLOCATION_INFORMATION
),
1714 FileAllocationInformation
);
1715 if (!NT_SUCCESS(Status
))
1717 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1718 ZwClose(FileHandle
);
1722 /* Flush the log file */
1723 Status
= ZwFlushBuffersFile(FileHandle
,
1725 if (!NT_SUCCESS(Status
))
1727 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1730 ZwClose(FileHandle
);
1737 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1739 OBJECT_ATTRIBUTES ObjectAttributes
;
1740 IO_STATUS_BLOCK IoStatusBlock
;
1742 LARGE_INTEGER FileOffset
;
1748 DPRINT("CmiStartHiveUpdate() called\n");
1750 /* Open hive for writing */
1751 InitializeObjectAttributes(&ObjectAttributes
,
1752 &RegistryHive
->HiveFileName
,
1753 OBJ_CASE_INSENSITIVE
,
1757 Status
= ZwCreateFile(&FileHandle
,
1762 FILE_ATTRIBUTE_NORMAL
,
1765 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1768 if (!NT_SUCCESS(Status
))
1770 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1774 /* Update firt update counter and checksum */
1775 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1776 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1778 /* Write hive block */
1779 FileOffset
.QuadPart
= (ULONGLONG
)0;
1780 Status
= ZwWriteFile(FileHandle
,
1785 RegistryHive
->HiveHeader
,
1786 sizeof(HIVE_HEADER
),
1789 if (!NT_SUCCESS(Status
))
1791 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1792 ZwClose(FileHandle
);
1797 while (BlockIndex
< RegistryHive
->BlockListSize
)
1799 LastIndex
= BlockIndex
;
1800 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1803 if (BlockIndex
== (ULONG
)-1 || BlockIndex
< LastIndex
)
1805 DPRINT("No more set bits\n");
1806 Status
= STATUS_SUCCESS
;
1810 DPRINT("Block %lu is dirty\n", BlockIndex
);
1812 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1813 DPRINT(" BlockPtr %p\n", BlockPtr
);
1815 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
1816 DPRINT(" File offset %I64x\n", FileOffset
.QuadPart
);
1818 /* Write hive block */
1819 Status
= ZwWriteFile(FileHandle
,
1828 if (!NT_SUCCESS(Status
))
1830 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1831 ZwClose(FileHandle
);
1838 Status
= ZwFlushBuffersFile(FileHandle
,
1840 if (!NT_SUCCESS(Status
))
1842 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1845 ZwClose(FileHandle
);
1852 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1854 OBJECT_ATTRIBUTES ObjectAttributes
;
1855 IO_STATUS_BLOCK IoStatusBlock
;
1856 LARGE_INTEGER FileOffset
;
1860 DPRINT("CmiFinishHiveUpdate() called\n");
1862 InitializeObjectAttributes(&ObjectAttributes
,
1863 &RegistryHive
->HiveFileName
,
1864 OBJ_CASE_INSENSITIVE
,
1868 Status
= ZwCreateFile(&FileHandle
,
1873 FILE_ATTRIBUTE_NORMAL
,
1876 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1879 if (!NT_SUCCESS(Status
))
1881 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1885 /* Update second update counter and checksum */
1886 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1887 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1888 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1890 /* Write hive block */
1891 FileOffset
.QuadPart
= (ULONGLONG
)0;
1892 Status
= ZwWriteFile(FileHandle
,
1897 RegistryHive
->HiveHeader
,
1898 sizeof(HIVE_HEADER
),
1901 if (!NT_SUCCESS(Status
))
1903 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1904 ZwClose(FileHandle
);
1908 Status
= ZwFlushBuffersFile(FileHandle
,
1910 if (!NT_SUCCESS(Status
))
1912 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1915 ZwClose(FileHandle
);
1922 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1926 DPRINT("CmiFlushRegistryHive() called\n");
1928 if (RegistryHive
->HiveDirty
== FALSE
)
1930 return(STATUS_SUCCESS
);
1933 DPRINT("Hive '%wZ' is dirty\n",
1934 &RegistryHive
->HiveFileName
);
1935 DPRINT("Log file: '%wZ'\n",
1936 &RegistryHive
->LogFileName
);
1938 /* Update hive header modification time */
1939 KeQuerySystemTime(&RegistryHive
->HiveHeader
->DateModified
);
1941 /* Start log update */
1942 Status
= CmiStartLogUpdate(RegistryHive
);
1943 if (!NT_SUCCESS(Status
))
1945 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1949 /* Finish log update */
1950 Status
= CmiFinishLogUpdate(RegistryHive
);
1951 if (!NT_SUCCESS(Status
))
1953 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1957 /* Start hive update */
1958 Status
= CmiStartHiveUpdate(RegistryHive
);
1959 if (!NT_SUCCESS(Status
))
1961 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1965 /* Finish the hive update */
1966 Status
= CmiFinishHiveUpdate(RegistryHive
);
1967 if (!NT_SUCCESS(Status
))
1969 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
1973 /* Cleanup log update */
1974 Status
= CmiCleanupLogUpdate(RegistryHive
);
1975 if (!NT_SUCCESS(Status
))
1977 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1981 /* Increment hive update counter */
1982 RegistryHive
->UpdateCounter
++;
1984 /* Clear dirty bitmap and dirty flag */
1985 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
1986 RegistryHive
->HiveDirty
= FALSE
;
1988 DPRINT("CmiFlushRegistryHive() done\n");
1990 return(STATUS_SUCCESS
);
1995 CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject
)
2002 VERIFY_KEY_OBJECT(KeyObject
);
2004 KeyCell
= KeyObject
->KeyCell
;
2005 VERIFY_KEY_CELL(KeyCell
);
2007 SubKeyCount
= (KeyCell
== NULL
) ? 0 : KeyCell
->NumberOfSubKeys
;
2009 /* Search for volatile or 'foreign' keys */
2010 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2012 CurKey
= KeyObject
->SubKeys
[i
];
2013 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2014 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2025 CmiGetMaxNameLength(PKEY_OBJECT KeyObject
)
2027 PHASH_TABLE_CELL HashBlock
;
2029 PKEY_CELL CurSubKeyCell
;
2035 VERIFY_KEY_OBJECT(KeyObject
);
2037 KeyCell
= KeyObject
->KeyCell
;
2038 VERIFY_KEY_CELL(KeyCell
);
2041 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2042 KeyCell
->HashTableOffset
,
2044 if (HashBlock
== NULL
)
2046 DPRINT("CmiGetBlock() failed\n");
2050 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2052 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2054 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2055 HashBlock
->Table
[i
].KeyOffset
,
2057 if (CurSubKeyCell
== NULL
)
2059 DPRINT("CmiGetBlock() failed\n");
2063 NameSize
= CurSubKeyCell
->NameSize
;
2064 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2066 NameSize
*= sizeof(WCHAR
);
2069 if (NameSize
> MaxName
)
2077 DPRINT ("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2078 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2080 CurKey
= KeyObject
->SubKeys
[i
];
2081 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2082 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2084 CurSubKeyCell
= CurKey
->KeyCell
;
2085 if (CurSubKeyCell
== NULL
)
2087 DPRINT("CmiGetBlock() failed\n");
2091 if ((CurSubKeyCell
->Flags
& REG_KEY_ROOT_CELL
) == REG_KEY_ROOT_CELL
)
2093 /* Use name of the key object */
2094 NameSize
= CurKey
->Name
.Length
;
2098 /* Use name of the key cell */
2099 NameSize
= CurSubKeyCell
->NameSize
;
2100 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2102 NameSize
*= sizeof(WCHAR
);
2105 DPRINT ("NameSize %lu\n", NameSize
);
2107 if (NameSize
> MaxName
)
2114 DPRINT ("MaxName %lu\n", MaxName
);
2121 CmiGetMaxClassLength(PKEY_OBJECT KeyObject
)
2123 PHASH_TABLE_CELL HashBlock
;
2125 PKEY_CELL CurSubKeyCell
;
2130 VERIFY_KEY_OBJECT(KeyObject
);
2132 KeyCell
= KeyObject
->KeyCell
;
2133 VERIFY_KEY_CELL(KeyCell
);
2136 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2137 KeyCell
->HashTableOffset
,
2139 if (HashBlock
== NULL
)
2141 DPRINT("CmiGetBlock() failed\n");
2145 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2147 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2149 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2150 HashBlock
->Table
[i
].KeyOffset
,
2152 if (CurSubKeyCell
== NULL
)
2154 DPRINT("CmiGetBlock() failed\n");
2158 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2160 MaxClass
= CurSubKeyCell
->ClassSize
;
2166 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2167 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2169 CurKey
= KeyObject
->SubKeys
[i
];
2170 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2171 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2173 CurSubKeyCell
= CurKey
->KeyCell
;
2174 if (CurSubKeyCell
== NULL
)
2176 DPRINT("CmiGetBlock() failed\n");
2180 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2182 MaxClass
= CurSubKeyCell
->ClassSize
;
2192 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
2195 PVALUE_LIST_CELL ValueListCell
;
2196 PVALUE_CELL CurValueCell
;
2201 VERIFY_KEY_CELL(KeyCell
);
2204 ValueListCell
= CmiGetCell (RegistryHive
,
2205 KeyCell
->ValueListOffset
,
2207 if (ValueListCell
== NULL
)
2209 DPRINT("CmiGetBlock() failed\n");
2213 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2215 CurValueCell
= CmiGetCell (RegistryHive
,
2216 ValueListCell
->ValueOffset
[i
],
2218 if (CurValueCell
== NULL
)
2220 DPRINT("CmiGetBlock() failed\n");
2223 if (CurValueCell
!= NULL
)
2225 Size
= CurValueCell
->NameSize
;
2226 if (CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
2228 Size
*= sizeof(WCHAR
);
2230 if (MaxValueName
< Size
)
2232 MaxValueName
= Size
;
2237 return MaxValueName
;
2242 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
2245 PVALUE_LIST_CELL ValueListCell
;
2246 PVALUE_CELL CurValueCell
;
2250 VERIFY_KEY_CELL(KeyCell
);
2253 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2254 if (ValueListCell
== NULL
)
2259 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2261 CurValueCell
= CmiGetCell (RegistryHive
,
2262 ValueListCell
->ValueOffset
[i
],NULL
);
2263 if ((CurValueCell
!= NULL
) &&
2264 (MaxValueData
< (LONG
)(CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2266 MaxValueData
= CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2270 return MaxValueData
;
2275 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
2276 IN PKEY_CELL KeyCell
,
2277 OUT PKEY_CELL
*SubKeyCell
,
2278 OUT BLOCK_OFFSET
*BlockOffset
,
2279 IN PUNICODE_STRING KeyName
,
2280 IN ACCESS_MASK DesiredAccess
,
2281 IN ULONG Attributes
)
2283 PHASH_TABLE_CELL HashBlock
;
2284 PKEY_CELL CurSubKeyCell
;
2287 VERIFY_KEY_CELL(KeyCell
);
2289 DPRINT("Scanning for sub key %wZ\n", KeyName
);
2291 ASSERT(RegistryHive
);
2295 /* The key does not have any subkeys */
2296 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
2298 return STATUS_SUCCESS
;
2301 /* Get hash table */
2302 HashBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2303 if (HashBlock
== NULL
)
2305 DPRINT("CmiGetBlock() failed\n");
2306 return STATUS_UNSUCCESSFUL
;
2309 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
) && (i
< HashBlock
->HashTableSize
); i
++)
2311 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2313 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2314 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1 &&
2315 (HashBlock
->Table
[i
].HashValue
== 0 ||
2316 CmiCompareHashI(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2318 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2319 HashBlock
->Table
[i
].KeyOffset
,
2321 if (CurSubKeyCell
== NULL
)
2323 DPRINT("CmiGetBlock() failed\n");
2324 return STATUS_UNSUCCESSFUL
;
2327 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2329 *SubKeyCell
= CurSubKeyCell
;
2330 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2337 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2338 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2339 (HashBlock
->Table
[i
].HashValue
== 0 ||
2340 CmiCompareHash(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2342 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2343 HashBlock
->Table
[i
].KeyOffset
,
2345 if (CurSubKeyCell
== NULL
)
2347 DPRINT("CmiGetBlock() failed\n");
2348 return STATUS_UNSUCCESSFUL
;
2351 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2353 *SubKeyCell
= CurSubKeyCell
;
2354 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2361 return STATUS_SUCCESS
;
2366 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2367 PKEY_OBJECT ParentKey
,
2369 PUNICODE_STRING SubKeyName
,
2371 PUNICODE_STRING Class
,
2372 ULONG CreateOptions
)
2374 PHASH_TABLE_CELL HashBlock
;
2375 BLOCK_OFFSET NKBOffset
;
2376 PKEY_CELL NewKeyCell
;
2378 PKEY_CELL ParentKeyCell
;
2379 PDATA_CELL ClassCell
;
2386 ParentKeyCell
= ParentKey
->KeyCell
;
2388 VERIFY_KEY_CELL(ParentKeyCell
);
2390 /* Skip leading backslash */
2391 if (SubKeyName
->Buffer
[0] == L
'\\')
2393 NamePtr
= &SubKeyName
->Buffer
[1];
2394 NameSize
= SubKeyName
->Length
- sizeof(WCHAR
);
2398 NamePtr
= SubKeyName
->Buffer
;
2399 NameSize
= SubKeyName
->Length
;
2402 /* Check whether key name can be packed */
2404 for (i
= 0; i
< NameSize
/ sizeof(WCHAR
); i
++)
2406 if (NamePtr
[i
] & 0xFF00)
2413 /* Adjust name size */
2416 NameSize
= NameSize
/ sizeof(WCHAR
);
2419 DPRINT("Key %S Length %lu %s\n", NamePtr
, NameSize
, (Packable
)?"True":"False");
2421 Status
= STATUS_SUCCESS
;
2423 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2424 Status
= CmiAllocateCell (RegistryHive
,
2426 (PVOID
) &NewKeyCell
,
2428 if (NewKeyCell
== NULL
)
2430 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2434 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2435 NewKeyCell
->Flags
= 0;
2436 KeQuerySystemTime(&NewKeyCell
->LastWriteTime
);
2437 NewKeyCell
->ParentKeyOffset
= -1;
2438 NewKeyCell
->NumberOfSubKeys
= 0;
2439 NewKeyCell
->HashTableOffset
= -1;
2440 NewKeyCell
->NumberOfValues
= 0;
2441 NewKeyCell
->ValueListOffset
= -1;
2442 NewKeyCell
->SecurityKeyOffset
= -1;
2443 NewKeyCell
->ClassNameOffset
= -1;
2445 /* Pack the key name */
2446 NewKeyCell
->NameSize
= NameSize
;
2449 NewKeyCell
->Flags
|= REG_KEY_NAME_PACKED
;
2450 for (i
= 0; i
< NameSize
; i
++)
2452 NewKeyCell
->Name
[i
] = (CHAR
)(NamePtr
[i
] & 0x00FF);
2457 RtlCopyMemory(NewKeyCell
->Name
,
2462 VERIFY_KEY_CELL(NewKeyCell
);
2466 NewKeyCell
->ClassSize
= Class
->Length
;
2467 Status
= CmiAllocateCell (RegistryHive
,
2468 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
2470 &NewKeyCell
->ClassNameOffset
);
2471 RtlCopyMemory (ClassCell
->Data
,
2477 if (!NT_SUCCESS(Status
))
2482 SubKey
->KeyCell
= NewKeyCell
;
2483 SubKey
->KeyCellOffset
= NKBOffset
;
2485 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2486 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(ParentKey
->RegistryHive
)))
2491 if (ParentKeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2493 Status
= CmiAllocateHashTableCell (RegistryHive
,
2495 &ParentKeyCell
->HashTableOffset
,
2496 REG_INIT_HASH_TABLE_SIZE
);
2497 if (!NT_SUCCESS(Status
))
2504 HashBlock
= CmiGetCell (RegistryHive
,
2505 ParentKeyCell
->HashTableOffset
,
2507 if (HashBlock
== NULL
)
2509 DPRINT("CmiGetCell() failed\n");
2510 return STATUS_UNSUCCESSFUL
;
2513 if (((ParentKeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2515 PHASH_TABLE_CELL NewHashBlock
;
2516 BLOCK_OFFSET HTOffset
;
2518 /* Reallocate the hash table cell */
2519 Status
= CmiAllocateHashTableCell (RegistryHive
,
2522 HashBlock
->HashTableSize
+
2523 REG_EXTEND_HASH_TABLE_SIZE
);
2524 if (!NT_SUCCESS(Status
))
2529 RtlZeroMemory(&NewHashBlock
->Table
[0],
2530 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2531 RtlCopyMemory(&NewHashBlock
->Table
[0],
2532 &HashBlock
->Table
[0],
2533 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2534 CmiDestroyCell (RegistryHive
,
2536 ParentKeyCell
->HashTableOffset
);
2537 ParentKeyCell
->HashTableOffset
= HTOffset
;
2538 HashBlock
= NewHashBlock
;
2542 Status
= CmiAddKeyToHashTable(RegistryHive
,
2544 ParentKeyCell
->HashTableOffset
,
2547 if (NT_SUCCESS(Status
))
2549 ParentKeyCell
->NumberOfSubKeys
++;
2552 KeQuerySystemTime (&ParentKeyCell
->LastWriteTime
);
2553 CmiMarkBlockDirty (RegistryHive
, ParentKey
->KeyCellOffset
);
2560 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2561 PKEY_OBJECT ParentKey
,
2564 PHASH_TABLE_CELL HashBlock
;
2565 PVALUE_LIST_CELL ValueList
;
2566 PVALUE_CELL ValueCell
;
2567 PDATA_CELL DataCell
;
2570 DPRINT("CmiRemoveSubKey() called\n");
2572 /* Remove all values */
2573 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2575 /* Get pointer to the value list cell */
2576 ValueList
= CmiGetCell (RegistryHive
,
2577 SubKey
->KeyCell
->ValueListOffset
,
2579 if (ValueList
== NULL
)
2581 DPRINT("CmiGetCell() failed\n");
2582 return STATUS_UNSUCCESSFUL
;
2585 /* Enumerate all values */
2586 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2588 /* Get pointer to value cell */
2589 ValueCell
= CmiGetCell(RegistryHive
,
2590 ValueList
->ValueOffset
[i
],
2592 if (ValueCell
== NULL
)
2594 DPRINT("CmiGetCell() failed\n");
2595 return STATUS_UNSUCCESSFUL
;
2598 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
)
2599 && ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
2601 DataCell
= CmiGetCell (RegistryHive
,
2602 ValueCell
->DataOffset
,
2604 if (DataCell
== NULL
)
2606 DPRINT("CmiGetCell() failed\n");
2607 return STATUS_UNSUCCESSFUL
;
2610 if (DataCell
!= NULL
)
2612 /* Destroy data cell */
2613 CmiDestroyCell (RegistryHive
,
2615 ValueCell
->DataOffset
);
2619 /* Destroy value cell */
2620 CmiDestroyCell (RegistryHive
,
2622 ValueList
->ValueOffset
[i
]);
2625 /* Destroy value list cell */
2626 CmiDestroyCell (RegistryHive
,
2628 SubKey
->KeyCell
->ValueListOffset
);
2630 SubKey
->KeyCell
->NumberOfValues
= 0;
2631 SubKey
->KeyCell
->ValueListOffset
= (BLOCK_OFFSET
)-1;
2633 CmiMarkBlockDirty(RegistryHive
,
2634 SubKey
->KeyCellOffset
);
2637 /* Remove the key from the parent key's hash block */
2638 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2640 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2641 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2642 ParentKey
->KeyCell
->HashTableOffset
,
2644 if (HashBlock
== NULL
)
2646 DPRINT("CmiGetCell() failed\n");
2647 return STATUS_UNSUCCESSFUL
;
2649 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2650 if (HashBlock
!= NULL
)
2652 CmiRemoveKeyFromHashTable(ParentKey
->RegistryHive
,
2654 SubKey
->KeyCellOffset
);
2655 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2656 ParentKey
->KeyCell
->HashTableOffset
);
2660 /* Remove the key's hash block */
2661 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2663 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
);
2664 HashBlock
= CmiGetCell (RegistryHive
,
2665 SubKey
->KeyCell
->HashTableOffset
,
2667 if (HashBlock
== NULL
)
2669 DPRINT("CmiGetCell() failed\n");
2670 return STATUS_UNSUCCESSFUL
;
2672 DPRINT("SubKey HashBlock %p\n", HashBlock
);
2673 if (HashBlock
!= NULL
)
2675 CmiDestroyCell (RegistryHive
,
2677 SubKey
->KeyCell
->HashTableOffset
);
2678 SubKey
->KeyCell
->HashTableOffset
= -1;
2682 /* Decrement the number of the parent key's sub keys */
2683 if (ParentKey
!= NULL
)
2685 DPRINT("ParentKey %p\n", ParentKey
);
2686 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2688 /* Remove the parent key's hash table */
2689 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2691 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2692 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2693 ParentKey
->KeyCell
->HashTableOffset
,
2695 if (HashBlock
== NULL
)
2697 DPRINT("CmiGetCell() failed\n");
2698 return STATUS_UNSUCCESSFUL
;
2700 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2701 if (HashBlock
!= NULL
)
2703 CmiDestroyCell (ParentKey
->RegistryHive
,
2705 ParentKey
->KeyCell
->HashTableOffset
);
2706 ParentKey
->KeyCell
->HashTableOffset
= (BLOCK_OFFSET
)-1;
2710 KeQuerySystemTime(&ParentKey
->KeyCell
->LastWriteTime
);
2711 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2712 ParentKey
->KeyCellOffset
);
2715 /* Destroy key cell */
2716 CmiDestroyCell (RegistryHive
,
2718 SubKey
->KeyCellOffset
);
2719 SubKey
->KeyCell
= NULL
;
2720 SubKey
->KeyCellOffset
= (BLOCK_OFFSET
)-1;
2722 DPRINT("CmiRemoveSubKey() done\n");
2724 return STATUS_SUCCESS
;
2729 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2730 IN PKEY_CELL KeyCell
,
2731 IN PUNICODE_STRING ValueName
,
2732 OUT PVALUE_CELL
*ValueCell
,
2733 OUT BLOCK_OFFSET
*ValueCellOffset
)
2735 PVALUE_LIST_CELL ValueListCell
;
2736 PVALUE_CELL CurValueCell
;
2740 if (ValueCellOffset
!= NULL
)
2741 *ValueCellOffset
= (BLOCK_OFFSET
)-1;
2743 /* The key does not have any values */
2744 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2746 return STATUS_OBJECT_NAME_NOT_FOUND
;
2749 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2750 if (ValueListCell
== NULL
)
2752 DPRINT("ValueListCell is NULL\n");
2753 return STATUS_UNSUCCESSFUL
;
2756 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2758 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2760 CurValueCell
= CmiGetCell (RegistryHive
,
2761 ValueListCell
->ValueOffset
[i
],
2763 if (CurValueCell
== NULL
)
2765 DPRINT("CmiGetBlock() failed\n");
2766 return STATUS_UNSUCCESSFUL
;
2769 if ((CurValueCell
!= NULL
) &&
2770 CmiComparePackedNames(ValueName
,
2772 CurValueCell
->NameSize
,
2773 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2775 *ValueCell
= CurValueCell
;
2776 if (ValueCellOffset
!= NULL
)
2777 *ValueCellOffset
= ValueListCell
->ValueOffset
[i
];
2778 //DPRINT("Found value %s\n", ValueName);
2779 return STATUS_SUCCESS
;
2783 return STATUS_OBJECT_NAME_NOT_FOUND
;
2788 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2789 IN PKEY_CELL KeyCell
,
2791 OUT PVALUE_CELL
*ValueCell
)
2793 PVALUE_LIST_CELL ValueListCell
;
2794 PVALUE_CELL CurValueCell
;
2798 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2800 return STATUS_NO_MORE_ENTRIES
;
2803 if (Index
>= KeyCell
->NumberOfValues
)
2805 return STATUS_NO_MORE_ENTRIES
;
2809 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2810 if (ValueListCell
== NULL
)
2812 DPRINT("CmiGetBlock() failed\n");
2813 return STATUS_UNSUCCESSFUL
;
2816 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2819 CurValueCell
= CmiGetCell (RegistryHive
,
2820 ValueListCell
->ValueOffset
[Index
],
2822 if (CurValueCell
== NULL
)
2824 DPRINT("CmiGetBlock() failed\n");
2825 return STATUS_UNSUCCESSFUL
;
2828 *ValueCell
= CurValueCell
;
2830 return STATUS_SUCCESS
;
2835 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2836 IN PKEY_CELL KeyCell
,
2837 IN BLOCK_OFFSET KeyCellOffset
,
2838 IN PUNICODE_STRING ValueName
,
2839 OUT PVALUE_CELL
*pValueCell
,
2840 OUT BLOCK_OFFSET
*pValueCellOffset
)
2842 PVALUE_LIST_CELL NewValueListCell
;
2843 PVALUE_LIST_CELL ValueListCell
;
2844 PVALUE_CELL NewValueCell
;
2845 BLOCK_OFFSET NewValueListCellOffset
;
2846 BLOCK_OFFSET ValueListCellOffset
;
2847 BLOCK_OFFSET NewValueCellOffset
;
2851 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG
)KeyCell
->ValueListOffset
);
2853 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2854 if (ValueListCell
== NULL
)
2856 CellSize
= sizeof(VALUE_LIST_CELL
) +
2857 (3 * sizeof(BLOCK_OFFSET
));
2858 Status
= CmiAllocateCell (RegistryHive
,
2860 (PVOID
) &ValueListCell
,
2861 &ValueListCellOffset
);
2862 if (!NT_SUCCESS(Status
))
2867 KeyCell
->ValueListOffset
= ValueListCellOffset
;
2868 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2869 CmiMarkBlockDirty(RegistryHive
, ValueListCellOffset
);
2871 else if (KeyCell
->NumberOfValues
>=
2872 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
)))
2875 CellSize
= sizeof(VALUE_LIST_CELL
) +
2876 ((KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) * sizeof(BLOCK_OFFSET
));
2878 CellSize
= 2 * (ULONG
)ABS_VALUE(ValueListCell
->CellSize
);
2879 Status
= CmiAllocateCell (RegistryHive
,
2881 (PVOID
) &NewValueListCell
,
2882 &NewValueListCellOffset
);
2883 if (!NT_SUCCESS(Status
))
2888 RtlCopyMemory(&NewValueListCell
->ValueOffset
[0],
2889 &ValueListCell
->ValueOffset
[0],
2890 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2891 CmiDestroyCell (RegistryHive
, ValueListCell
, KeyCell
->ValueListOffset
);
2892 CmiMarkBlockDirty (RegistryHive
, KeyCell
->ValueListOffset
);
2894 KeyCell
->ValueListOffset
= NewValueListCellOffset
;
2895 ValueListCell
= NewValueListCell
;
2896 CmiMarkBlockDirty (RegistryHive
, KeyCellOffset
);
2897 CmiMarkBlockDirty (RegistryHive
, NewValueListCellOffset
);
2900 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2901 KeyCell
->NumberOfValues
,
2902 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2903 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
),
2904 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
));
2906 Status
= CmiAllocateValueCell(RegistryHive
,
2908 &NewValueCellOffset
,
2910 if (!NT_SUCCESS(Status
))
2915 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = NewValueCellOffset
;
2916 KeyCell
->NumberOfValues
++;
2918 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2919 CmiMarkBlockDirty(RegistryHive
, KeyCell
->ValueListOffset
);
2920 CmiMarkBlockDirty(RegistryHive
, NewValueCellOffset
);
2922 *pValueCell
= NewValueCell
;
2923 *pValueCellOffset
= NewValueCellOffset
;
2925 return STATUS_SUCCESS
;
2930 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2931 IN PKEY_CELL KeyCell
,
2932 IN BLOCK_OFFSET KeyCellOffset
,
2933 IN PUNICODE_STRING ValueName
)
2935 PVALUE_LIST_CELL ValueListCell
;
2936 PVALUE_CELL CurValueCell
;
2940 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2941 if (ValueListCell
== NULL
)
2943 DPRINT1("CmiGetBlock() failed\n");
2944 return STATUS_SUCCESS
;
2947 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2949 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2951 CurValueCell
= CmiGetCell (RegistryHive
, ValueListCell
->ValueOffset
[i
], NULL
);
2952 if (CurValueCell
== NULL
)
2954 DPRINT1("CmiGetBlock() failed\n");
2955 return STATUS_UNSUCCESSFUL
;
2958 if (CmiComparePackedNames(ValueName
,
2960 CurValueCell
->NameSize
,
2961 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2963 Status
= CmiDestroyValueCell(RegistryHive
,
2965 ValueListCell
->ValueOffset
[i
]);
2966 if (CurValueCell
== NULL
)
2968 DPRINT1("CmiDestroyValueCell() failed\n");
2972 if (i
< (KeyCell
->NumberOfValues
- 1))
2974 RtlMoveMemory(&ValueListCell
->ValueOffset
[i
],
2975 &ValueListCell
->ValueOffset
[i
+ 1],
2976 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2978 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
- 1] = 0;
2981 KeyCell
->NumberOfValues
--;
2983 if (KeyCell
->NumberOfValues
== 0)
2985 CmiDestroyCell(RegistryHive
,
2987 KeyCell
->ValueListOffset
);
2988 KeyCell
->ValueListOffset
= -1;
2992 CmiMarkBlockDirty(RegistryHive
,
2993 KeyCell
->ValueListOffset
);
2996 CmiMarkBlockDirty(RegistryHive
,
2999 return STATUS_SUCCESS
;
3003 DPRINT("Couldn't find the desired value\n");
3005 return STATUS_OBJECT_NAME_NOT_FOUND
;
3010 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive
,
3011 OUT PHASH_TABLE_CELL
*HashBlock
,
3012 OUT BLOCK_OFFSET
*HBOffset
,
3013 IN ULONG SubKeyCount
)
3015 PHASH_TABLE_CELL NewHashBlock
;
3019 Status
= STATUS_SUCCESS
;
3021 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
3022 (SubKeyCount
* sizeof(HASH_RECORD
));
3023 Status
= CmiAllocateCell (RegistryHive
,
3025 (PVOID
*) &NewHashBlock
,
3028 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
3030 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3034 ASSERT(SubKeyCount
<= 0xffff); /* should really be USHORT_MAX or similar */
3035 NewHashBlock
->Id
= REG_HASH_TABLE_CELL_ID
;
3036 NewHashBlock
->HashTableSize
= (USHORT
)SubKeyCount
;
3037 *HashBlock
= NewHashBlock
;
3045 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
3046 PHASH_TABLE_CELL HashBlock
,
3049 BLOCK_OFFSET KeyOffset
;
3052 if (HashBlock
== NULL
)
3055 if (IsPointerHive(RegistryHive
))
3057 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
3061 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
3062 KeyCell
= CmiGetCell (RegistryHive
, KeyOffset
, NULL
);
3070 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
3071 PHASH_TABLE_CELL HashCell
,
3072 BLOCK_OFFSET HashCellOffset
,
3073 PKEY_CELL NewKeyCell
,
3074 BLOCK_OFFSET NKBOffset
)
3078 for (i
= 0; i
< HashCell
->HashTableSize
; i
++)
3080 if (HashCell
->Table
[i
].KeyOffset
== 0)
3082 HashCell
->Table
[i
].KeyOffset
= NKBOffset
;
3083 HashCell
->Table
[i
].HashValue
= 0;
3084 if (NewKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3086 RtlCopyMemory(&HashCell
->Table
[i
].HashValue
,
3088 min(NewKeyCell
->NameSize
, sizeof(ULONG
)));
3090 CmiMarkBlockDirty(RegistryHive
, HashCellOffset
);
3091 return STATUS_SUCCESS
;
3095 return STATUS_UNSUCCESSFUL
;
3100 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
3101 PHASH_TABLE_CELL HashBlock
,
3102 BLOCK_OFFSET NKBOffset
)
3106 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3108 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
3110 HashBlock
->Table
[i
].KeyOffset
= 0;
3111 HashBlock
->Table
[i
].HashValue
= 0;
3112 return STATUS_SUCCESS
;
3116 return STATUS_UNSUCCESSFUL
;
3121 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
3122 PVALUE_CELL
*ValueCell
,
3123 BLOCK_OFFSET
*VBOffset
,
3124 IN PUNICODE_STRING ValueName
)
3126 PVALUE_CELL NewValueCell
;
3132 Status
= STATUS_SUCCESS
;
3134 NameSize
= CmiGetPackedNameLength(ValueName
,
3137 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
3139 Status
= CmiAllocateCell (RegistryHive
,
3140 sizeof(VALUE_CELL
) + NameSize
,
3141 (PVOID
*) &NewValueCell
,
3143 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
3145 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3149 ASSERT(NameSize
<= 0xffff); /* should really be USHORT_MAX or similar */
3150 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
3151 NewValueCell
->NameSize
= (USHORT
)NameSize
;
3154 /* Pack the value name */
3155 for (i
= 0; i
< NameSize
; i
++)
3156 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
3157 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
3161 /* Copy the value name */
3162 RtlCopyMemory(NewValueCell
->Name
,
3165 NewValueCell
->Flags
= 0;
3167 NewValueCell
->DataType
= 0;
3168 NewValueCell
->DataSize
= 0;
3169 NewValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
3170 *ValueCell
= NewValueCell
;
3178 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
3179 PVALUE_CELL ValueCell
,
3180 BLOCK_OFFSET ValueCellOffset
)
3186 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n",
3187 ValueCell
, ValueCellOffset
);
3189 VERIFY_VALUE_CELL(ValueCell
);
3191 /* Destroy the data cell */
3192 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
)
3193 && ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
3195 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, &Bin
);
3196 if (DataCell
== NULL
)
3198 DPRINT("CmiGetCell() failed\n");
3199 return STATUS_UNSUCCESSFUL
;
3202 Status
= CmiDestroyCell (RegistryHive
, DataCell
, ValueCell
->DataOffset
);
3203 if (!NT_SUCCESS(Status
))
3208 /* Update time of heap */
3209 if (!IsNoFileHive(RegistryHive
))
3210 KeQuerySystemTime(&Bin
->DateModified
);
3213 /* Destroy the value cell */
3214 Status
= CmiDestroyCell (RegistryHive
, ValueCell
, ValueCellOffset
);
3216 /* Update time of heap */
3217 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, ValueCellOffset
, &Bin
))
3219 KeQuerySystemTime(&Bin
->DateModified
);
3227 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
3230 BLOCK_OFFSET
*NewBlockOffset
)
3232 PBLOCK_LIST_ENTRY BlockList
;
3233 PCELL_HEADER tmpBlock
;
3239 DPRINT ("CmiAddBin (BlockCount %lu)\n", BlockCount
);
3241 BinSize
= BlockCount
* REG_BLOCK_SIZE
;
3242 tmpBin
= ExAllocatePool(PagedPool
, BinSize
);
3245 return STATUS_INSUFFICIENT_RESOURCES
;
3247 RtlZeroMemory (tmpBin
,
3250 tmpBin
->HeaderId
= REG_BIN_ID
;
3251 tmpBin
->BinOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
3252 RegistryHive
->FileSize
+= BinSize
;
3253 tmpBin
->BinSize
= BinSize
;
3254 KeQuerySystemTime(&tmpBin
->DateModified
);
3255 tmpBin
->MemAlloc
= 0;
3257 DPRINT (" BinOffset %lx BinSize %lx\n", tmpBin
->BinOffset
,tmpBin
->BinSize
);
3259 /* Allocate new block list */
3260 BlockList
= ExAllocatePool(NonPagedPool
,
3261 sizeof(BLOCK_LIST_ENTRY
) * (RegistryHive
->BlockListSize
+ BlockCount
));
3262 if (BlockList
== NULL
)
3265 return STATUS_INSUFFICIENT_RESOURCES
;
3268 if (RegistryHive
->BlockListSize
> 0)
3270 RtlCopyMemory (BlockList
,
3271 RegistryHive
->BlockList
,
3272 sizeof(BLOCK_LIST_ENTRY
) * RegistryHive
->BlockListSize
);
3273 ExFreePool(RegistryHive
->BlockList
);
3276 RegistryHive
->BlockList
= BlockList
;
3277 for (i
= 0; i
< BlockCount
; i
++)
3279 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Block
=
3280 (PVOID
)((ULONG_PTR
)tmpBin
+ (i
* REG_BLOCK_SIZE
));
3281 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Bin
= tmpBin
;
3283 RegistryHive
->BlockListSize
+= BlockCount
;
3285 /* Initialize a free block in this heap : */
3286 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
3287 tmpBlock
->CellSize
= (BinSize
- REG_HBIN_DATA_OFFSET
);
3289 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3290 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
3292 /* Grow bitmap if necessary */
3293 if (!IsNoFileHive(RegistryHive
) &&
3294 BitmapSize
> RegistryHive
->DirtyBitMap
.SizeOfBitMap
/ 8)
3296 PULONG BitmapBuffer
;
3298 DPRINT("Grow hive bitmap\n");
3300 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
3301 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
3302 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
3304 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
3305 RtlCopyMemory(BitmapBuffer
,
3306 RegistryHive
->DirtyBitMap
.Buffer
,
3307 RegistryHive
->DirtyBitMap
.SizeOfBitMap
/ 8);
3308 ExFreePool(RegistryHive
->BitmapBuffer
);
3309 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
3310 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
3311 RegistryHive
->BitmapBuffer
,
3315 *NewBlock
= (PVOID
) tmpBlock
;
3318 *NewBlockOffset
= tmpBin
->BinOffset
+ REG_HBIN_DATA_OFFSET
;
3320 /* Mark new bin dirty */
3321 CmiMarkBinDirty(RegistryHive
,
3324 return STATUS_SUCCESS
;
3329 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
3332 BLOCK_OFFSET
*CellOffset
)
3334 PCELL_HEADER NewCell
;
3340 /* Round to 16 bytes multiple */
3341 CellSize
= ROUND_UP(CellSize
, 16);
3343 /* Handle volatile hives first */
3344 if (IsPointerHive(RegistryHive
))
3346 NewCell
= ExAllocatePool(NonPagedPool
, CellSize
);
3347 if (NewCell
== NULL
)
3349 return STATUS_INSUFFICIENT_RESOURCES
;
3352 RtlZeroMemory (NewCell
,
3354 NewCell
->CellSize
= -CellSize
;
3357 if (CellOffset
!= NULL
)
3358 *CellOffset
= (BLOCK_OFFSET
) NewCell
;
3362 /* first search in free blocks */
3364 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3366 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
3368 NewCell
= RegistryHive
->FreeList
[i
];
3369 if (CellOffset
!= NULL
)
3370 *CellOffset
= RegistryHive
->FreeListOffset
[i
];
3372 /* Update time of heap */
3373 Temp
= CmiGetCell (RegistryHive
,
3374 RegistryHive
->FreeListOffset
[i
],
3378 DPRINT("CmiGetBlock() failed\n");
3379 return STATUS_UNSUCCESSFUL
;
3382 KeQuerySystemTime(&Bin
->DateModified
);
3383 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
3385 if ((i
+ 1) < RegistryHive
->FreeListSize
)
3387 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
3388 &RegistryHive
->FreeList
[i
+ 1],
3389 sizeof(RegistryHive
->FreeList
[0])
3390 * (RegistryHive
->FreeListSize
- i
- 1));
3391 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
3392 &RegistryHive
->FreeListOffset
[i
+ 1],
3393 sizeof(RegistryHive
->FreeListOffset
[0])
3394 * (RegistryHive
->FreeListSize
- i
- 1));
3396 RegistryHive
->FreeListSize
--;
3401 /* Need to extend hive file : */
3402 if (NewCell
== NULL
)
3405 Status
= CmiAddBin(RegistryHive
,
3406 ((CellSize
+ sizeof(HBIN
) - 1) / REG_BLOCK_SIZE
) + 1,
3409 if (!NT_SUCCESS(Status
))
3415 /* Split the block in two parts */
3416 if (NewCell
->CellSize
> CellSize
)
3418 NewCell
= (PCELL_HEADER
) ((ULONG_PTR
) NewCell
+ CellSize
);
3419 NewCell
->CellSize
= ((PCELL_HEADER
) (*Cell
))->CellSize
- CellSize
;
3420 CmiAddFree(RegistryHive
,
3422 *CellOffset
+ CellSize
,
3424 CmiMarkBlockDirty(RegistryHive
,
3425 *CellOffset
+ CellSize
);
3427 else if (NewCell
->CellSize
< CellSize
)
3429 return STATUS_UNSUCCESSFUL
;
3432 RtlZeroMemory(*Cell
,
3434 ((PCELL_HEADER
) (*Cell
))->CellSize
= -CellSize
;
3437 return STATUS_SUCCESS
;
3442 CmiDestroyCell (PREGISTRY_HIVE RegistryHive
,
3444 BLOCK_OFFSET CellOffset
)
3449 Status
= STATUS_SUCCESS
;
3451 if (IsPointerHive(RegistryHive
))
3457 PCELL_HEADER pFree
= Cell
;
3459 if (pFree
->CellSize
< 0)
3460 pFree
->CellSize
= -pFree
->CellSize
;
3462 /* Clear block (except the block size) */
3463 RtlZeroMemory(((char*)pFree
) + sizeof(ULONG
),
3464 pFree
->CellSize
- sizeof(ULONG
));
3466 /* Add block to the list of free blocks */
3467 CmiAddFree(RegistryHive
, Cell
, CellOffset
, TRUE
);
3469 /* Update time of heap */
3470 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, CellOffset
,&pBin
))
3471 KeQuerySystemTime(&pBin
->DateModified
);
3473 CmiMarkBlockDirty(RegistryHive
, CellOffset
);
3481 CmiGetCell (PREGISTRY_HIVE RegistryHive
,
3482 BLOCK_OFFSET CellOffset
,
3492 if (CellOffset
== (BLOCK_OFFSET
)-1)
3497 if (IsPointerHive (RegistryHive
))
3499 return (PVOID
)CellOffset
;
3502 if (CellOffset
> RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
)
3504 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3505 CellOffset
, RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
);
3509 pBin
= RegistryHive
->BlockList
[CellOffset
/ REG_BLOCK_SIZE
].Bin
;
3520 return((PVOID
)((ULONG_PTR
)pBin
+ (CellOffset
- pBin
->BinOffset
)));
3525 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3526 PCELL_HEADER FreeBlock
,
3527 BLOCK_OFFSET FreeOffset
)
3529 BLOCK_OFFSET BlockOffset
;
3530 BLOCK_OFFSET BinOffset
;
3536 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3537 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3539 CmiGetCell (RegistryHive
,
3542 DPRINT("Bin %p\n", Bin
);
3546 BinOffset
= Bin
->BinOffset
;
3547 BinSize
= Bin
->BinSize
;
3548 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3550 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3552 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3553 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3554 if (BlockOffset
> BinOffset
&&
3555 BlockOffset
< BinOffset
+ BinSize
)
3557 DPRINT("Free block: Offset %lx Size %lx\n",
3558 BlockOffset
, BlockSize
);
3560 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3561 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3562 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3564 DPRINT("Merge current block with previous and next block\n");
3566 RegistryHive
->FreeList
[i
]->CellSize
+=
3567 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3569 FreeBlock
->CellSize
= 0;
3570 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3573 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3575 RtlMoveMemory(&RegistryHive
->FreeList
[i
+ 1],
3576 &RegistryHive
->FreeList
[i
+ 2],
3577 sizeof(RegistryHive
->FreeList
[0])
3578 * (RegistryHive
->FreeListSize
- i
- 2));
3579 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3580 &RegistryHive
->FreeListOffset
[i
+ 2],
3581 sizeof(RegistryHive
->FreeListOffset
[0])
3582 * (RegistryHive
->FreeListSize
- i
- 2));
3584 RegistryHive
->FreeListSize
--;
3586 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3590 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3592 DPRINT("Merge current block with previous block\n");
3594 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3595 FreeBlock
->CellSize
= 0;
3597 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3601 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3603 DPRINT("Merge current block with next block\n");
3605 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3606 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3607 RegistryHive
->FreeList
[i
] = FreeBlock
;
3608 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3610 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3622 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3623 PCELL_HEADER FreeBlock
,
3624 BLOCK_OFFSET FreeOffset
,
3625 BOOLEAN MergeFreeBlocks
)
3627 PCELL_HEADER
*tmpList
;
3628 BLOCK_OFFSET
*tmpListOffset
;
3633 ASSERT(RegistryHive
);
3636 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3637 FreeBlock
, FreeOffset
);
3639 /* Merge free blocks */
3640 if (MergeFreeBlocks
== TRUE
)
3642 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3643 return(STATUS_SUCCESS
);
3646 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3648 tmpList
= ExAllocatePool(PagedPool
,
3649 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3650 if (tmpList
== NULL
)
3651 return STATUS_INSUFFICIENT_RESOURCES
;
3653 tmpListOffset
= ExAllocatePool(PagedPool
,
3654 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3656 if (tmpListOffset
== NULL
)
3658 ExFreePool(tmpList
);
3659 return STATUS_INSUFFICIENT_RESOURCES
;
3662 if (RegistryHive
->FreeListMax
)
3664 RtlMoveMemory(tmpList
,
3665 RegistryHive
->FreeList
,
3666 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3667 RtlMoveMemory(tmpListOffset
,
3668 RegistryHive
->FreeListOffset
,
3669 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3670 ExFreePool(RegistryHive
->FreeList
);
3671 ExFreePool(RegistryHive
->FreeListOffset
);
3673 RegistryHive
->FreeList
= tmpList
;
3674 RegistryHive
->FreeListOffset
= tmpListOffset
;
3675 RegistryHive
->FreeListMax
+= 32;
3678 /* Add new offset to free list, maintaining list in ascending order */
3679 if ((RegistryHive
->FreeListSize
== 0)
3680 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3682 /* Add to end of list */
3683 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3684 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3686 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3688 /* Add to begin of list */
3689 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3690 &RegistryHive
->FreeList
[0],
3691 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3692 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3693 &RegistryHive
->FreeListOffset
[0],
3694 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3695 RegistryHive
->FreeList
[0] = FreeBlock
;
3696 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3697 RegistryHive
->FreeListSize
++;
3701 /* Search where to insert */
3703 maxInd
= RegistryHive
->FreeListSize
- 1;
3704 while ((maxInd
- minInd
) > 1)
3706 medInd
= (minInd
+ maxInd
) / 2;
3707 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3713 /* Insert before maxInd */
3714 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3715 &RegistryHive
->FreeList
[maxInd
],
3716 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3717 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3718 &RegistryHive
->FreeListOffset
[maxInd
],
3719 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3720 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3721 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3722 RegistryHive
->FreeListSize
++;
3725 return STATUS_SUCCESS
;
3730 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3731 BLOCK_OFFSET BlockOffset
)
3738 if (IsNoFileHive(RegistryHive
))
3741 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3743 BlockNumber
= (ULONG
)BlockOffset
/ REG_BLOCK_SIZE
;
3745 Cell
= CmiGetCell (RegistryHive
,
3749 CellSize
= Cell
->CellSize
;
3751 CellSize
= -CellSize
;
3753 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, REG_BLOCK_SIZE
) -
3754 ROUND_DOWN(BlockOffset
, REG_BLOCK_SIZE
)) / REG_BLOCK_SIZE
;
3756 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3759 (Cell
->CellSize
< 0) ? "used" : "free",
3762 RegistryHive
->HiveDirty
= TRUE
;
3763 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3770 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3771 BLOCK_OFFSET BinOffset
)
3777 if (IsNoFileHive(RegistryHive
))
3780 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3782 BlockNumber
= (ULONG
)BinOffset
/ REG_BLOCK_SIZE
;
3784 Bin
= RegistryHive
->BlockList
[BlockNumber
].Bin
;
3786 BlockCount
= Bin
->BinSize
/ REG_BLOCK_SIZE
;
3788 DPRINT(" BlockNumber %lu BinSize %lu BlockCount %lu\n",
3793 RegistryHive
->HiveDirty
= TRUE
;
3794 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3801 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3802 OUT PBOOLEAN Packable
)
3806 if (Packable
!= NULL
)
3809 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3811 if (Name
->Buffer
[i
] & 0xFF00)
3813 if (Packable
!= NULL
)
3815 return Name
->Length
;
3819 return (Name
->Length
/ sizeof(WCHAR
));
3824 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3825 IN PUCHAR NameBuffer
,
3826 IN USHORT NameBufferSize
,
3827 IN BOOLEAN NamePacked
)
3832 if (NamePacked
== TRUE
)
3834 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3837 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3839 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3845 if (Name
->Length
!= NameBufferSize
)
3848 UNameBuffer
= (PWCHAR
)NameBuffer
;
3850 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3852 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3862 CmiCopyPackedName(PWCHAR NameBuffer
,
3863 PUCHAR PackedNameBuffer
,
3864 ULONG PackedNameSize
)
3868 for (i
= 0; i
< PackedNameSize
; i
++)
3869 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];
3874 CmiCompareHash(PUNICODE_STRING KeyName
,
3879 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3880 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3881 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3882 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3884 return (strncmp(Buffer
, HashString
, 4) == 0);
3889 CmiCompareHashI(PUNICODE_STRING KeyName
,
3894 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3895 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3896 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3897 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3899 return (_strnicmp(Buffer
, HashString
, 4) == 0);
3904 CmiCompareKeyNames(PUNICODE_STRING KeyName
,
3910 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3912 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3914 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3917 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3919 if (KeyName
->Buffer
[i
] != (WCHAR
)KeyCell
->Name
[i
])
3925 if (KeyName
->Length
!= KeyCell
->NameSize
)
3928 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3929 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3931 if (KeyName
->Buffer
[i
] != UnicodeName
[i
])
3941 CmiCompareKeyNamesI(PUNICODE_STRING KeyName
,
3947 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3949 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3951 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3954 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3956 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3957 RtlUpcaseUnicodeChar((WCHAR
)KeyCell
->Name
[i
]))
3963 if (KeyName
->Length
!= KeyCell
->NameSize
)
3966 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3967 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3969 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3970 RtlUpcaseUnicodeChar(UnicodeName
[i
]))
3980 CmiCopyKey (PREGISTRY_HIVE DstHive
,
3981 PKEY_CELL DstKeyCell
,
3982 PREGISTRY_HIVE SrcHive
,
3983 PKEY_CELL SrcKeyCell
)
3985 PKEY_CELL NewKeyCell
;
3986 ULONG NewKeyCellSize
;
3987 BLOCK_OFFSET NewKeyCellOffset
;
3988 PHASH_TABLE_CELL NewHashTableCell
;
3989 ULONG NewHashTableSize
;
3990 BLOCK_OFFSET NewHashTableOffset
;
3994 DPRINT ("CmiCopyKey() called\n");
3996 if (DstKeyCell
== NULL
)
3998 /* Allocate and copy key cell */
3999 NewKeyCellSize
= sizeof(KEY_CELL
) + SrcKeyCell
->NameSize
;
4000 Status
= CmiAllocateCell (DstHive
,
4002 (PVOID
) &NewKeyCell
,
4004 if (!NT_SUCCESS(Status
))
4006 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4009 if (NewKeyCell
== NULL
)
4011 DPRINT1 ("Failed to allocate a key cell\n");
4012 return STATUS_INSUFFICIENT_RESOURCES
;
4015 RtlCopyMemory (NewKeyCell
,
4019 DstHive
->HiveHeader
->RootKeyOffset
= NewKeyCellOffset
;
4021 /* Copy class name */
4022 if (SrcKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4024 PDATA_CELL SrcClassNameCell
;
4025 PDATA_CELL NewClassNameCell
;
4026 BLOCK_OFFSET NewClassNameOffset
;
4028 SrcClassNameCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ClassNameOffset
, NULL
),
4030 NewKeyCell
->ClassSize
= SrcKeyCell
->ClassSize
;
4031 Status
= CmiAllocateCell (DstHive
,
4032 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
4033 (PVOID
)&NewClassNameCell
,
4034 &NewClassNameOffset
);
4035 if (!NT_SUCCESS(Status
))
4037 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4041 RtlCopyMemory (NewClassNameCell
,
4043 NewKeyCell
->ClassSize
);
4044 NewKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4049 NewKeyCell
= DstKeyCell
;
4052 /* Allocate hash table */
4053 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4055 NewHashTableSize
= ROUND_UP(SrcKeyCell
->NumberOfSubKeys
+ 1, 4) - 1;
4056 Status
= CmiAllocateHashTableCell (DstHive
,
4058 &NewHashTableOffset
,
4060 if (!NT_SUCCESS(Status
))
4062 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status
);
4065 NewKeyCell
->HashTableOffset
= NewHashTableOffset
;
4069 NewHashTableCell
= NULL
;
4072 /* Allocate and copy value list and values */
4073 if (SrcKeyCell
->NumberOfValues
!= 0)
4075 PVALUE_LIST_CELL NewValueListCell
;
4076 PVALUE_LIST_CELL SrcValueListCell
;
4077 PVALUE_CELL NewValueCell
;
4078 PVALUE_CELL SrcValueCell
;
4079 PDATA_CELL SrcValueDataCell
;
4080 PDATA_CELL NewValueDataCell
;
4081 BLOCK_OFFSET ValueCellOffset
;
4082 BLOCK_OFFSET ValueDataCellOffset
;
4083 ULONG NewValueListCellSize
;
4084 ULONG NewValueCellSize
;
4087 NewValueListCellSize
=
4088 ROUND_UP(SrcKeyCell
->NumberOfValues
, 4) * sizeof(BLOCK_OFFSET
);
4089 Status
= CmiAllocateCell (DstHive
,
4090 NewValueListCellSize
,
4091 (PVOID
)&NewValueListCell
,
4092 &NewKeyCell
->ValueListOffset
);
4093 if (!NT_SUCCESS(Status
))
4095 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4099 RtlZeroMemory (NewValueListCell
,
4100 NewValueListCellSize
);
4103 SrcValueListCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ValueListOffset
, NULL
);
4104 for (i
= 0; i
< SrcKeyCell
->NumberOfValues
; i
++)
4106 /* Copy value cell */
4107 SrcValueCell
= CmiGetCell (SrcHive
, SrcValueListCell
->ValueOffset
[i
], NULL
);
4109 NewValueCellSize
= sizeof(VALUE_CELL
) + SrcValueCell
->NameSize
;
4110 Status
= CmiAllocateCell (DstHive
,
4112 (PVOID
*) &NewValueCell
,
4114 if (!NT_SUCCESS(Status
))
4116 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4120 NewValueListCell
->ValueOffset
[i
] = ValueCellOffset
;
4121 RtlCopyMemory (NewValueCell
,
4125 /* Copy value data cell */
4126 if (SrcValueCell
->DataSize
> (LONG
) sizeof(PVOID
))
4128 SrcValueDataCell
= CmiGetCell (SrcHive
, SrcValueCell
->DataOffset
, NULL
);
4130 Status
= CmiAllocateCell (DstHive
,
4131 sizeof(CELL_HEADER
) + SrcValueCell
->DataSize
,
4132 (PVOID
*) &NewValueDataCell
,
4133 &ValueDataCellOffset
);
4134 if (!NT_SUCCESS(Status
))
4136 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4139 RtlCopyMemory (NewValueDataCell
,
4141 SrcValueCell
->DataSize
);
4142 NewValueCell
->DataOffset
= ValueDataCellOffset
;
4148 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4150 PHASH_TABLE_CELL SrcHashTableCell
;
4151 PKEY_CELL SrcSubKeyCell
;
4152 PKEY_CELL NewSubKeyCell
;
4153 ULONG NewSubKeyCellSize
;
4154 BLOCK_OFFSET NewSubKeyCellOffset
;
4155 PHASH_RECORD SrcHashRecord
;
4157 SrcHashTableCell
= CmiGetCell (SrcHive
,
4158 SrcKeyCell
->HashTableOffset
,
4161 for (i
= 0; i
< SrcKeyCell
->NumberOfSubKeys
; i
++)
4163 SrcHashRecord
= &SrcHashTableCell
->Table
[i
];
4164 SrcSubKeyCell
= CmiGetCell (SrcHive
, SrcHashRecord
->KeyOffset
, NULL
);
4166 /* Allocate and copy key cell */
4167 NewSubKeyCellSize
= sizeof(KEY_CELL
) + SrcSubKeyCell
->NameSize
;
4168 Status
= CmiAllocateCell (DstHive
,
4170 (PVOID
)&NewSubKeyCell
,
4171 &NewSubKeyCellOffset
);
4172 if (!NT_SUCCESS(Status
))
4174 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4177 if (NewKeyCell
== NULL
)
4179 DPRINT1 ("Failed to allocate a sub key cell\n");
4180 return STATUS_INSUFFICIENT_RESOURCES
;
4183 NewHashTableCell
->Table
[i
].KeyOffset
= NewSubKeyCellOffset
;
4184 NewHashTableCell
->Table
[i
].HashValue
= SrcHashRecord
->HashValue
;
4186 RtlCopyMemory (NewSubKeyCell
,
4190 /* Copy class name */
4191 if (SrcSubKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4193 PDATA_CELL SrcClassNameCell
;
4194 PDATA_CELL NewClassNameCell
;
4195 BLOCK_OFFSET NewClassNameOffset
;
4197 SrcClassNameCell
= CmiGetCell (SrcHive
,
4198 SrcSubKeyCell
->ClassNameOffset
,
4201 NewSubKeyCell
->ClassSize
= SrcSubKeyCell
->ClassSize
;
4202 Status
= CmiAllocateCell (DstHive
,
4203 sizeof(CELL_HEADER
) + NewSubKeyCell
->ClassSize
,
4204 (PVOID
)&NewClassNameCell
,
4205 &NewClassNameOffset
);
4206 if (!NT_SUCCESS(Status
))
4208 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4212 NewSubKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4213 RtlCopyMemory (NewClassNameCell
,
4215 NewSubKeyCell
->ClassSize
);
4218 /* Copy subkey data and subkeys */
4219 Status
= CmiCopyKey (DstHive
,
4223 if (!NT_SUCCESS(Status
))
4225 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4231 return STATUS_SUCCESS
;
4236 CmiSaveTempHive (PREGISTRY_HIVE Hive
,
4239 IO_STATUS_BLOCK IoStatusBlock
;
4240 LARGE_INTEGER FileOffset
;
4245 DPRINT ("CmiSaveTempHive() called\n");
4247 Hive
->HiveHeader
->Checksum
= CmiCalcChecksum ((PULONG
)Hive
->HiveHeader
);
4249 /* Write hive block */
4250 FileOffset
.QuadPart
= (ULONGLONG
)0;
4251 Status
= ZwWriteFile (FileHandle
,
4257 sizeof(HIVE_HEADER
),
4260 if (!NT_SUCCESS(Status
))
4262 DPRINT1 ("ZwWriteFile() failed (Status %lx)\n", Status
);
4266 DPRINT ("Saving %lu blocks\n", Hive
->BlockListSize
);
4267 for (BlockIndex
= 0; BlockIndex
< Hive
->BlockListSize
; BlockIndex
++)
4269 BlockPtr
= Hive
->BlockList
[BlockIndex
].Block
;
4270 DPRINT ("BlockPtr %p\n", BlockPtr
);
4272 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
4273 DPRINT ("File offset %I64x\n", FileOffset
.QuadPart
);
4275 /* Write hive block */
4276 Status
= ZwWriteFile (FileHandle
,
4285 if (!NT_SUCCESS(Status
))
4287 DPRINT1 ("ZwWriteFile() failed (Status %lx)\n", Status
);
4292 Status
= ZwFlushBuffersFile (FileHandle
,
4294 if (!NT_SUCCESS(Status
))
4296 DPRINT1 ("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
4299 DPRINT ("CmiSaveTempHive() done\n");