2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/regfile.c
5 * PURPOSE: Registry file manipulation routines
11 #include <internal/debug.h>
16 /* uncomment to enable hive checks (incomplete and probably buggy) */
19 /* LOCAL MACROS *************************************************************/
21 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
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;
47 Header
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
48 Header
->BlockSize
= REG_BLOCK_SIZE
;
55 CmiCreateDefaultBinHeader(PHBIN BinHeader
)
58 RtlZeroMemory(BinHeader
, sizeof(HBIN
));
59 BinHeader
->HeaderId
= REG_BIN_ID
;
60 BinHeader
->DateModified
.u
.LowPart
= 0;
61 BinHeader
->DateModified
.u
.HighPart
= 0;
62 BinHeader
->BinSize
= REG_BLOCK_SIZE
;
67 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
)
70 RtlZeroMemory(RootKeyCell
, sizeof(KEY_CELL
));
71 RootKeyCell
->CellSize
= -sizeof(KEY_CELL
);
72 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
73 RootKeyCell
->Flags
= REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
;
74 NtQuerySystemTime(&RootKeyCell
->LastWriteTime
);
75 RootKeyCell
->ParentKeyOffset
= 0;
76 RootKeyCell
->NumberOfSubKeys
= 0;
77 RootKeyCell
->HashTableOffset
= -1;
78 RootKeyCell
->NumberOfValues
= 0;
79 RootKeyCell
->ValueListOffset
= -1;
80 RootKeyCell
->SecurityKeyOffset
= 0;
81 RootKeyCell
->ClassNameOffset
= -1;
82 RootKeyCell
->NameSize
= 0;
83 RootKeyCell
->ClassSize
= 0;
88 CmiVerifyBinHeader(PHBIN BinHeader
)
95 if (BinHeader
->HeaderId
!= REG_BIN_ID
)
97 DbgPrint("Bin header ID is %.08x (should be %.08x)\n",
98 BinHeader
->HeaderId
, REG_BIN_ID
);
99 ASSERT(BinHeader
->HeaderId
== REG_BIN_ID
);
102 //BinHeader->DateModified.dwLowDateTime
104 //BinHeader->DateModified.dwHighDateTime
107 if (BinHeader
->BinSize
!= REG_BLOCK_SIZE
)
109 DbgPrint("BinSize is %.08x (should be a multiple of %.08x)\n",
110 BinHeader
->BinSize
, REG_BLOCK_SIZE
);
111 ASSERT(BinHeader
->BinSize
% REG_BLOCK_SIZE
== 0);
119 CmiVerifyKeyCell(PKEY_CELL KeyCell
)
126 if (KeyCell
->CellSize
== 0)
128 DbgPrint("CellSize is %d (must not be 0)\n",
130 ASSERT(KeyCell
->CellSize
!= 0);
133 if (KeyCell
->Id
!= REG_KEY_CELL_ID
)
135 DbgPrint("Id is %.08x (should be %.08x)\n",
136 KeyCell
->Id
, REG_KEY_CELL_ID
);
137 ASSERT(KeyCell
->Id
== REG_KEY_CELL_ID
);
142 //KeyCell->LastWriteTime;
144 if (KeyCell
->ParentKeyOffset
< 0)
146 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
147 KeyCell
->ParentKeyOffset
);
148 ASSERT(KeyCell
->ParentKeyOffset
>= 0);
151 if (KeyCell
->NumberOfSubKeys
< 0)
153 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
154 KeyCell
->NumberOfSubKeys
);
155 ASSERT(KeyCell
->NumberOfSubKeys
>= 0);
158 //KeyCell->HashTableOffset;
160 if (KeyCell
->NumberOfValues
< 0)
162 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
163 KeyCell
->NumberOfValues
);
164 ASSERT(KeyCell
->NumberOfValues
>= 0);
167 //KeyCell->ValuesOffset = -1;
169 if (KeyCell
->SecurityKeyOffset
< 0)
171 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
172 KeyCell
->SecurityKeyOffset
);
173 ASSERT(KeyCell
->SecurityKeyOffset
>= 0);
176 //KeyCell->ClassNameOffset = -1;
187 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell
)
192 CmiVerifyKeyCell(RootKeyCell
);
194 if (!(RootKeyCell
->Flags
& REG_KEY_ROOT_CELL
))
196 DbgPrint("Flags is %.08x (should be %.08x)\n",
197 RootKeyCell
->Flags
, REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
);
198 ASSERT(!(RootKeyCell
->Flags
& (REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
)));
206 CmiVerifyValueCell(PVALUE_CELL ValueCell
)
213 if (ValueCell
->CellSize
== 0)
215 DbgPrint("CellSize is %d (must not be 0)\n",
216 ValueCell
->CellSize
);
217 ASSERT(ValueCell
->CellSize
!= 0);
220 if (ValueCell
->Id
!= REG_VALUE_CELL_ID
)
222 DbgPrint("Id is %.08x (should be %.08x)\n",
223 ValueCell
->Id
, REG_VALUE_CELL_ID
);
224 ASSERT(ValueCell
->Id
== REG_VALUE_CELL_ID
);
227 //ValueCell->NameSize;
228 //ValueCell->LONG DataSize;
229 //ValueCell->DataOffset;
230 //ValueCell->ULONG DataType;
231 //ValueCell->USHORT Flags;
232 //ValueCell->USHORT Unused1;
233 //ValueCell->UCHAR Name[0];
239 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell
)
244 if (ValueListCell
->CellSize
== 0)
246 DbgPrint("CellSize is %d (must not be 0)\n",
247 ValueListCell
->CellSize
);
248 ASSERT(ValueListCell
->CellSize
!= 0);
256 CmiVerifyKeyObject(PKEY_OBJECT KeyObject
)
261 if (KeyObject
->RegistryHive
== NULL
)
263 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
264 KeyObject
->RegistryHive
);
265 ASSERT(KeyObject
->RegistryHive
!= NULL
);
268 if (KeyObject
->KeyCell
== NULL
)
270 DbgPrint("KeyCell is NULL (must not be NULL)\n",
272 ASSERT(KeyObject
->KeyCell
!= NULL
);
275 if (KeyObject
->ParentKey
== NULL
)
277 DbgPrint("ParentKey is NULL (must not be NULL)\n",
278 KeyObject
->ParentKey
);
279 ASSERT(KeyObject
->ParentKey
!= NULL
);
287 CmiVerifyHiveHeader(PHIVE_HEADER Header
)
292 if (Header
->BlockId
!= REG_HIVE_ID
)
294 DbgPrint("BlockId is %.08x (must be %.08x)\n",
297 ASSERT(Header
->BlockId
== REG_HIVE_ID
);
300 if (Header
->Unused3
!= 1)
302 DbgPrint("Unused3 is %.08x (must be 1)\n",
304 ASSERT(Header
->Unused3
== 1);
307 if (Header
->Unused4
!= 3)
309 DbgPrint("Unused4 is %.08x (must be 3)\n",
311 ASSERT(Header
->Unused4
== 3);
314 if (Header
->Unused5
!= 0)
316 DbgPrint("Unused5 is %.08x (must be 0)\n",
318 ASSERT(Header
->Unused5
== 0);
321 if (Header
->Unused6
!= 1)
323 DbgPrint("Unused6 is %.08x (must be 1)\n",
325 ASSERT(Header
->Unused6
== 1);
328 if (Header
->Unused7
!= 1)
330 DbgPrint("Unused7 is %.08x (must be 1)\n",
332 ASSERT(Header
->Unused7
== 1);
340 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive
)
345 CmiVerifyHiveHeader(RegistryHive
->HiveHeader
);
352 CmiCreateNewRegFile(HANDLE FileHandle
)
354 IO_STATUS_BLOCK IoStatusBlock
;
355 PCELL_HEADER FreeCell
;
356 PHIVE_HEADER HiveHeader
;
357 PKEY_CELL RootKeyCell
;
362 Buffer
= (PCHAR
) ExAllocatePool(NonPagedPool
, 2 * REG_BLOCK_SIZE
);
364 return STATUS_INSUFFICIENT_RESOURCES
;
366 RtlZeroMemory (Buffer
,
369 HiveHeader
= (PHIVE_HEADER
)Buffer
;
370 BinHeader
= (PHBIN
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
);
371 RootKeyCell
= (PKEY_CELL
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
);
372 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
374 CmiCreateDefaultHiveHeader(HiveHeader
);
375 CmiCreateDefaultBinHeader(BinHeader
);
376 CmiCreateDefaultRootKeyCell(RootKeyCell
);
379 BinHeader
->BinOffset
= 0;
381 /* Offset to root key block */
382 HiveHeader
->RootKeyOffset
= REG_HBIN_DATA_OFFSET
;
384 /* The rest of the block is free */
385 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
387 Status
= NtWriteFile(FileHandle
,
399 ASSERTMSG(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
401 if (!NT_SUCCESS(Status
))
406 Status
= NtFlushBuffersFile(FileHandle
,
415 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive
)
417 OBJECT_ATTRIBUTES ObjectAttributes
;
418 FILE_STANDARD_INFORMATION fsi
;
419 IO_STATUS_BLOCK IoStatusBlock
;
420 HANDLE HiveHandle
= INVALID_HANDLE_VALUE
;
421 HANDLE LogHandle
= INVALID_HANDLE_VALUE
;
422 PHIVE_HEADER HiveHeader
= NULL
;
423 PHIVE_HEADER LogHeader
= NULL
;
424 LARGE_INTEGER FileOffset
;
428 RTL_BITMAP BlockBitMap
;
431 DPRINT("CmiCheckAndFixHive() called\n");
433 /* Try to open the hive file */
434 InitializeObjectAttributes(&ObjectAttributes
,
435 &RegistryHive
->HiveFileName
,
436 OBJ_CASE_INSENSITIVE
,
440 Status
= ZwCreateFile(&HiveHandle
,
441 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
445 FILE_ATTRIBUTE_NORMAL
,
448 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
451 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
453 return(STATUS_SUCCESS
);
455 if (!NT_SUCCESS(Status
))
457 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
461 /* Try to open the log file */
462 InitializeObjectAttributes(&ObjectAttributes
,
463 &RegistryHive
->LogFileName
,
464 OBJ_CASE_INSENSITIVE
,
468 Status
= ZwCreateFile(&LogHandle
,
469 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
473 FILE_ATTRIBUTE_NORMAL
,
476 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
479 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
481 LogHandle
= INVALID_HANDLE_VALUE
;
483 else if (!NT_SUCCESS(Status
))
485 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
490 /* Allocate hive header */
491 HiveHeader
= ExAllocatePool(PagedPool
,
492 sizeof(HIVE_HEADER
));
493 if (HiveHeader
== NULL
)
495 DPRINT("ExAllocatePool() failed\n");
496 Status
= STATUS_INSUFFICIENT_RESOURCES
;
500 /* Read hive base block */
501 FileOffset
.QuadPart
= 0ULL;
502 Status
= NtReadFile(HiveHandle
,
511 if (!NT_SUCCESS(Status
))
513 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
517 if (LogHandle
== INVALID_HANDLE_VALUE
)
519 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
520 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
522 /* There is no way to fix the hive without log file - BSOD! */
523 DPRINT("Hive header inconsistent and no log file available!\n");
524 KEBUGCHECK(CONFIG_LIST_FAILED
);
527 Status
= STATUS_SUCCESS
;
532 /* Allocate hive header */
533 LogHeader
= ExAllocatePool(PagedPool
,
534 sizeof(HIVE_HEADER
));
535 if (LogHeader
== NULL
)
537 DPRINT("ExAllocatePool() failed\n");
538 Status
= STATUS_INSUFFICIENT_RESOURCES
;
542 /* Read log file header */
543 FileOffset
.QuadPart
= 0ULL;
544 Status
= NtReadFile(LogHandle
,
553 if (!NT_SUCCESS(Status
))
555 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
559 /* Check log file header integrity */
560 if (LogHeader
->Checksum
!= CmiCalcChecksum((PULONG
)LogHeader
) ||
561 LogHeader
->UpdateCounter1
!= LogHeader
->UpdateCounter2
)
563 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
564 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
566 DPRINT("Hive file and log file are inconsistent!\n");
567 KEBUGCHECK(CONFIG_LIST_FAILED
);
570 /* Log file damaged but hive is okay */
571 Status
= STATUS_SUCCESS
;
575 if (HiveHeader
->UpdateCounter1
== HiveHeader
->UpdateCounter2
&&
576 HiveHeader
->UpdateCounter1
== LogHeader
->UpdateCounter1
)
578 /* Hive and log file are up-to-date */
579 Status
= STATUS_SUCCESS
;
584 * Hive needs an update!
588 Status
= NtQueryInformationFile(LogHandle
,
592 FileStandardInformation
);
593 if (!NT_SUCCESS(Status
))
595 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
598 FileSize
= fsi
.EndOfFile
.u
.LowPart
;
600 /* Calculate bitmap and block size */
601 BitmapSize
= ROUND_UP((FileSize
/ REG_BLOCK_SIZE
) - 1, sizeof(ULONG
) * 8) / 8;
602 BufferSize
= sizeof(HIVE_HEADER
) +
605 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
607 /* Reallocate log header block */
608 ExFreePool(LogHeader
);
609 LogHeader
= ExAllocatePool(PagedPool
,
611 if (LogHeader
== NULL
)
613 DPRINT("ExAllocatePool() failed\n");
614 Status
= STATUS_INSUFFICIENT_RESOURCES
;
618 /* Read log file header */
619 FileOffset
.QuadPart
= 0ULL;
620 Status
= NtReadFile(LogHandle
,
629 if (!NT_SUCCESS(Status
))
631 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
635 /* Initialize bitmap */
636 RtlInitializeBitMap(&BlockBitMap
,
637 (PVOID
)((ULONG_PTR
)LogHeader
+ REG_BLOCK_SIZE
+ sizeof(ULONG
)),
640 /* FIXME: Update dirty blocks */
643 /* FIXME: Update hive header */
646 Status
= STATUS_SUCCESS
;
650 /* Clean up the mess */
652 if (HiveHeader
!= NULL
)
653 ExFreePool(HiveHeader
);
655 if (LogHeader
!= NULL
)
656 ExFreePool(LogHeader
);
658 if (LogHandle
!= INVALID_HANDLE_VALUE
)
669 CmiImportHiveBins(PREGISTRY_HIVE Hive
,
672 BLOCK_OFFSET BlockOffset
;
679 while (BlockIndex
< Hive
->BlockListSize
)
681 Bin
= (PHBIN
)((ULONG_PTR
)ChunkPtr
+ BlockOffset
);
683 if (Bin
->HeaderId
!= REG_BIN_ID
)
685 DPRINT1 ("Bad bin header id %x, offset %x\n", Bin
->HeaderId
, BlockOffset
);
686 return STATUS_REGISTRY_CORRUPT
;
689 ASSERTMSG((Bin
->BinSize
% REG_BLOCK_SIZE
) == 0,
690 ("Bin size (0x%.08x) must be multiple of 4K\n",
693 /* Allocate the hive block */
694 Hive
->BlockList
[BlockIndex
].Bin
= ExAllocatePool (PagedPool
,
696 if (Hive
->BlockList
[BlockIndex
].Bin
== NULL
)
698 DPRINT1 ("ExAllocatePool() failed\n");
699 return STATUS_INSUFFICIENT_RESOURCES
;
701 Hive
->BlockList
[BlockIndex
].Block
= (PVOID
)Hive
->BlockList
[BlockIndex
].Bin
;
704 RtlCopyMemory (Hive
->BlockList
[BlockIndex
].Bin
,
708 if (Bin
->BinSize
> REG_BLOCK_SIZE
)
710 for (j
= 1; j
< Bin
->BinSize
/ REG_BLOCK_SIZE
; j
++)
712 Hive
->BlockList
[BlockIndex
+ j
].Bin
= Hive
->BlockList
[BlockIndex
].Bin
;
713 Hive
->BlockList
[BlockIndex
+ j
].Block
=
714 (PVOID
)((ULONG_PTR
)Hive
->BlockList
[BlockIndex
].Bin
+ (j
* REG_BLOCK_SIZE
));
718 BlockIndex
+= Bin
->BinSize
/ REG_BLOCK_SIZE
;
719 BlockOffset
+= Bin
->BinSize
;
722 return STATUS_SUCCESS
;
727 CmiFreeHiveBins (PREGISTRY_HIVE Hive
)
733 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
735 if (Hive
->BlockList
[i
].Bin
== NULL
)
738 if (Hive
->BlockList
[i
].Bin
!= Bin
)
740 Bin
= Hive
->BlockList
[i
].Bin
;
741 ExFreePool (Hive
->BlockList
[i
].Bin
);
743 Hive
->BlockList
[i
].Bin
= NULL
;
744 Hive
->BlockList
[i
].Block
= NULL
;
750 CmiCreateHiveFreeCellList(PREGISTRY_HIVE Hive
)
752 BLOCK_OFFSET BlockOffset
;
753 PCELL_HEADER FreeBlock
;
759 /* Initialize the free cell list */
760 Hive
->FreeListSize
= 0;
761 Hive
->FreeListMax
= 0;
762 Hive
->FreeList
= NULL
;
763 Hive
->FreeListOffset
= NULL
;
767 while (BlockIndex
< Hive
->BlockListSize
)
769 Bin
= Hive
->BlockList
[BlockIndex
].Bin
;
771 /* Search free blocks and add to list */
772 FreeOffset
= REG_HBIN_DATA_OFFSET
;
773 while (FreeOffset
< Bin
->BinSize
)
775 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) Bin
+ FreeOffset
);
776 if (FreeBlock
->CellSize
> 0)
778 Status
= CmiAddFree(Hive
,
780 Bin
->BinOffset
+ FreeOffset
,
783 if (!NT_SUCCESS(Status
))
788 FreeOffset
+= FreeBlock
->CellSize
;
792 FreeOffset
-= FreeBlock
->CellSize
;
796 BlockIndex
+= Bin
->BinSize
/ REG_BLOCK_SIZE
;
797 BlockOffset
+= Bin
->BinSize
;
800 return STATUS_SUCCESS
;
805 CmiFreeHiveFreeCellList(PREGISTRY_HIVE Hive
)
807 ExFreePool (Hive
->FreeList
);
808 ExFreePool (Hive
->FreeListOffset
);
810 Hive
->FreeListSize
= 0;
811 Hive
->FreeListMax
= 0;
812 Hive
->FreeList
= NULL
;
813 Hive
->FreeListOffset
= NULL
;
818 CmiCreateHiveBitmap(PREGISTRY_HIVE Hive
)
822 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
823 BitmapSize
= ROUND_UP(Hive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
824 DPRINT("Hive->BlockListSize: %lu\n", Hive
->BlockListSize
);
825 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
827 /* Allocate bitmap */
828 Hive
->BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
830 if (Hive
->BitmapBuffer
== NULL
)
832 return STATUS_INSUFFICIENT_RESOURCES
;
835 RtlInitializeBitMap(&Hive
->DirtyBitMap
,
839 /* Initialize bitmap */
840 RtlClearAllBits(&Hive
->DirtyBitMap
);
841 Hive
->HiveDirty
= FALSE
;
843 return STATUS_SUCCESS
;
848 CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive
,
851 OBJECT_ATTRIBUTES ObjectAttributes
;
852 ULONG CreateDisposition
;
853 IO_STATUS_BLOCK IoSB
;
855 PSECTION_OBJECT SectionObject
;
860 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) called\n",
861 RegistryHive
, Filename
);
863 /* Duplicate Filename */
864 Status
= RtlCreateUnicodeString(&RegistryHive
->HiveFileName
,
866 if (!NT_SUCCESS(Status
))
868 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status
);
872 /* Create log file name */
873 RegistryHive
->LogFileName
.Length
= (wcslen(Filename
) + 4) * sizeof(WCHAR
);
874 RegistryHive
->LogFileName
.MaximumLength
= RegistryHive
->LogFileName
.Length
+ sizeof(WCHAR
);
875 RegistryHive
->LogFileName
.Buffer
= ExAllocatePool(NonPagedPool
,
876 RegistryHive
->LogFileName
.MaximumLength
);
877 if (RegistryHive
->LogFileName
.Buffer
== NULL
)
879 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
880 DPRINT("ExAllocatePool() failed\n");
881 return(STATUS_INSUFFICIENT_RESOURCES
);
883 wcscpy(RegistryHive
->LogFileName
.Buffer
,
885 wcscat(RegistryHive
->LogFileName
.Buffer
,
889 /* Check and eventually fix a hive */
890 Status
= CmiCheckAndFixHive(RegistryHive
);
891 if (!NT_SUCCESS(Status
))
893 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
894 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
895 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status
);
900 InitializeObjectAttributes(&ObjectAttributes
,
901 &RegistryHive
->HiveFileName
,
902 OBJ_CASE_INSENSITIVE
,
906 CreateDisposition
= FILE_OPEN_IF
;
907 Status
= ZwCreateFile(&FileHandle
,
912 FILE_ATTRIBUTE_NORMAL
,
915 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
918 if (!NT_SUCCESS(Status
))
920 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
921 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
922 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
926 if (IoSB
.Information
!= FILE_OPENED
)
928 Status
= CmiCreateNewRegFile(FileHandle
);
929 if (!NT_SUCCESS(Status
))
931 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status
);
933 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
934 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
939 /* Create the hive section */
940 Status
= MmCreateSection(&SectionObject
,
948 if (!NT_SUCCESS(Status
))
950 DPRINT1("MmCreateSection() failed (Status %lx)\n", Status
);
951 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
952 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
956 /* Map the hive file */
959 Status
= MmMapViewOfSection(SectionObject
,
960 PsGetCurrentProcess(),
969 if (!NT_SUCCESS(Status
))
971 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status
);
972 ObDereferenceObject(SectionObject
);
973 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
974 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
978 DPRINT("ViewBase %p ViewSize %lx\n", ViewBase
, ViewSize
);
980 /* Copy hive header and initalize hive */
981 RtlCopyMemory (RegistryHive
->HiveHeader
,
983 sizeof(HIVE_HEADER
));
984 RegistryHive
->FileSize
= ViewSize
;
985 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ REG_BLOCK_SIZE
) - 1;
986 RegistryHive
->UpdateCounter
= RegistryHive
->HiveHeader
->UpdateCounter1
;
988 /* Allocate hive block list */
989 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
990 RegistryHive
->BlockListSize
* sizeof(BLOCK_LIST_ENTRY
));
991 if (RegistryHive
->BlockList
== NULL
)
993 DPRINT1("Failed to allocate the hive block list\n");
994 MmUnmapViewOfSection(PsGetCurrentProcess(),
996 ObDereferenceObject(SectionObject
);
997 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
998 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1000 return STATUS_INSUFFICIENT_RESOURCES
;
1002 RtlZeroMemory (RegistryHive
->BlockList
,
1003 RegistryHive
->BlockListSize
* sizeof(BLOCK_LIST_ENTRY
));
1005 /* Import the hive bins */
1006 Status
= CmiImportHiveBins (RegistryHive
,
1007 ViewBase
+ REG_BLOCK_SIZE
);
1008 if (!NT_SUCCESS(Status
))
1010 ExFreePool(RegistryHive
->BlockList
);
1011 MmUnmapViewOfSection(PsGetCurrentProcess(),
1013 ObDereferenceObject(SectionObject
);
1014 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1015 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1016 NtClose(FileHandle
);
1020 /* Unmap and dereference the hive section */
1021 MmUnmapViewOfSection(PsGetCurrentProcess(),
1023 ObDereferenceObject(SectionObject
);
1025 /* Close the hive file */
1026 NtClose(FileHandle
);
1028 /* Initialize the free cell list */
1029 Status
= CmiCreateHiveFreeCellList (RegistryHive
);
1030 if (!NT_SUCCESS(Status
))
1032 CmiFreeHiveBins(RegistryHive
);
1033 ExFreePool(RegistryHive
->BlockList
);
1034 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1035 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1039 /* Create the block bitmap */
1040 Status
= CmiCreateHiveBitmap (RegistryHive
);
1041 if (!NT_SUCCESS(Status
))
1043 CmiFreeHiveFreeCellList(RegistryHive
);
1044 CmiFreeHiveBins(RegistryHive
);
1045 ExFreePool(RegistryHive
->BlockList
);
1046 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1047 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1051 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n",
1052 RegistryHive
, Filename
);
1054 return STATUS_SUCCESS
;
1059 CmiCreateVolatileHive(PREGISTRY_HIVE
*RegistryHive
)
1061 PKEY_CELL RootKeyCell
;
1062 PREGISTRY_HIVE Hive
;
1064 *RegistryHive
= NULL
;
1066 Hive
= ExAllocatePool (NonPagedPool
,
1067 sizeof(REGISTRY_HIVE
));
1069 return STATUS_INSUFFICIENT_RESOURCES
;
1071 RtlZeroMemory (Hive
,
1072 sizeof(REGISTRY_HIVE
));
1074 DPRINT("Hive %x\n", Hive
);
1076 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1077 sizeof(HIVE_HEADER
));
1078 if (Hive
->HiveHeader
== NULL
)
1081 return STATUS_INSUFFICIENT_RESOURCES
;
1083 RtlZeroMemory (Hive
->HiveHeader
,
1084 sizeof(HIVE_HEADER
));
1086 Hive
->Flags
= (HIVE_NO_FILE
| HIVE_POINTER
);
1088 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1090 RootKeyCell
= (PKEY_CELL
)ExAllocatePool (NonPagedPool
,
1092 if (RootKeyCell
== NULL
)
1094 ExFreePool(Hive
->HiveHeader
);
1096 return STATUS_INSUFFICIENT_RESOURCES
;
1099 CmiCreateDefaultRootKeyCell (RootKeyCell
);
1100 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)RootKeyCell
;
1102 /* Acquire hive list lock exclusively */
1103 KeEnterCriticalRegion();
1104 ExAcquireResourceExclusiveLite (&CmiRegistryLock
, TRUE
);
1106 /* Add the new hive to the hive list */
1107 InsertTailList (&CmiHiveListHead
,
1110 /* Release hive list lock */
1111 ExReleaseResourceLite (&CmiRegistryLock
);
1112 KeLeaveCriticalRegion();
1114 VERIFY_REGISTRY_HIVE (Hive
);
1116 *RegistryHive
= Hive
;
1118 return STATUS_SUCCESS
;
1123 CmiCreateTempHive(PREGISTRY_HIVE
*RegistryHive
)
1126 PCELL_HEADER FreeCell
;
1127 PREGISTRY_HIVE Hive
;
1130 DPRINT ("CmiCreateTempHive() called\n");
1132 *RegistryHive
= NULL
;
1134 Hive
= ExAllocatePool (NonPagedPool
,
1135 sizeof(REGISTRY_HIVE
));
1138 DPRINT1 ("Failed to allocate registry hive block\n");
1139 return STATUS_INSUFFICIENT_RESOURCES
;
1141 RtlZeroMemory (Hive
,
1142 sizeof(REGISTRY_HIVE
));
1144 DPRINT ("Hive %x\n", Hive
);
1146 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1148 if (Hive
->HiveHeader
== NULL
)
1150 DPRINT1 ("Failed to allocate hive header block\n");
1152 return STATUS_INSUFFICIENT_RESOURCES
;
1154 RtlZeroMemory (Hive
->HiveHeader
,
1157 DPRINT ("HiveHeader %x\n", Hive
->HiveHeader
);
1159 Hive
->Flags
= HIVE_NO_FILE
;
1161 RtlInitUnicodeString (&Hive
->HiveFileName
,
1163 RtlInitUnicodeString (&Hive
->LogFileName
,
1166 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1168 /* Allocate hive block list */
1169 Hive
->BlockList
= ExAllocatePool (NonPagedPool
,
1170 sizeof(PBLOCK_LIST_ENTRY
));
1171 if (Hive
->BlockList
== NULL
)
1173 DPRINT1 ("Failed to allocate hive block list\n");
1174 ExFreePool(Hive
->HiveHeader
);
1176 return STATUS_INSUFFICIENT_RESOURCES
;
1179 /* Allocate first Bin */
1180 Hive
->BlockList
[0].Bin
= ExAllocatePool (NonPagedPool
,
1182 if (Hive
->BlockList
[0].Bin
== NULL
)
1184 DPRINT1 ("Failed to allocate first bin\n");
1185 ExFreePool(Hive
->BlockList
);
1186 ExFreePool(Hive
->HiveHeader
);
1188 return STATUS_INSUFFICIENT_RESOURCES
;
1190 Hive
->BlockList
[0].Block
= (PVOID
)Hive
->BlockList
[0].Bin
;
1192 Hive
->FileSize
= 2* REG_BLOCK_SIZE
;
1193 Hive
->BlockListSize
= 1;
1194 Hive
->UpdateCounter
= Hive
->HiveHeader
->UpdateCounter1
;
1197 BinHeader
= Hive
->BlockList
[0].Bin
;
1198 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)BinHeader
+ REG_HBIN_DATA_OFFSET
);
1200 CmiCreateDefaultBinHeader (BinHeader
);
1203 BinHeader
->BinOffset
= 0;
1205 /* Offset to root key block */
1206 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
1208 /* The rest of the block is free */
1209 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
1211 /* Create the free cell list */
1212 Status
= CmiCreateHiveFreeCellList (Hive
);
1213 if (Hive
->BlockList
[0].Bin
== NULL
)
1215 DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status
);
1216 ExFreePool(Hive
->BlockList
[0].Bin
);
1217 ExFreePool(Hive
->BlockList
);
1218 ExFreePool(Hive
->HiveHeader
);
1223 /* Acquire hive list lock exclusively */
1224 KeEnterCriticalRegion();
1225 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1227 /* Add the new hive to the hive list */
1228 InsertTailList (&CmiHiveListHead
,
1231 /* Release hive list lock */
1232 ExReleaseResourceLite(&CmiRegistryLock
);
1233 KeLeaveCriticalRegion();
1235 VERIFY_REGISTRY_HIVE (Hive
);
1237 *RegistryHive
= Hive
;
1239 return STATUS_SUCCESS
;
1244 CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1245 IN PUNICODE_STRING FileName
,
1248 PREGISTRY_HIVE Hive
;
1251 DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName
);
1253 if (Flags
& ~REG_NO_LAZY_FLUSH
)
1254 return STATUS_INVALID_PARAMETER
;
1256 Hive
= ExAllocatePool (NonPagedPool
,
1257 sizeof(REGISTRY_HIVE
));
1260 DPRINT1 ("Failed to allocate hive header.\n");
1261 return STATUS_INSUFFICIENT_RESOURCES
;
1263 RtlZeroMemory (Hive
,
1264 sizeof(REGISTRY_HIVE
));
1266 DPRINT ("Hive %x\n", Hive
);
1267 Hive
->Flags
= (Flags
& REG_NO_LAZY_FLUSH
) ? HIVE_NO_SYNCH
: 0;
1269 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool(NonPagedPool
,
1270 sizeof(HIVE_HEADER
));
1271 if (Hive
->HiveHeader
== NULL
)
1273 DPRINT1 ("Failed to allocate hive header.\n");
1275 return STATUS_INSUFFICIENT_RESOURCES
;
1278 RtlZeroMemory (Hive
->HiveHeader
,
1279 sizeof(HIVE_HEADER
));
1281 Status
= CmiInitNonVolatileRegistryHive (Hive
,
1283 if (!NT_SUCCESS (Status
))
1285 DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status
);
1286 ExFreePool (Hive
->HiveHeader
);
1291 /* Add the new hive to the hive list */
1292 InsertTailList (&CmiHiveListHead
,
1295 VERIFY_REGISTRY_HIVE(Hive
);
1297 Status
= CmiConnectHive (KeyObjectAttributes
,
1299 if (!NT_SUCCESS(Status
))
1301 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status
);
1302 // CmiRemoveRegistryHive (Hive);
1305 DPRINT ("CmiLoadHive() done\n");
1312 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
1314 if (RegistryHive
->Flags
& HIVE_POINTER
)
1315 return STATUS_UNSUCCESSFUL
;
1317 /* Remove hive from hive list */
1318 RemoveEntryList (&RegistryHive
->HiveList
);
1320 /* Release file names */
1321 RtlFreeUnicodeString (&RegistryHive
->HiveFileName
);
1322 RtlFreeUnicodeString (&RegistryHive
->LogFileName
);
1324 /* Release hive bitmap */
1325 ExFreePool (RegistryHive
->BitmapBuffer
);
1327 /* Release free cell list */
1328 ExFreePool (RegistryHive
->FreeList
);
1329 ExFreePool (RegistryHive
->FreeListOffset
);
1331 /* Release bins and bin list */
1332 CmiFreeHiveBins (RegistryHive
);
1333 ExFreePool (RegistryHive
->BlockList
);
1335 /* Release hive header */
1336 ExFreePool (RegistryHive
->HiveHeader
);
1339 ExFreePool (RegistryHive
);
1341 return STATUS_SUCCESS
;
1346 CmiCalcChecksum(PULONG Buffer
)
1351 for (i
= 0; i
< 127; i
++)
1359 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
1361 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1362 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1363 OBJECT_ATTRIBUTES ObjectAttributes
;
1364 IO_STATUS_BLOCK IoStatusBlock
;
1366 LARGE_INTEGER FileOffset
;
1376 DPRINT("CmiStartLogUpdate() called\n");
1378 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1379 BufferSize
= sizeof(HIVE_HEADER
) +
1382 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1384 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1386 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
,
1390 DPRINT("ExAllocatePool() failed\n");
1391 return(STATUS_INSUFFICIENT_RESOURCES
);
1393 RtlZeroMemory (Buffer
,
1396 /* Open log file for writing */
1397 InitializeObjectAttributes(&ObjectAttributes
,
1398 &RegistryHive
->LogFileName
,
1399 OBJ_CASE_INSENSITIVE
,
1403 Status
= ZwCreateFile(&FileHandle
,
1408 FILE_ATTRIBUTE_NORMAL
,
1411 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1414 if (!NT_SUCCESS(Status
))
1416 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1421 /* Update firt update counter and checksum */
1422 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1423 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1425 /* Copy hive header */
1426 RtlCopyMemory(Buffer
,
1427 RegistryHive
->HiveHeader
,
1428 sizeof(HIVE_HEADER
));
1429 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1436 RegistryHive
->DirtyBitMap
.Buffer
,
1439 /* Write hive block and block bitmap */
1440 FileOffset
.QuadPart
= (ULONGLONG
)0;
1441 Status
= NtWriteFile(FileHandle
,
1450 if (!NT_SUCCESS(Status
))
1452 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1453 NtClose(FileHandle
);
1459 /* Write dirty blocks */
1460 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1462 while (BlockIndex
< RegistryHive
->BlockListSize
)
1464 LastIndex
= BlockIndex
;
1465 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1468 if (BlockIndex
== (ULONG
)-1 || BlockIndex
< LastIndex
)
1470 DPRINT("No more set bits\n");
1471 Status
= STATUS_SUCCESS
;
1475 DPRINT("Block %lu is dirty\n", BlockIndex
);
1477 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1478 DPRINT("BlockPtr %p\n", BlockPtr
);
1479 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1481 /* Write hive block */
1482 Status
= NtWriteFile(FileHandle
,
1491 if (!NT_SUCCESS(Status
))
1493 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1494 NtClose(FileHandle
);
1499 FileOffset
.QuadPart
+= (ULONGLONG
)REG_BLOCK_SIZE
;
1502 /* Truncate log file */
1503 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1504 Status
= NtSetInformationFile(FileHandle
,
1507 sizeof(FILE_END_OF_FILE_INFORMATION
),
1508 FileEndOfFileInformation
);
1509 if (!NT_SUCCESS(Status
))
1511 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1512 NtClose(FileHandle
);
1516 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1517 Status
= NtSetInformationFile(FileHandle
,
1519 &FileAllocationInfo
,
1520 sizeof(FILE_ALLOCATION_INFORMATION
),
1521 FileAllocationInformation
);
1522 if (!NT_SUCCESS(Status
))
1524 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1525 NtClose(FileHandle
);
1529 /* Flush the log file */
1530 Status
= NtFlushBuffersFile(FileHandle
,
1532 if (!NT_SUCCESS(Status
))
1534 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1537 NtClose(FileHandle
);
1544 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1546 OBJECT_ATTRIBUTES ObjectAttributes
;
1547 IO_STATUS_BLOCK IoStatusBlock
;
1549 LARGE_INTEGER FileOffset
;
1556 DPRINT("CmiFinishLogUpdate() called\n");
1558 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1559 BufferSize
= sizeof(HIVE_HEADER
) +
1562 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1564 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1566 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1569 DPRINT("ExAllocatePool() failed\n");
1570 return(STATUS_INSUFFICIENT_RESOURCES
);
1573 /* Open log file for writing */
1574 InitializeObjectAttributes(&ObjectAttributes
,
1575 &RegistryHive
->LogFileName
,
1576 OBJ_CASE_INSENSITIVE
,
1580 Status
= ZwCreateFile(&FileHandle
,
1585 FILE_ATTRIBUTE_NORMAL
,
1588 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1591 if (!NT_SUCCESS(Status
))
1593 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1598 /* Update first and second update counter and checksum */
1599 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1600 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1601 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1603 /* Copy hive header */
1604 RtlCopyMemory(Buffer
,
1605 RegistryHive
->HiveHeader
,
1606 sizeof(HIVE_HEADER
));
1607 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1609 /* Write empty block bitmap */
1617 /* Write hive block and block bitmap */
1618 FileOffset
.QuadPart
= (ULONGLONG
)0;
1619 Status
= NtWriteFile(FileHandle
,
1628 if (!NT_SUCCESS(Status
))
1630 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1631 NtClose(FileHandle
);
1638 /* Flush the log file */
1639 Status
= NtFlushBuffersFile(FileHandle
,
1641 if (!NT_SUCCESS(Status
))
1643 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1646 NtClose(FileHandle
);
1653 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1655 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1656 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1657 OBJECT_ATTRIBUTES ObjectAttributes
;
1658 IO_STATUS_BLOCK IoStatusBlock
;
1664 DPRINT("CmiCleanupLogUpdate() called\n");
1666 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1667 BufferSize
= sizeof(HIVE_HEADER
) +
1670 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1672 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1674 /* Open log file for writing */
1675 InitializeObjectAttributes(&ObjectAttributes
,
1676 &RegistryHive
->LogFileName
,
1677 OBJ_CASE_INSENSITIVE
,
1681 Status
= ZwCreateFile(&FileHandle
,
1686 FILE_ATTRIBUTE_NORMAL
,
1689 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1692 if (!NT_SUCCESS(Status
))
1694 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1698 /* Truncate log file */
1699 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1700 Status
= NtSetInformationFile(FileHandle
,
1703 sizeof(FILE_END_OF_FILE_INFORMATION
),
1704 FileEndOfFileInformation
);
1705 if (!NT_SUCCESS(Status
))
1707 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1708 NtClose(FileHandle
);
1712 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1713 Status
= NtSetInformationFile(FileHandle
,
1715 &FileAllocationInfo
,
1716 sizeof(FILE_ALLOCATION_INFORMATION
),
1717 FileAllocationInformation
);
1718 if (!NT_SUCCESS(Status
))
1720 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1721 NtClose(FileHandle
);
1725 /* Flush the log file */
1726 Status
= NtFlushBuffersFile(FileHandle
,
1728 if (!NT_SUCCESS(Status
))
1730 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1733 NtClose(FileHandle
);
1740 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1742 OBJECT_ATTRIBUTES ObjectAttributes
;
1743 IO_STATUS_BLOCK IoStatusBlock
;
1745 LARGE_INTEGER FileOffset
;
1751 DPRINT("CmiStartHiveUpdate() called\n");
1753 /* Open hive for writing */
1754 InitializeObjectAttributes(&ObjectAttributes
,
1755 &RegistryHive
->HiveFileName
,
1756 OBJ_CASE_INSENSITIVE
,
1760 Status
= ZwCreateFile(&FileHandle
,
1765 FILE_ATTRIBUTE_NORMAL
,
1768 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1771 if (!NT_SUCCESS(Status
))
1773 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1777 /* Update firt update counter and checksum */
1778 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1779 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1781 /* Write hive block */
1782 FileOffset
.QuadPart
= (ULONGLONG
)0;
1783 Status
= NtWriteFile(FileHandle
,
1788 RegistryHive
->HiveHeader
,
1789 sizeof(HIVE_HEADER
),
1792 if (!NT_SUCCESS(Status
))
1794 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1795 NtClose(FileHandle
);
1800 while (BlockIndex
< RegistryHive
->BlockListSize
)
1802 LastIndex
= BlockIndex
;
1803 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1806 if (BlockIndex
== (ULONG
)-1 || BlockIndex
< LastIndex
)
1808 DPRINT("No more set bits\n");
1809 Status
= STATUS_SUCCESS
;
1813 DPRINT("Block %lu is dirty\n", BlockIndex
);
1815 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1816 DPRINT(" BlockPtr %p\n", BlockPtr
);
1818 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
1819 DPRINT(" File offset %I64x\n", FileOffset
.QuadPart
);
1821 /* Write hive block */
1822 Status
= NtWriteFile(FileHandle
,
1831 if (!NT_SUCCESS(Status
))
1833 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1834 NtClose(FileHandle
);
1841 Status
= NtFlushBuffersFile(FileHandle
,
1843 if (!NT_SUCCESS(Status
))
1845 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1848 NtClose(FileHandle
);
1855 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1857 OBJECT_ATTRIBUTES ObjectAttributes
;
1858 IO_STATUS_BLOCK IoStatusBlock
;
1859 LARGE_INTEGER FileOffset
;
1863 DPRINT("CmiFinishHiveUpdate() called\n");
1865 InitializeObjectAttributes(&ObjectAttributes
,
1866 &RegistryHive
->HiveFileName
,
1867 OBJ_CASE_INSENSITIVE
,
1871 Status
= ZwCreateFile(&FileHandle
,
1876 FILE_ATTRIBUTE_NORMAL
,
1879 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1882 if (!NT_SUCCESS(Status
))
1884 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1888 /* Update second update counter and checksum */
1889 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1890 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1891 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1893 /* Write hive block */
1894 FileOffset
.QuadPart
= (ULONGLONG
)0;
1895 Status
= NtWriteFile(FileHandle
,
1900 RegistryHive
->HiveHeader
,
1901 sizeof(HIVE_HEADER
),
1904 if (!NT_SUCCESS(Status
))
1906 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1907 NtClose(FileHandle
);
1911 Status
= NtFlushBuffersFile(FileHandle
,
1913 if (!NT_SUCCESS(Status
))
1915 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1918 NtClose(FileHandle
);
1925 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1929 DPRINT("CmiFlushRegistryHive() called\n");
1931 if (RegistryHive
->HiveDirty
== FALSE
)
1933 return(STATUS_SUCCESS
);
1936 DPRINT("Hive '%wZ' is dirty\n",
1937 &RegistryHive
->HiveFileName
);
1938 DPRINT("Log file: '%wZ'\n",
1939 &RegistryHive
->LogFileName
);
1941 /* Update hive header modification time */
1942 NtQuerySystemTime(&RegistryHive
->HiveHeader
->DateModified
);
1944 /* Start log update */
1945 Status
= CmiStartLogUpdate(RegistryHive
);
1946 if (!NT_SUCCESS(Status
))
1948 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1952 /* Finish log update */
1953 Status
= CmiFinishLogUpdate(RegistryHive
);
1954 if (!NT_SUCCESS(Status
))
1956 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1960 /* Start hive update */
1961 Status
= CmiStartHiveUpdate(RegistryHive
);
1962 if (!NT_SUCCESS(Status
))
1964 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1968 /* Finish the hive update */
1969 Status
= CmiFinishHiveUpdate(RegistryHive
);
1970 if (!NT_SUCCESS(Status
))
1972 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
1976 /* Cleanup log update */
1977 Status
= CmiCleanupLogUpdate(RegistryHive
);
1978 if (!NT_SUCCESS(Status
))
1980 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1984 /* Increment hive update counter */
1985 RegistryHive
->UpdateCounter
++;
1987 /* Clear dirty bitmap and dirty flag */
1988 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
1989 RegistryHive
->HiveDirty
= FALSE
;
1991 DPRINT("CmiFlushRegistryHive() done\n");
1993 return(STATUS_SUCCESS
);
1998 CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject
)
2005 VERIFY_KEY_OBJECT(KeyObject
);
2007 KeyCell
= KeyObject
->KeyCell
;
2008 VERIFY_KEY_CELL(KeyCell
);
2010 SubKeyCount
= (KeyCell
== NULL
) ? 0 : KeyCell
->NumberOfSubKeys
;
2012 /* Search for volatile or 'foreign' keys */
2013 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2015 CurKey
= KeyObject
->SubKeys
[i
];
2016 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2017 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2028 CmiGetMaxNameLength(PKEY_OBJECT KeyObject
)
2030 PHASH_TABLE_CELL HashBlock
;
2032 PKEY_CELL CurSubKeyCell
;
2038 VERIFY_KEY_OBJECT(KeyObject
);
2040 KeyCell
= KeyObject
->KeyCell
;
2041 VERIFY_KEY_CELL(KeyCell
);
2044 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2045 KeyCell
->HashTableOffset
,
2047 if (HashBlock
== NULL
)
2049 DPRINT("CmiGetBlock() failed\n");
2053 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2055 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2057 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2058 HashBlock
->Table
[i
].KeyOffset
,
2060 if (CurSubKeyCell
== NULL
)
2062 DPRINT("CmiGetBlock() failed\n");
2066 NameSize
= CurSubKeyCell
->NameSize
;
2067 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2069 NameSize
*= sizeof(WCHAR
);
2072 if (NameSize
> MaxName
)
2080 DPRINT ("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2081 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2083 CurKey
= KeyObject
->SubKeys
[i
];
2084 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2085 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2087 CurSubKeyCell
= CurKey
->KeyCell
;
2088 if (CurSubKeyCell
== NULL
)
2090 DPRINT("CmiGetBlock() failed\n");
2094 if ((CurSubKeyCell
->Flags
& REG_KEY_ROOT_CELL
) == REG_KEY_ROOT_CELL
)
2096 /* Use name of the key object */
2097 NameSize
= CurKey
->Name
.Length
;
2101 /* Use name of the key cell */
2102 NameSize
= CurSubKeyCell
->NameSize
;
2103 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2105 NameSize
*= sizeof(WCHAR
);
2108 DPRINT ("NameSize %lu\n", NameSize
);
2110 if (NameSize
> MaxName
)
2117 DPRINT ("MaxName %lu\n", MaxName
);
2124 CmiGetMaxClassLength(PKEY_OBJECT KeyObject
)
2126 PHASH_TABLE_CELL HashBlock
;
2128 PKEY_CELL CurSubKeyCell
;
2133 VERIFY_KEY_OBJECT(KeyObject
);
2135 KeyCell
= KeyObject
->KeyCell
;
2136 VERIFY_KEY_CELL(KeyCell
);
2139 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2140 KeyCell
->HashTableOffset
,
2142 if (HashBlock
== NULL
)
2144 DPRINT("CmiGetBlock() failed\n");
2148 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2150 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2152 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2153 HashBlock
->Table
[i
].KeyOffset
,
2155 if (CurSubKeyCell
== NULL
)
2157 DPRINT("CmiGetBlock() failed\n");
2161 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2163 MaxClass
= CurSubKeyCell
->ClassSize
;
2169 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2170 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2172 CurKey
= KeyObject
->SubKeys
[i
];
2173 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2174 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2176 CurSubKeyCell
= CurKey
->KeyCell
;
2177 if (CurSubKeyCell
== NULL
)
2179 DPRINT("CmiGetBlock() failed\n");
2183 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2185 MaxClass
= CurSubKeyCell
->ClassSize
;
2195 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
2198 PVALUE_LIST_CELL ValueListCell
;
2199 PVALUE_CELL CurValueCell
;
2204 VERIFY_KEY_CELL(KeyCell
);
2207 ValueListCell
= CmiGetCell (RegistryHive
,
2208 KeyCell
->ValueListOffset
,
2210 if (ValueListCell
== NULL
)
2212 DPRINT("CmiGetBlock() failed\n");
2216 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2218 CurValueCell
= CmiGetCell (RegistryHive
,
2219 ValueListCell
->ValueOffset
[i
],
2221 if (CurValueCell
== NULL
)
2223 DPRINT("CmiGetBlock() failed\n");
2226 if (CurValueCell
!= NULL
)
2228 Size
= CurValueCell
->NameSize
;
2229 if (CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
2231 Size
*= sizeof(WCHAR
);
2233 if (MaxValueName
< Size
)
2235 MaxValueName
= Size
;
2240 return MaxValueName
;
2245 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
2248 PVALUE_LIST_CELL ValueListCell
;
2249 PVALUE_CELL CurValueCell
;
2253 VERIFY_KEY_CELL(KeyCell
);
2256 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2257 if (ValueListCell
== NULL
)
2262 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2264 CurValueCell
= CmiGetCell (RegistryHive
,
2265 ValueListCell
->ValueOffset
[i
],NULL
);
2266 if ((CurValueCell
!= NULL
) &&
2267 (MaxValueData
< (LONG
)(CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2269 MaxValueData
= CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2273 return MaxValueData
;
2278 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
2279 IN PKEY_CELL KeyCell
,
2280 OUT PKEY_CELL
*SubKeyCell
,
2281 OUT BLOCK_OFFSET
*BlockOffset
,
2282 IN PUNICODE_STRING KeyName
,
2283 IN ACCESS_MASK DesiredAccess
,
2284 IN ULONG Attributes
)
2286 PHASH_TABLE_CELL HashBlock
;
2287 PKEY_CELL CurSubKeyCell
;
2290 VERIFY_KEY_CELL(KeyCell
);
2292 DPRINT("Scanning for sub key %wZ\n", KeyName
);
2294 ASSERT(RegistryHive
);
2298 /* The key does not have any subkeys */
2299 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
2301 return STATUS_SUCCESS
;
2304 /* Get hash table */
2305 HashBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2306 if (HashBlock
== NULL
)
2308 DPRINT("CmiGetBlock() failed\n");
2309 return STATUS_UNSUCCESSFUL
;
2312 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
) && (i
< HashBlock
->HashTableSize
); i
++)
2314 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2316 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2317 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1 &&
2318 (HashBlock
->Table
[i
].HashValue
== 0 ||
2319 CmiCompareHashI(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2321 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2322 HashBlock
->Table
[i
].KeyOffset
,
2324 if (CurSubKeyCell
== NULL
)
2326 DPRINT("CmiGetBlock() failed\n");
2327 return STATUS_UNSUCCESSFUL
;
2330 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2332 *SubKeyCell
= CurSubKeyCell
;
2333 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2340 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2341 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2342 (HashBlock
->Table
[i
].HashValue
== 0 ||
2343 CmiCompareHash(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2345 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2346 HashBlock
->Table
[i
].KeyOffset
,
2348 if (CurSubKeyCell
== NULL
)
2350 DPRINT("CmiGetBlock() failed\n");
2351 return STATUS_UNSUCCESSFUL
;
2354 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2356 *SubKeyCell
= CurSubKeyCell
;
2357 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2364 return STATUS_SUCCESS
;
2369 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2370 PKEY_OBJECT ParentKey
,
2372 PUNICODE_STRING SubKeyName
,
2374 PUNICODE_STRING Class
,
2375 ULONG CreateOptions
)
2377 PHASH_TABLE_CELL HashBlock
;
2378 BLOCK_OFFSET NKBOffset
;
2379 PKEY_CELL NewKeyCell
;
2381 PKEY_CELL ParentKeyCell
;
2382 PDATA_CELL ClassCell
;
2389 ParentKeyCell
= ParentKey
->KeyCell
;
2391 VERIFY_KEY_CELL(ParentKeyCell
);
2393 /* Skip leading backslash */
2394 if (SubKeyName
->Buffer
[0] == L
'\\')
2396 NamePtr
= &SubKeyName
->Buffer
[1];
2397 NameSize
= SubKeyName
->Length
- sizeof(WCHAR
);
2401 NamePtr
= SubKeyName
->Buffer
;
2402 NameSize
= SubKeyName
->Length
;
2405 /* Check whether key name can be packed */
2407 for (i
= 0; i
< NameSize
/ sizeof(WCHAR
); i
++)
2409 if (NamePtr
[i
] & 0xFF00)
2416 /* Adjust name size */
2419 NameSize
= NameSize
/ sizeof(WCHAR
);
2422 DPRINT("Key %S Length %lu %s\n", NamePtr
, NameSize
, (Packable
)?"True":"False");
2424 Status
= STATUS_SUCCESS
;
2426 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2427 Status
= CmiAllocateCell (RegistryHive
,
2429 (PVOID
) &NewKeyCell
,
2431 if (NewKeyCell
== NULL
)
2433 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2437 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2438 NewKeyCell
->Flags
= 0;
2439 NtQuerySystemTime(&NewKeyCell
->LastWriteTime
);
2440 NewKeyCell
->ParentKeyOffset
= -1;
2441 NewKeyCell
->NumberOfSubKeys
= 0;
2442 NewKeyCell
->HashTableOffset
= -1;
2443 NewKeyCell
->NumberOfValues
= 0;
2444 NewKeyCell
->ValueListOffset
= -1;
2445 NewKeyCell
->SecurityKeyOffset
= -1;
2446 NewKeyCell
->ClassNameOffset
= -1;
2448 /* Pack the key name */
2449 NewKeyCell
->NameSize
= NameSize
;
2452 NewKeyCell
->Flags
|= REG_KEY_NAME_PACKED
;
2453 for (i
= 0; i
< NameSize
; i
++)
2455 NewKeyCell
->Name
[i
] = (CHAR
)(NamePtr
[i
] & 0x00FF);
2460 RtlCopyMemory(NewKeyCell
->Name
,
2465 VERIFY_KEY_CELL(NewKeyCell
);
2469 NewKeyCell
->ClassSize
= Class
->Length
;
2470 Status
= CmiAllocateCell (RegistryHive
,
2471 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
2473 &NewKeyCell
->ClassNameOffset
);
2474 RtlCopyMemory (ClassCell
->Data
,
2480 if (!NT_SUCCESS(Status
))
2485 SubKey
->KeyCell
= NewKeyCell
;
2486 SubKey
->KeyCellOffset
= NKBOffset
;
2488 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2489 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(ParentKey
->RegistryHive
)))
2494 if (ParentKeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2496 Status
= CmiAllocateHashTableCell (RegistryHive
,
2498 &ParentKeyCell
->HashTableOffset
,
2499 REG_INIT_HASH_TABLE_SIZE
);
2500 if (!NT_SUCCESS(Status
))
2507 HashBlock
= CmiGetCell (RegistryHive
,
2508 ParentKeyCell
->HashTableOffset
,
2510 if (HashBlock
== NULL
)
2512 DPRINT("CmiGetCell() failed\n");
2513 return STATUS_UNSUCCESSFUL
;
2516 if (((ParentKeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2518 PHASH_TABLE_CELL NewHashBlock
;
2519 BLOCK_OFFSET HTOffset
;
2521 /* Reallocate the hash table cell */
2522 Status
= CmiAllocateHashTableCell (RegistryHive
,
2525 HashBlock
->HashTableSize
+
2526 REG_EXTEND_HASH_TABLE_SIZE
);
2527 if (!NT_SUCCESS(Status
))
2532 RtlZeroMemory(&NewHashBlock
->Table
[0],
2533 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2534 RtlCopyMemory(&NewHashBlock
->Table
[0],
2535 &HashBlock
->Table
[0],
2536 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2537 CmiDestroyCell (RegistryHive
,
2539 ParentKeyCell
->HashTableOffset
);
2540 ParentKeyCell
->HashTableOffset
= HTOffset
;
2541 HashBlock
= NewHashBlock
;
2545 Status
= CmiAddKeyToHashTable(RegistryHive
,
2547 ParentKeyCell
->HashTableOffset
,
2550 if (NT_SUCCESS(Status
))
2552 ParentKeyCell
->NumberOfSubKeys
++;
2555 NtQuerySystemTime (&ParentKeyCell
->LastWriteTime
);
2556 CmiMarkBlockDirty (RegistryHive
, ParentKey
->KeyCellOffset
);
2563 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2564 PKEY_OBJECT ParentKey
,
2567 PHASH_TABLE_CELL HashBlock
;
2568 PVALUE_LIST_CELL ValueList
;
2569 PVALUE_CELL ValueCell
;
2570 PDATA_CELL DataCell
;
2573 DPRINT("CmiRemoveSubKey() called\n");
2575 /* Remove all values */
2576 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2578 /* Get pointer to the value list cell */
2579 ValueList
= CmiGetCell (RegistryHive
,
2580 SubKey
->KeyCell
->ValueListOffset
,
2582 if (ValueList
== NULL
)
2584 DPRINT("CmiGetCell() failed\n");
2585 return STATUS_UNSUCCESSFUL
;
2588 /* Enumerate all values */
2589 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2591 /* Get pointer to value cell */
2592 ValueCell
= CmiGetCell(RegistryHive
,
2593 ValueList
->ValueOffset
[i
],
2595 if (ValueCell
== NULL
)
2597 DPRINT("CmiGetCell() failed\n");
2598 return STATUS_UNSUCCESSFUL
;
2601 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
)
2602 && ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
2604 DataCell
= CmiGetCell (RegistryHive
,
2605 ValueCell
->DataOffset
,
2607 if (DataCell
== NULL
)
2609 DPRINT("CmiGetCell() failed\n");
2610 return STATUS_UNSUCCESSFUL
;
2613 if (DataCell
!= NULL
)
2615 /* Destroy data cell */
2616 CmiDestroyCell (RegistryHive
,
2618 ValueCell
->DataOffset
);
2622 /* Destroy value cell */
2623 CmiDestroyCell (RegistryHive
,
2625 ValueList
->ValueOffset
[i
]);
2628 /* Destroy value list cell */
2629 CmiDestroyCell (RegistryHive
,
2631 SubKey
->KeyCell
->ValueListOffset
);
2633 SubKey
->KeyCell
->NumberOfValues
= 0;
2634 SubKey
->KeyCell
->ValueListOffset
= (BLOCK_OFFSET
)-1;
2636 CmiMarkBlockDirty(RegistryHive
,
2637 SubKey
->KeyCellOffset
);
2640 /* Remove the key from the parent key's hash block */
2641 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2643 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2644 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2645 ParentKey
->KeyCell
->HashTableOffset
,
2647 if (HashBlock
== NULL
)
2649 DPRINT("CmiGetCell() failed\n");
2650 return STATUS_UNSUCCESSFUL
;
2652 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2653 if (HashBlock
!= NULL
)
2655 CmiRemoveKeyFromHashTable(ParentKey
->RegistryHive
,
2657 SubKey
->KeyCellOffset
);
2658 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2659 ParentKey
->KeyCell
->HashTableOffset
);
2663 /* Remove the key's hash block */
2664 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2666 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
);
2667 HashBlock
= CmiGetCell (RegistryHive
,
2668 SubKey
->KeyCell
->HashTableOffset
,
2670 if (HashBlock
== NULL
)
2672 DPRINT("CmiGetCell() failed\n");
2673 return STATUS_UNSUCCESSFUL
;
2675 DPRINT("SubKey HashBlock %p\n", HashBlock
);
2676 if (HashBlock
!= NULL
)
2678 CmiDestroyCell (RegistryHive
,
2680 SubKey
->KeyCell
->HashTableOffset
);
2681 SubKey
->KeyCell
->HashTableOffset
= -1;
2685 /* Decrement the number of the parent key's sub keys */
2686 if (ParentKey
!= NULL
)
2688 DPRINT("ParentKey %p\n", ParentKey
);
2689 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2691 /* Remove the parent key's hash table */
2692 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2694 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2695 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2696 ParentKey
->KeyCell
->HashTableOffset
,
2698 if (HashBlock
== NULL
)
2700 DPRINT("CmiGetCell() failed\n");
2701 return STATUS_UNSUCCESSFUL
;
2703 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2704 if (HashBlock
!= NULL
)
2706 CmiDestroyCell (ParentKey
->RegistryHive
,
2708 ParentKey
->KeyCell
->HashTableOffset
);
2709 ParentKey
->KeyCell
->HashTableOffset
= (BLOCK_OFFSET
)-1;
2713 NtQuerySystemTime(&ParentKey
->KeyCell
->LastWriteTime
);
2714 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2715 ParentKey
->KeyCellOffset
);
2718 /* Destroy key cell */
2719 CmiDestroyCell (RegistryHive
,
2721 SubKey
->KeyCellOffset
);
2722 SubKey
->KeyCell
= NULL
;
2723 SubKey
->KeyCellOffset
= (BLOCK_OFFSET
)-1;
2725 DPRINT("CmiRemoveSubKey() done\n");
2727 return STATUS_SUCCESS
;
2732 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2733 IN PKEY_CELL KeyCell
,
2734 IN PUNICODE_STRING ValueName
,
2735 OUT PVALUE_CELL
*ValueCell
,
2736 OUT BLOCK_OFFSET
*ValueCellOffset
)
2738 PVALUE_LIST_CELL ValueListCell
;
2739 PVALUE_CELL CurValueCell
;
2743 if (ValueCellOffset
!= NULL
)
2744 *ValueCellOffset
= (BLOCK_OFFSET
)-1;
2746 /* The key does not have any values */
2747 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2749 return STATUS_OBJECT_NAME_NOT_FOUND
;
2752 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2753 if (ValueListCell
== NULL
)
2755 DPRINT("ValueListCell is NULL\n");
2756 return STATUS_UNSUCCESSFUL
;
2759 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2761 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2763 CurValueCell
= CmiGetCell (RegistryHive
,
2764 ValueListCell
->ValueOffset
[i
],
2766 if (CurValueCell
== NULL
)
2768 DPRINT("CmiGetBlock() failed\n");
2769 return STATUS_UNSUCCESSFUL
;
2772 if ((CurValueCell
!= NULL
) &&
2773 CmiComparePackedNames(ValueName
,
2775 CurValueCell
->NameSize
,
2776 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2778 *ValueCell
= CurValueCell
;
2779 if (ValueCellOffset
!= NULL
)
2780 *ValueCellOffset
= ValueListCell
->ValueOffset
[i
];
2781 //DPRINT("Found value %s\n", ValueName);
2782 return STATUS_SUCCESS
;
2786 return STATUS_OBJECT_NAME_NOT_FOUND
;
2791 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2792 IN PKEY_CELL KeyCell
,
2794 OUT PVALUE_CELL
*ValueCell
)
2796 PVALUE_LIST_CELL ValueListCell
;
2797 PVALUE_CELL CurValueCell
;
2801 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2803 return STATUS_NO_MORE_ENTRIES
;
2806 if (Index
>= KeyCell
->NumberOfValues
)
2808 return STATUS_NO_MORE_ENTRIES
;
2812 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2813 if (ValueListCell
== NULL
)
2815 DPRINT("CmiGetBlock() failed\n");
2816 return STATUS_UNSUCCESSFUL
;
2819 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2822 CurValueCell
= CmiGetCell (RegistryHive
,
2823 ValueListCell
->ValueOffset
[Index
],
2825 if (CurValueCell
== NULL
)
2827 DPRINT("CmiGetBlock() failed\n");
2828 return STATUS_UNSUCCESSFUL
;
2831 *ValueCell
= CurValueCell
;
2833 return STATUS_SUCCESS
;
2838 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2839 IN PKEY_CELL KeyCell
,
2840 IN BLOCK_OFFSET KeyCellOffset
,
2841 IN PUNICODE_STRING ValueName
,
2842 OUT PVALUE_CELL
*pValueCell
,
2843 OUT BLOCK_OFFSET
*pValueCellOffset
)
2845 PVALUE_LIST_CELL NewValueListCell
;
2846 PVALUE_LIST_CELL ValueListCell
;
2847 PVALUE_CELL NewValueCell
;
2848 BLOCK_OFFSET NewValueListCellOffset
;
2849 BLOCK_OFFSET ValueListCellOffset
;
2850 BLOCK_OFFSET NewValueCellOffset
;
2854 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG
)KeyCell
->ValueListOffset
);
2856 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2857 if (ValueListCell
== NULL
)
2859 CellSize
= sizeof(VALUE_LIST_CELL
) +
2860 (3 * sizeof(BLOCK_OFFSET
));
2861 Status
= CmiAllocateCell (RegistryHive
,
2863 (PVOID
) &ValueListCell
,
2864 &ValueListCellOffset
);
2865 if (!NT_SUCCESS(Status
))
2870 KeyCell
->ValueListOffset
= ValueListCellOffset
;
2871 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2872 CmiMarkBlockDirty(RegistryHive
, ValueListCellOffset
);
2874 else if (KeyCell
->NumberOfValues
>=
2875 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
)))
2878 CellSize
= sizeof(VALUE_LIST_CELL
) +
2879 ((KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) * sizeof(BLOCK_OFFSET
));
2881 CellSize
= 2 * (ULONG
)ABS_VALUE(ValueListCell
->CellSize
);
2882 Status
= CmiAllocateCell (RegistryHive
,
2884 (PVOID
) &NewValueListCell
,
2885 &NewValueListCellOffset
);
2886 if (!NT_SUCCESS(Status
))
2891 RtlCopyMemory(&NewValueListCell
->ValueOffset
[0],
2892 &ValueListCell
->ValueOffset
[0],
2893 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2894 CmiDestroyCell (RegistryHive
, ValueListCell
, KeyCell
->ValueListOffset
);
2895 CmiMarkBlockDirty (RegistryHive
, KeyCell
->ValueListOffset
);
2897 KeyCell
->ValueListOffset
= NewValueListCellOffset
;
2898 ValueListCell
= NewValueListCell
;
2899 CmiMarkBlockDirty (RegistryHive
, KeyCellOffset
);
2900 CmiMarkBlockDirty (RegistryHive
, NewValueListCellOffset
);
2903 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2904 KeyCell
->NumberOfValues
,
2905 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2906 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
),
2907 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
));
2909 Status
= CmiAllocateValueCell(RegistryHive
,
2911 &NewValueCellOffset
,
2913 if (!NT_SUCCESS(Status
))
2918 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = NewValueCellOffset
;
2919 KeyCell
->NumberOfValues
++;
2921 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2922 CmiMarkBlockDirty(RegistryHive
, KeyCell
->ValueListOffset
);
2923 CmiMarkBlockDirty(RegistryHive
, NewValueCellOffset
);
2925 *pValueCell
= NewValueCell
;
2926 *pValueCellOffset
= NewValueCellOffset
;
2928 return STATUS_SUCCESS
;
2933 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2934 IN PKEY_CELL KeyCell
,
2935 IN BLOCK_OFFSET KeyCellOffset
,
2936 IN PUNICODE_STRING ValueName
)
2938 PVALUE_LIST_CELL ValueListCell
;
2939 PVALUE_CELL CurValueCell
;
2943 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2944 if (ValueListCell
== NULL
)
2946 DPRINT1("CmiGetBlock() failed\n");
2947 return STATUS_SUCCESS
;
2950 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2952 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2954 CurValueCell
= CmiGetCell (RegistryHive
, ValueListCell
->ValueOffset
[i
], NULL
);
2955 if (CurValueCell
== NULL
)
2957 DPRINT1("CmiGetBlock() failed\n");
2958 return STATUS_UNSUCCESSFUL
;
2961 if (CmiComparePackedNames(ValueName
,
2963 CurValueCell
->NameSize
,
2964 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2966 Status
= CmiDestroyValueCell(RegistryHive
,
2968 ValueListCell
->ValueOffset
[i
]);
2969 if (CurValueCell
== NULL
)
2971 DPRINT1("CmiDestroyValueCell() failed\n");
2975 if (i
< (KeyCell
->NumberOfValues
- 1))
2977 RtlMoveMemory(&ValueListCell
->ValueOffset
[i
],
2978 &ValueListCell
->ValueOffset
[i
+ 1],
2979 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2981 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
- 1] = 0;
2984 KeyCell
->NumberOfValues
--;
2986 if (KeyCell
->NumberOfValues
== 0)
2988 CmiDestroyCell(RegistryHive
,
2990 KeyCell
->ValueListOffset
);
2991 KeyCell
->ValueListOffset
= -1;
2995 CmiMarkBlockDirty(RegistryHive
,
2996 KeyCell
->ValueListOffset
);
2999 CmiMarkBlockDirty(RegistryHive
,
3002 return STATUS_SUCCESS
;
3006 DPRINT("Couldn't find the desired value\n");
3008 return STATUS_OBJECT_NAME_NOT_FOUND
;
3013 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive
,
3014 OUT PHASH_TABLE_CELL
*HashBlock
,
3015 OUT BLOCK_OFFSET
*HBOffset
,
3016 IN ULONG SubKeyCount
)
3018 PHASH_TABLE_CELL NewHashBlock
;
3022 Status
= STATUS_SUCCESS
;
3024 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
3025 (SubKeyCount
* sizeof(HASH_RECORD
));
3026 Status
= CmiAllocateCell (RegistryHive
,
3028 (PVOID
*) &NewHashBlock
,
3031 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
3033 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3037 ASSERT(SubKeyCount
<= 0xffff); /* should really be USHORT_MAX or similar */
3038 NewHashBlock
->Id
= REG_HASH_TABLE_CELL_ID
;
3039 NewHashBlock
->HashTableSize
= (USHORT
)SubKeyCount
;
3040 *HashBlock
= NewHashBlock
;
3048 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
3049 PHASH_TABLE_CELL HashBlock
,
3052 BLOCK_OFFSET KeyOffset
;
3055 if (HashBlock
== NULL
)
3058 if (IsPointerHive(RegistryHive
))
3060 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
3064 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
3065 KeyCell
= CmiGetCell (RegistryHive
, KeyOffset
, NULL
);
3073 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
3074 PHASH_TABLE_CELL HashCell
,
3075 BLOCK_OFFSET HashCellOffset
,
3076 PKEY_CELL NewKeyCell
,
3077 BLOCK_OFFSET NKBOffset
)
3081 for (i
= 0; i
< HashCell
->HashTableSize
; i
++)
3083 if (HashCell
->Table
[i
].KeyOffset
== 0)
3085 HashCell
->Table
[i
].KeyOffset
= NKBOffset
;
3086 HashCell
->Table
[i
].HashValue
= 0;
3087 if (NewKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3089 RtlCopyMemory(&HashCell
->Table
[i
].HashValue
,
3091 min(NewKeyCell
->NameSize
, sizeof(ULONG
)));
3093 CmiMarkBlockDirty(RegistryHive
, HashCellOffset
);
3094 return STATUS_SUCCESS
;
3098 return STATUS_UNSUCCESSFUL
;
3103 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
3104 PHASH_TABLE_CELL HashBlock
,
3105 BLOCK_OFFSET NKBOffset
)
3109 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3111 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
3113 HashBlock
->Table
[i
].KeyOffset
= 0;
3114 HashBlock
->Table
[i
].HashValue
= 0;
3115 return STATUS_SUCCESS
;
3119 return STATUS_UNSUCCESSFUL
;
3124 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
3125 PVALUE_CELL
*ValueCell
,
3126 BLOCK_OFFSET
*VBOffset
,
3127 IN PUNICODE_STRING ValueName
)
3129 PVALUE_CELL NewValueCell
;
3135 Status
= STATUS_SUCCESS
;
3137 NameSize
= CmiGetPackedNameLength(ValueName
,
3140 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
3142 Status
= CmiAllocateCell (RegistryHive
,
3143 sizeof(VALUE_CELL
) + NameSize
,
3144 (PVOID
*) &NewValueCell
,
3146 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
3148 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3152 ASSERT(NameSize
<= 0xffff); /* should really be USHORT_MAX or similar */
3153 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
3154 NewValueCell
->NameSize
= (USHORT
)NameSize
;
3157 /* Pack the value name */
3158 for (i
= 0; i
< NameSize
; i
++)
3159 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
3160 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
3164 /* Copy the value name */
3165 RtlCopyMemory(NewValueCell
->Name
,
3168 NewValueCell
->Flags
= 0;
3170 NewValueCell
->DataType
= 0;
3171 NewValueCell
->DataSize
= 0;
3172 NewValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
3173 *ValueCell
= NewValueCell
;
3181 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
3182 PVALUE_CELL ValueCell
,
3183 BLOCK_OFFSET ValueCellOffset
)
3189 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n",
3190 ValueCell
, ValueCellOffset
);
3192 VERIFY_VALUE_CELL(ValueCell
);
3194 /* Destroy the data cell */
3195 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
)
3196 && ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
3198 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, &Bin
);
3199 if (DataCell
== NULL
)
3201 DPRINT("CmiGetCell() failed\n");
3202 return STATUS_UNSUCCESSFUL
;
3205 Status
= CmiDestroyCell (RegistryHive
, DataCell
, ValueCell
->DataOffset
);
3206 if (!NT_SUCCESS(Status
))
3211 /* Update time of heap */
3212 if (!IsNoFileHive(RegistryHive
))
3213 NtQuerySystemTime(&Bin
->DateModified
);
3216 /* Destroy the value cell */
3217 Status
= CmiDestroyCell (RegistryHive
, ValueCell
, ValueCellOffset
);
3219 /* Update time of heap */
3220 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, ValueCellOffset
, &Bin
))
3222 NtQuerySystemTime(&Bin
->DateModified
);
3230 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
3233 BLOCK_OFFSET
*NewBlockOffset
)
3235 PBLOCK_LIST_ENTRY BlockList
;
3236 PCELL_HEADER tmpBlock
;
3241 DPRINT ("CmiAddBin (BlockCount %lu)\n", BlockCount
);
3243 BinSize
= BlockCount
* REG_BLOCK_SIZE
;
3244 tmpBin
= ExAllocatePool(PagedPool
, BinSize
);
3247 return STATUS_INSUFFICIENT_RESOURCES
;
3249 RtlZeroMemory (tmpBin
,
3252 tmpBin
->HeaderId
= REG_BIN_ID
;
3253 tmpBin
->BinOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
3254 RegistryHive
->FileSize
+= BinSize
;
3255 tmpBin
->BinSize
= BinSize
;
3256 tmpBin
->Unused1
= 0;
3257 NtQuerySystemTime(&tmpBin
->DateModified
);
3258 tmpBin
->Unused2
= 0;
3260 DPRINT (" BinOffset %lx BinSize %lx\n", tmpBin
->BinOffset
,tmpBin
->BinSize
);
3262 /* Allocate new block list */
3263 BlockList
= ExAllocatePool(NonPagedPool
,
3264 sizeof(BLOCK_LIST_ENTRY
) * (RegistryHive
->BlockListSize
+ BlockCount
));
3265 if (BlockList
== NULL
)
3268 return STATUS_INSUFFICIENT_RESOURCES
;
3271 if (RegistryHive
->BlockListSize
> 0)
3273 RtlCopyMemory (BlockList
,
3274 RegistryHive
->BlockList
,
3275 sizeof(BLOCK_LIST_ENTRY
) * RegistryHive
->BlockListSize
);
3276 ExFreePool(RegistryHive
->BlockList
);
3279 RegistryHive
->BlockList
= BlockList
;
3280 for (i
= 0; i
< BlockCount
; i
++)
3282 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Block
=
3283 (PVOID
)((ULONG_PTR
)tmpBin
+ (i
* REG_BLOCK_SIZE
));
3284 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Bin
= tmpBin
;
3286 RegistryHive
->BlockListSize
+= BlockCount
;
3288 /* Initialize a free block in this heap : */
3289 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
3290 tmpBlock
->CellSize
= (BinSize
- REG_HBIN_DATA_OFFSET
);
3292 /* Grow bitmap if necessary */
3293 if (IsNoFileHive(RegistryHive
) &&
3294 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
3296 PULONG BitmapBuffer
;
3299 DPRINT("Grow hive bitmap\n");
3301 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3302 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
3303 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
3304 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
3305 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
3307 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
3308 RtlCopyMemory(BitmapBuffer
,
3309 RegistryHive
->DirtyBitMap
.Buffer
,
3310 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
3311 ExFreePool(RegistryHive
->BitmapBuffer
);
3312 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
3313 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
3314 RegistryHive
->BitmapBuffer
,
3318 *NewBlock
= (PVOID
) tmpBlock
;
3321 *NewBlockOffset
= tmpBin
->BinOffset
+ REG_HBIN_DATA_OFFSET
;
3323 /* Mark new bin dirty */
3324 CmiMarkBinDirty(RegistryHive
,
3327 return STATUS_SUCCESS
;
3332 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
3335 BLOCK_OFFSET
*CellOffset
)
3337 PCELL_HEADER NewCell
;
3343 /* Round to 16 bytes multiple */
3344 CellSize
= ROUND_UP(CellSize
, 16);
3346 /* Handle volatile hives first */
3347 if (IsPointerHive(RegistryHive
))
3349 NewCell
= ExAllocatePool(NonPagedPool
, CellSize
);
3350 if (NewCell
== NULL
)
3352 return STATUS_INSUFFICIENT_RESOURCES
;
3355 RtlZeroMemory (NewCell
,
3357 NewCell
->CellSize
= -CellSize
;
3360 if (CellOffset
!= NULL
)
3361 *CellOffset
= (BLOCK_OFFSET
) NewCell
;
3365 /* first search in free blocks */
3367 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3369 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
3371 NewCell
= RegistryHive
->FreeList
[i
];
3372 if (CellOffset
!= NULL
)
3373 *CellOffset
= RegistryHive
->FreeListOffset
[i
];
3375 /* Update time of heap */
3376 Temp
= CmiGetCell (RegistryHive
,
3377 RegistryHive
->FreeListOffset
[i
],
3381 DPRINT("CmiGetBlock() failed\n");
3382 return STATUS_UNSUCCESSFUL
;
3385 NtQuerySystemTime(&Bin
->DateModified
);
3386 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
3388 if ((i
+ 1) < RegistryHive
->FreeListSize
)
3390 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
3391 &RegistryHive
->FreeList
[i
+ 1],
3392 sizeof(RegistryHive
->FreeList
[0])
3393 * (RegistryHive
->FreeListSize
- i
- 1));
3394 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
3395 &RegistryHive
->FreeListOffset
[i
+ 1],
3396 sizeof(RegistryHive
->FreeListOffset
[0])
3397 * (RegistryHive
->FreeListSize
- i
- 1));
3399 RegistryHive
->FreeListSize
--;
3404 /* Need to extend hive file : */
3405 if (NewCell
== NULL
)
3408 Status
= CmiAddBin(RegistryHive
,
3409 ((CellSize
+ sizeof(HBIN
) - 1) / REG_BLOCK_SIZE
) + 1,
3412 if (!NT_SUCCESS(Status
))
3418 /* Split the block in two parts */
3419 if (NewCell
->CellSize
> CellSize
)
3421 NewCell
= (PCELL_HEADER
) ((ULONG_PTR
) NewCell
+ CellSize
);
3422 NewCell
->CellSize
= ((PCELL_HEADER
) (*Cell
))->CellSize
- CellSize
;
3423 CmiAddFree(RegistryHive
,
3425 *CellOffset
+ CellSize
,
3427 CmiMarkBlockDirty(RegistryHive
,
3428 *CellOffset
+ CellSize
);
3430 else if (NewCell
->CellSize
< CellSize
)
3432 return STATUS_UNSUCCESSFUL
;
3435 RtlZeroMemory(*Cell
,
3437 ((PCELL_HEADER
) (*Cell
))->CellSize
= -CellSize
;
3440 return STATUS_SUCCESS
;
3445 CmiDestroyCell (PREGISTRY_HIVE RegistryHive
,
3447 BLOCK_OFFSET CellOffset
)
3452 Status
= STATUS_SUCCESS
;
3454 if (IsPointerHive(RegistryHive
))
3460 PCELL_HEADER pFree
= Cell
;
3462 if (pFree
->CellSize
< 0)
3463 pFree
->CellSize
= -pFree
->CellSize
;
3465 /* Clear block (except the block size) */
3466 RtlZeroMemory(((char*)pFree
) + sizeof(ULONG
),
3467 pFree
->CellSize
- sizeof(ULONG
));
3469 /* Add block to the list of free blocks */
3470 CmiAddFree(RegistryHive
, Cell
, CellOffset
, TRUE
);
3472 /* Update time of heap */
3473 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, CellOffset
,&pBin
))
3474 NtQuerySystemTime(&pBin
->DateModified
);
3476 CmiMarkBlockDirty(RegistryHive
, CellOffset
);
3484 CmiGetCell (PREGISTRY_HIVE RegistryHive
,
3485 BLOCK_OFFSET CellOffset
,
3495 if (CellOffset
== (BLOCK_OFFSET
)-1)
3500 if (IsPointerHive (RegistryHive
))
3502 return (PVOID
)CellOffset
;
3505 if (CellOffset
> RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
)
3507 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3508 CellOffset
, RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
);
3512 pBin
= RegistryHive
->BlockList
[CellOffset
/ REG_BLOCK_SIZE
].Bin
;
3523 return((PVOID
)((ULONG_PTR
)pBin
+ (CellOffset
- pBin
->BinOffset
)));
3528 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3529 PCELL_HEADER FreeBlock
,
3530 BLOCK_OFFSET FreeOffset
)
3532 BLOCK_OFFSET BlockOffset
;
3533 BLOCK_OFFSET BinOffset
;
3539 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3540 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3542 CmiGetCell (RegistryHive
,
3545 DPRINT("Bin %p\n", Bin
);
3549 BinOffset
= Bin
->BinOffset
;
3550 BinSize
= Bin
->BinSize
;
3551 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3553 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3555 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3556 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3557 if (BlockOffset
> BinOffset
&&
3558 BlockOffset
< BinOffset
+ BinSize
)
3560 DPRINT("Free block: Offset %lx Size %lx\n",
3561 BlockOffset
, BlockSize
);
3563 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3564 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3565 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3567 DPRINT("Merge current block with previous and next block\n");
3569 RegistryHive
->FreeList
[i
]->CellSize
+=
3570 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3572 FreeBlock
->CellSize
= 0;
3573 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3576 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3578 RtlMoveMemory(&RegistryHive
->FreeList
[i
+ 1],
3579 &RegistryHive
->FreeList
[i
+ 2],
3580 sizeof(RegistryHive
->FreeList
[0])
3581 * (RegistryHive
->FreeListSize
- i
- 2));
3582 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3583 &RegistryHive
->FreeListOffset
[i
+ 2],
3584 sizeof(RegistryHive
->FreeListOffset
[0])
3585 * (RegistryHive
->FreeListSize
- i
- 2));
3587 RegistryHive
->FreeListSize
--;
3589 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3593 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3595 DPRINT("Merge current block with previous block\n");
3597 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3598 FreeBlock
->CellSize
= 0;
3600 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3604 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3606 DPRINT("Merge current block with next block\n");
3608 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3609 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3610 RegistryHive
->FreeList
[i
] = FreeBlock
;
3611 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3613 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3625 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3626 PCELL_HEADER FreeBlock
,
3627 BLOCK_OFFSET FreeOffset
,
3628 BOOLEAN MergeFreeBlocks
)
3630 PCELL_HEADER
*tmpList
;
3631 BLOCK_OFFSET
*tmpListOffset
;
3636 ASSERT(RegistryHive
);
3639 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3640 FreeBlock
, FreeOffset
);
3642 /* Merge free blocks */
3643 if (MergeFreeBlocks
== TRUE
)
3645 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3646 return(STATUS_SUCCESS
);
3649 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3651 tmpList
= ExAllocatePool(PagedPool
,
3652 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3653 if (tmpList
== NULL
)
3654 return STATUS_INSUFFICIENT_RESOURCES
;
3656 tmpListOffset
= ExAllocatePool(PagedPool
,
3657 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3659 if (tmpListOffset
== NULL
)
3661 ExFreePool(tmpList
);
3662 return STATUS_INSUFFICIENT_RESOURCES
;
3665 if (RegistryHive
->FreeListMax
)
3667 RtlMoveMemory(tmpList
,
3668 RegistryHive
->FreeList
,
3669 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3670 RtlMoveMemory(tmpListOffset
,
3671 RegistryHive
->FreeListOffset
,
3672 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3673 ExFreePool(RegistryHive
->FreeList
);
3674 ExFreePool(RegistryHive
->FreeListOffset
);
3676 RegistryHive
->FreeList
= tmpList
;
3677 RegistryHive
->FreeListOffset
= tmpListOffset
;
3678 RegistryHive
->FreeListMax
+= 32;
3681 /* Add new offset to free list, maintaining list in ascending order */
3682 if ((RegistryHive
->FreeListSize
== 0)
3683 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3685 /* Add to end of list */
3686 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3687 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3689 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3691 /* Add to begin of list */
3692 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3693 &RegistryHive
->FreeList
[0],
3694 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3695 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3696 &RegistryHive
->FreeListOffset
[0],
3697 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3698 RegistryHive
->FreeList
[0] = FreeBlock
;
3699 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3700 RegistryHive
->FreeListSize
++;
3704 /* Search where to insert */
3706 maxInd
= RegistryHive
->FreeListSize
- 1;
3707 while ((maxInd
- minInd
) > 1)
3709 medInd
= (minInd
+ maxInd
) / 2;
3710 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3716 /* Insert before maxInd */
3717 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3718 &RegistryHive
->FreeList
[maxInd
],
3719 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3720 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3721 &RegistryHive
->FreeListOffset
[maxInd
],
3722 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3723 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3724 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3725 RegistryHive
->FreeListSize
++;
3728 return STATUS_SUCCESS
;
3733 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3734 BLOCK_OFFSET BlockOffset
)
3741 if (IsNoFileHive(RegistryHive
))
3744 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3746 BlockNumber
= (ULONG
)BlockOffset
/ REG_BLOCK_SIZE
;
3748 Cell
= CmiGetCell (RegistryHive
,
3752 CellSize
= Cell
->CellSize
;
3754 CellSize
= -CellSize
;
3756 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, REG_BLOCK_SIZE
) -
3757 ROUND_DOWN(BlockOffset
, REG_BLOCK_SIZE
)) / REG_BLOCK_SIZE
;
3759 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3762 (Cell
->CellSize
< 0) ? "used" : "free",
3765 RegistryHive
->HiveDirty
= TRUE
;
3766 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3773 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3774 BLOCK_OFFSET BinOffset
)
3780 if (IsNoFileHive(RegistryHive
))
3783 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3785 BlockNumber
= (ULONG
)BinOffset
/ REG_BLOCK_SIZE
;
3787 Bin
= RegistryHive
->BlockList
[BlockNumber
].Bin
;
3789 BlockCount
= Bin
->BinSize
/ REG_BLOCK_SIZE
;
3791 DPRINT(" BlockNumber %lu BinSize %lu BlockCount %lu\n",
3796 RegistryHive
->HiveDirty
= TRUE
;
3797 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3804 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3805 OUT PBOOLEAN Packable
)
3809 if (Packable
!= NULL
)
3812 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3814 if (Name
->Buffer
[i
] & 0xFF00)
3816 if (Packable
!= NULL
)
3818 return Name
->Length
;
3822 return (Name
->Length
/ sizeof(WCHAR
));
3827 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3828 IN PUCHAR NameBuffer
,
3829 IN USHORT NameBufferSize
,
3830 IN BOOLEAN NamePacked
)
3835 if (NamePacked
== TRUE
)
3837 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3840 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3842 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3848 if (Name
->Length
!= NameBufferSize
)
3851 UNameBuffer
= (PWCHAR
)NameBuffer
;
3853 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3855 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3865 CmiCopyPackedName(PWCHAR NameBuffer
,
3866 PUCHAR PackedNameBuffer
,
3867 ULONG PackedNameSize
)
3871 for (i
= 0; i
< PackedNameSize
; i
++)
3872 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];
3877 CmiCompareHash(PUNICODE_STRING KeyName
,
3882 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3883 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3884 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3885 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3887 return (strncmp(Buffer
, HashString
, 4) == 0);
3892 CmiCompareHashI(PUNICODE_STRING KeyName
,
3897 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3898 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3899 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3900 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3902 return (_strnicmp(Buffer
, HashString
, 4) == 0);
3907 CmiCompareKeyNames(PUNICODE_STRING KeyName
,
3913 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3915 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3917 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3920 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3922 if (KeyName
->Buffer
[i
] != (WCHAR
)KeyCell
->Name
[i
])
3928 if (KeyName
->Length
!= KeyCell
->NameSize
)
3931 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3932 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3934 if (KeyName
->Buffer
[i
] != UnicodeName
[i
])
3944 CmiCompareKeyNamesI(PUNICODE_STRING KeyName
,
3950 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3952 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3954 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3957 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3959 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3960 RtlUpcaseUnicodeChar((WCHAR
)KeyCell
->Name
[i
]))
3966 if (KeyName
->Length
!= KeyCell
->NameSize
)
3969 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3970 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3972 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3973 RtlUpcaseUnicodeChar(UnicodeName
[i
]))
3983 CmiCopyKey (PREGISTRY_HIVE DstHive
,
3984 PKEY_CELL DstKeyCell
,
3985 PREGISTRY_HIVE SrcHive
,
3986 PKEY_CELL SrcKeyCell
)
3988 PKEY_CELL NewKeyCell
;
3989 ULONG NewKeyCellSize
;
3990 BLOCK_OFFSET NewKeyCellOffset
;
3991 PHASH_TABLE_CELL NewHashTableCell
;
3992 ULONG NewHashTableSize
;
3993 BLOCK_OFFSET NewHashTableOffset
;
3997 DPRINT ("CmiCopyKey() called\n");
3999 if (DstKeyCell
== NULL
)
4001 /* Allocate and copy key cell */
4002 NewKeyCellSize
= sizeof(KEY_CELL
) + SrcKeyCell
->NameSize
;
4003 Status
= CmiAllocateCell (DstHive
,
4005 (PVOID
) &NewKeyCell
,
4007 if (!NT_SUCCESS(Status
))
4009 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4012 if (NewKeyCell
== NULL
)
4014 DPRINT1 ("Failed to allocate a key cell\n");
4015 return STATUS_INSUFFICIENT_RESOURCES
;
4018 RtlCopyMemory (NewKeyCell
,
4022 DstHive
->HiveHeader
->RootKeyOffset
= NewKeyCellOffset
;
4024 /* Copy class name */
4025 if (SrcKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4027 PDATA_CELL SrcClassNameCell
;
4028 PDATA_CELL NewClassNameCell
;
4029 BLOCK_OFFSET NewClassNameOffset
;
4031 SrcClassNameCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ClassNameOffset
, NULL
),
4033 NewKeyCell
->ClassSize
= SrcKeyCell
->ClassSize
;
4034 Status
= CmiAllocateCell (DstHive
,
4035 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
4036 (PVOID
)&NewClassNameCell
,
4037 &NewClassNameOffset
);
4038 if (!NT_SUCCESS(Status
))
4040 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4044 RtlCopyMemory (NewClassNameCell
,
4046 NewKeyCell
->ClassSize
);
4047 NewKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4052 NewKeyCell
= DstKeyCell
;
4055 /* Allocate hash table */
4056 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4058 NewHashTableSize
= ROUND_UP(SrcKeyCell
->NumberOfSubKeys
+ 1, 4) - 1;
4059 Status
= CmiAllocateHashTableCell (DstHive
,
4061 &NewHashTableOffset
,
4063 if (!NT_SUCCESS(Status
))
4065 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status
);
4068 NewKeyCell
->HashTableOffset
= NewHashTableOffset
;
4071 /* Allocate and copy value list and values */
4072 if (SrcKeyCell
->NumberOfValues
!= 0)
4074 PVALUE_LIST_CELL NewValueListCell
;
4075 PVALUE_LIST_CELL SrcValueListCell
;
4076 PVALUE_CELL NewValueCell
;
4077 PVALUE_CELL SrcValueCell
;
4078 PDATA_CELL SrcValueDataCell
;
4079 PDATA_CELL NewValueDataCell
;
4080 BLOCK_OFFSET ValueCellOffset
;
4081 BLOCK_OFFSET ValueDataCellOffset
;
4082 ULONG NewValueListCellSize
;
4083 ULONG NewValueCellSize
;
4086 NewValueListCellSize
=
4087 ROUND_UP(SrcKeyCell
->NumberOfValues
, 4) * sizeof(BLOCK_OFFSET
);
4088 Status
= CmiAllocateCell (DstHive
,
4089 NewValueListCellSize
,
4090 (PVOID
)&NewValueListCell
,
4091 &NewKeyCell
->ValueListOffset
);
4092 if (!NT_SUCCESS(Status
))
4094 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4098 RtlZeroMemory (NewValueListCell
,
4099 NewValueListCellSize
);
4102 SrcValueListCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ValueListOffset
, NULL
);
4103 for (i
= 0; i
< SrcKeyCell
->NumberOfValues
; i
++)
4105 /* Copy value cell */
4106 SrcValueCell
= CmiGetCell (SrcHive
, SrcValueListCell
->ValueOffset
[i
], NULL
);
4108 NewValueCellSize
= sizeof(VALUE_CELL
) + SrcValueCell
->NameSize
;
4109 Status
= CmiAllocateCell (DstHive
,
4111 (PVOID
*) &NewValueCell
,
4113 if (!NT_SUCCESS(Status
))
4115 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4119 NewValueListCell
->ValueOffset
[i
] = ValueCellOffset
;
4120 RtlCopyMemory (NewValueCell
,
4124 /* Copy value data cell */
4125 if (SrcValueCell
->DataSize
> (LONG
) sizeof(PVOID
))
4127 SrcValueDataCell
= CmiGetCell (SrcHive
, SrcValueCell
->DataOffset
, NULL
);
4129 Status
= CmiAllocateCell (DstHive
,
4130 sizeof(CELL_HEADER
) + SrcValueCell
->DataSize
,
4131 (PVOID
*) &NewValueDataCell
,
4132 &ValueDataCellOffset
);
4133 if (!NT_SUCCESS(Status
))
4135 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4138 RtlCopyMemory (NewValueDataCell
,
4140 SrcValueCell
->DataSize
);
4141 NewValueCell
->DataOffset
= ValueDataCellOffset
;
4147 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4149 PHASH_TABLE_CELL SrcHashTableCell
;
4150 PKEY_CELL SrcSubKeyCell
;
4151 PKEY_CELL NewSubKeyCell
;
4152 ULONG NewSubKeyCellSize
;
4153 BLOCK_OFFSET NewSubKeyCellOffset
;
4154 PHASH_RECORD SrcHashRecord
;
4156 SrcHashTableCell
= CmiGetCell (SrcHive
,
4157 SrcKeyCell
->HashTableOffset
,
4160 for (i
= 0; i
< SrcKeyCell
->NumberOfSubKeys
; i
++)
4162 SrcHashRecord
= &SrcHashTableCell
->Table
[i
];
4163 SrcSubKeyCell
= CmiGetCell (SrcHive
, SrcHashRecord
->KeyOffset
, NULL
);
4165 /* Allocate and copy key cell */
4166 NewSubKeyCellSize
= sizeof(KEY_CELL
) + SrcSubKeyCell
->NameSize
;
4167 Status
= CmiAllocateCell (DstHive
,
4169 (PVOID
)&NewSubKeyCell
,
4170 &NewSubKeyCellOffset
);
4171 if (!NT_SUCCESS(Status
))
4173 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4176 if (NewKeyCell
== NULL
)
4178 DPRINT1 ("Failed to allocate a sub key cell\n");
4179 return STATUS_INSUFFICIENT_RESOURCES
;
4182 NewHashTableCell
->Table
[i
].KeyOffset
= NewSubKeyCellOffset
;
4183 NewHashTableCell
->Table
[i
].HashValue
= SrcHashRecord
->HashValue
;
4185 RtlCopyMemory (NewSubKeyCell
,
4189 /* Copy class name */
4190 if (SrcSubKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4192 PDATA_CELL SrcClassNameCell
;
4193 PDATA_CELL NewClassNameCell
;
4194 BLOCK_OFFSET NewClassNameOffset
;
4196 SrcClassNameCell
= CmiGetCell (SrcHive
,
4197 SrcSubKeyCell
->ClassNameOffset
,
4200 NewSubKeyCell
->ClassSize
= SrcSubKeyCell
->ClassSize
;
4201 Status
= CmiAllocateCell (DstHive
,
4202 sizeof(CELL_HEADER
) + NewSubKeyCell
->ClassSize
,
4203 (PVOID
)&NewClassNameCell
,
4204 &NewClassNameOffset
);
4205 if (!NT_SUCCESS(Status
))
4207 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4211 NewSubKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4212 RtlCopyMemory (NewClassNameCell
,
4214 NewSubKeyCell
->ClassSize
);
4217 /* Copy subkey data and subkeys */
4218 Status
= CmiCopyKey (DstHive
,
4222 if (!NT_SUCCESS(Status
))
4224 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4230 return STATUS_SUCCESS
;
4235 CmiSaveTempHive (PREGISTRY_HIVE Hive
,
4238 IO_STATUS_BLOCK IoStatusBlock
;
4239 LARGE_INTEGER FileOffset
;
4244 DPRINT ("CmiSaveTempHive() called\n");
4246 Hive
->HiveHeader
->Checksum
= CmiCalcChecksum ((PULONG
)Hive
->HiveHeader
);
4248 /* Write hive block */
4249 FileOffset
.QuadPart
= (ULONGLONG
)0;
4250 Status
= NtWriteFile (FileHandle
,
4256 sizeof(HIVE_HEADER
),
4259 if (!NT_SUCCESS(Status
))
4261 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4265 DPRINT ("Saving %lu blocks\n", Hive
->BlockListSize
);
4266 for (BlockIndex
= 0; BlockIndex
< Hive
->BlockListSize
; BlockIndex
++)
4268 BlockPtr
= Hive
->BlockList
[BlockIndex
].Block
;
4269 DPRINT ("BlockPtr %p\n", BlockPtr
);
4271 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
4272 DPRINT ("File offset %I64x\n", FileOffset
.QuadPart
);
4274 /* Write hive block */
4275 Status
= NtWriteFile (FileHandle
,
4284 if (!NT_SUCCESS(Status
))
4286 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4291 Status
= NtFlushBuffersFile (FileHandle
,
4293 if (!NT_SUCCESS(Status
))
4295 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
4298 DPRINT ("CmiSaveTempHive() done\n");