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
,
440 Status
= NtCreateFile(&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("NtCreateFile() failed (Status %lx)\n", Status
);
461 /* Try to open the log file */
462 InitializeObjectAttributes(&ObjectAttributes
,
463 &RegistryHive
->LogFileName
,
468 Status
= NtCreateFile(&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("NtCreateFile() 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
,
906 CreateDisposition
= FILE_OPEN_IF
;
907 Status
= NtCreateFile(&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("NtCreateFile() 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 ExInitializeResourceLite (&Hive
->HiveResource
);
1104 /* Acquire hive list lock exclusively */
1105 KeEnterCriticalRegion();
1106 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1109 /* Add the new hive to the hive list */
1110 InsertTailList (&CmiHiveListHead
,
1113 /* Release hive list lock */
1114 ExReleaseResourceLite (&CmiHiveListLock
);
1115 KeLeaveCriticalRegion();
1117 VERIFY_REGISTRY_HIVE (Hive
);
1119 *RegistryHive
= Hive
;
1121 return STATUS_SUCCESS
;
1126 CmiCreateTempHive(PREGISTRY_HIVE
*RegistryHive
)
1129 PCELL_HEADER FreeCell
;
1130 PREGISTRY_HIVE Hive
;
1133 DPRINT ("CmiCreateTempHive() called\n");
1135 *RegistryHive
= NULL
;
1137 Hive
= ExAllocatePool (NonPagedPool
,
1138 sizeof(REGISTRY_HIVE
));
1141 DPRINT1 ("Failed to allocate registry hive block\n");
1142 return STATUS_INSUFFICIENT_RESOURCES
;
1144 RtlZeroMemory (Hive
,
1145 sizeof(REGISTRY_HIVE
));
1147 DPRINT ("Hive %x\n", Hive
);
1149 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1151 if (Hive
->HiveHeader
== NULL
)
1153 DPRINT1 ("Failed to allocate hive header block\n");
1155 return STATUS_INSUFFICIENT_RESOURCES
;
1157 RtlZeroMemory (Hive
->HiveHeader
,
1160 DPRINT ("HiveHeader %x\n", Hive
->HiveHeader
);
1162 Hive
->Flags
= HIVE_NO_FILE
;
1164 RtlInitUnicodeString (&Hive
->HiveFileName
,
1166 RtlInitUnicodeString (&Hive
->LogFileName
,
1169 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1171 /* Allocate hive block list */
1172 Hive
->BlockList
= ExAllocatePool (NonPagedPool
,
1173 sizeof(PBLOCK_LIST_ENTRY
));
1174 if (Hive
->BlockList
== NULL
)
1176 DPRINT1 ("Failed to allocate hive block list\n");
1177 ExFreePool(Hive
->HiveHeader
);
1179 return STATUS_INSUFFICIENT_RESOURCES
;
1182 /* Allocate first Bin */
1183 Hive
->BlockList
[0].Bin
= ExAllocatePool (NonPagedPool
,
1185 if (Hive
->BlockList
[0].Bin
== NULL
)
1187 DPRINT1 ("Failed to allocate first bin\n");
1188 ExFreePool(Hive
->BlockList
);
1189 ExFreePool(Hive
->HiveHeader
);
1191 return STATUS_INSUFFICIENT_RESOURCES
;
1193 Hive
->BlockList
[0].Block
= (PVOID
)Hive
->BlockList
[0].Bin
;
1195 Hive
->FileSize
= 2* REG_BLOCK_SIZE
;
1196 Hive
->BlockListSize
= 1;
1197 Hive
->UpdateCounter
= Hive
->HiveHeader
->UpdateCounter1
;
1200 BinHeader
= Hive
->BlockList
[0].Bin
;
1201 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)BinHeader
+ REG_HBIN_DATA_OFFSET
);
1203 CmiCreateDefaultBinHeader (BinHeader
);
1206 BinHeader
->BinOffset
= 0;
1208 /* Offset to root key block */
1209 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
1211 /* The rest of the block is free */
1212 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
1214 /* Create the free cell list */
1215 Status
= CmiCreateHiveFreeCellList (Hive
);
1216 if (Hive
->BlockList
[0].Bin
== NULL
)
1218 DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status
);
1219 ExFreePool(Hive
->BlockList
[0].Bin
);
1220 ExFreePool(Hive
->BlockList
);
1221 ExFreePool(Hive
->HiveHeader
);
1227 ExInitializeResourceLite (&Hive
->HiveResource
);
1229 /* Acquire hive list lock exclusively */
1230 KeEnterCriticalRegion();
1231 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1234 /* Add the new hive to the hive list */
1235 InsertTailList (&CmiHiveListHead
,
1238 /* Release hive list lock */
1239 ExReleaseResourceLite (&CmiHiveListLock
);
1240 KeLeaveCriticalRegion();
1242 VERIFY_REGISTRY_HIVE (Hive
);
1244 *RegistryHive
= Hive
;
1246 return STATUS_SUCCESS
;
1251 CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1252 IN PUNICODE_STRING FileName
,
1255 PREGISTRY_HIVE Hive
;
1258 DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName
);
1260 if (Flags
& ~REG_NO_LAZY_FLUSH
)
1261 return STATUS_INVALID_PARAMETER
;
1263 Hive
= ExAllocatePool (NonPagedPool
,
1264 sizeof(REGISTRY_HIVE
));
1267 DPRINT1 ("Failed to allocate hive header.\n");
1268 return STATUS_INSUFFICIENT_RESOURCES
;
1270 RtlZeroMemory (Hive
,
1271 sizeof(REGISTRY_HIVE
));
1273 DPRINT ("Hive %x\n", Hive
);
1274 Hive
->Flags
= (Flags
& REG_NO_LAZY_FLUSH
) ? HIVE_NO_SYNCH
: 0;
1276 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool(NonPagedPool
,
1277 sizeof(HIVE_HEADER
));
1278 if (Hive
->HiveHeader
== NULL
)
1280 DPRINT1 ("Failed to allocate hive header.\n");
1282 return STATUS_INSUFFICIENT_RESOURCES
;
1285 RtlZeroMemory (Hive
->HiveHeader
,
1286 sizeof(HIVE_HEADER
));
1288 Status
= CmiInitNonVolatileRegistryHive (Hive
,
1290 if (!NT_SUCCESS (Status
))
1292 DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status
);
1293 ExFreePool (Hive
->HiveHeader
);
1298 ExInitializeResourceLite (&Hive
->HiveResource
);
1300 /* Add the new hive to the hive list */
1301 KeEnterCriticalRegion();
1302 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1304 InsertTailList (&CmiHiveListHead
,
1306 ExReleaseResourceLite (&CmiHiveListLock
);
1307 KeLeaveCriticalRegion();
1310 VERIFY_REGISTRY_HIVE(Hive
);
1313 Status
= CmiConnectHive (KeyObjectAttributes
,
1315 if (!NT_SUCCESS(Status
))
1317 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status
);
1318 // CmiRemoveRegistryHive (Hive);
1321 DPRINT ("CmiLoadHive() done\n");
1328 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
1330 if (RegistryHive
->Flags
& HIVE_POINTER
)
1331 return STATUS_UNSUCCESSFUL
;
1333 /* Acquire hive list lock exclusively */
1334 KeEnterCriticalRegion();
1335 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1338 /* Remove hive from hive list */
1339 RemoveEntryList (&RegistryHive
->HiveList
);
1341 /* Release hive list lock */
1342 ExReleaseResourceLite (&CmiHiveListLock
);
1343 KeLeaveCriticalRegion();
1345 /* Release file names */
1346 RtlFreeUnicodeString (&RegistryHive
->HiveFileName
);
1347 RtlFreeUnicodeString (&RegistryHive
->LogFileName
);
1349 /* Release hive bitmap */
1350 ExFreePool (RegistryHive
->BitmapBuffer
);
1352 /* Release free cell list */
1353 ExFreePool (RegistryHive
->FreeList
);
1354 ExFreePool (RegistryHive
->FreeListOffset
);
1356 /* Release hive resource */
1357 ExDeleteResource (&RegistryHive
->HiveResource
);
1359 /* Release bins and bin list */
1360 CmiFreeHiveBins (RegistryHive
);
1361 ExFreePool (RegistryHive
->BlockList
);
1363 /* Release hive header */
1364 ExFreePool (RegistryHive
->HiveHeader
);
1367 ExFreePool (RegistryHive
);
1369 return STATUS_SUCCESS
;
1374 CmiCalcChecksum(PULONG Buffer
)
1379 for (i
= 0; i
< 127; i
++)
1387 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
1389 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1390 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1391 OBJECT_ATTRIBUTES ObjectAttributes
;
1392 IO_STATUS_BLOCK IoStatusBlock
;
1394 LARGE_INTEGER FileOffset
;
1403 DPRINT("CmiStartLogUpdate() called\n");
1405 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1406 BufferSize
= sizeof(HIVE_HEADER
) +
1409 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1411 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1413 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
,
1417 DPRINT("ExAllocatePool() failed\n");
1418 return(STATUS_INSUFFICIENT_RESOURCES
);
1420 RtlZeroMemory (Buffer
,
1423 /* Open log file for writing */
1424 InitializeObjectAttributes(&ObjectAttributes
,
1425 &RegistryHive
->LogFileName
,
1430 Status
= NtCreateFile(&FileHandle
,
1435 FILE_ATTRIBUTE_NORMAL
,
1438 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1441 if (!NT_SUCCESS(Status
))
1443 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1448 /* Update firt update counter and checksum */
1449 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1450 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1452 /* Copy hive header */
1453 RtlCopyMemory(Buffer
,
1454 RegistryHive
->HiveHeader
,
1455 sizeof(HIVE_HEADER
));
1456 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1463 RegistryHive
->DirtyBitMap
.Buffer
,
1466 /* Write hive block and block bitmap */
1467 FileOffset
.QuadPart
= (ULONGLONG
)0;
1468 Status
= NtWriteFile(FileHandle
,
1477 if (!NT_SUCCESS(Status
))
1479 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1480 NtClose(FileHandle
);
1486 /* Write dirty blocks */
1487 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1491 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1494 if ((BlockIndex
== (ULONG
)-1) ||
1495 (BlockIndex
>= RegistryHive
->BlockListSize
))
1497 DPRINT("No more set bits\n");
1498 Status
= STATUS_SUCCESS
;
1502 DPRINT("Block %lu is dirty\n", BlockIndex
);
1504 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1505 DPRINT("BlockPtr %p\n", BlockPtr
);
1506 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1508 /* Write hive block */
1509 Status
= NtWriteFile(FileHandle
,
1518 if (!NT_SUCCESS(Status
))
1520 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1521 NtClose(FileHandle
);
1526 FileOffset
.QuadPart
+= (ULONGLONG
)REG_BLOCK_SIZE
;
1529 /* Truncate log file */
1530 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1531 Status
= NtSetInformationFile(FileHandle
,
1534 sizeof(FILE_END_OF_FILE_INFORMATION
),
1535 FileEndOfFileInformation
);
1536 if (!NT_SUCCESS(Status
))
1538 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1539 NtClose(FileHandle
);
1543 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1544 Status
= NtSetInformationFile(FileHandle
,
1546 &FileAllocationInfo
,
1547 sizeof(FILE_ALLOCATION_INFORMATION
),
1548 FileAllocationInformation
);
1549 if (!NT_SUCCESS(Status
))
1551 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1552 NtClose(FileHandle
);
1556 /* Flush the log file */
1557 Status
= NtFlushBuffersFile(FileHandle
,
1559 if (!NT_SUCCESS(Status
))
1561 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1564 NtClose(FileHandle
);
1571 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1573 OBJECT_ATTRIBUTES ObjectAttributes
;
1574 IO_STATUS_BLOCK IoStatusBlock
;
1576 LARGE_INTEGER FileOffset
;
1583 DPRINT("CmiFinishLogUpdate() called\n");
1585 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1586 BufferSize
= sizeof(HIVE_HEADER
) +
1589 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1591 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1593 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1596 DPRINT("ExAllocatePool() failed\n");
1597 return(STATUS_INSUFFICIENT_RESOURCES
);
1600 /* Open log file for writing */
1601 InitializeObjectAttributes(&ObjectAttributes
,
1602 &RegistryHive
->LogFileName
,
1607 Status
= NtCreateFile(&FileHandle
,
1612 FILE_ATTRIBUTE_NORMAL
,
1615 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1618 if (!NT_SUCCESS(Status
))
1620 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1625 /* Update first and second update counter and checksum */
1626 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1627 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1628 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1630 /* Copy hive header */
1631 RtlCopyMemory(Buffer
,
1632 RegistryHive
->HiveHeader
,
1633 sizeof(HIVE_HEADER
));
1634 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1636 /* Write empty block bitmap */
1644 /* Write hive block and block bitmap */
1645 FileOffset
.QuadPart
= (ULONGLONG
)0;
1646 Status
= NtWriteFile(FileHandle
,
1655 if (!NT_SUCCESS(Status
))
1657 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1658 NtClose(FileHandle
);
1665 /* Flush the log file */
1666 Status
= NtFlushBuffersFile(FileHandle
,
1668 if (!NT_SUCCESS(Status
))
1670 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1673 NtClose(FileHandle
);
1680 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1682 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1683 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1684 OBJECT_ATTRIBUTES ObjectAttributes
;
1685 IO_STATUS_BLOCK IoStatusBlock
;
1691 DPRINT("CmiCleanupLogUpdate() called\n");
1693 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1694 BufferSize
= sizeof(HIVE_HEADER
) +
1697 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1699 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1701 /* Open log file for writing */
1702 InitializeObjectAttributes(&ObjectAttributes
,
1703 &RegistryHive
->LogFileName
,
1708 Status
= NtCreateFile(&FileHandle
,
1713 FILE_ATTRIBUTE_NORMAL
,
1716 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1719 if (!NT_SUCCESS(Status
))
1721 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1725 /* Truncate log file */
1726 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1727 Status
= NtSetInformationFile(FileHandle
,
1730 sizeof(FILE_END_OF_FILE_INFORMATION
),
1731 FileEndOfFileInformation
);
1732 if (!NT_SUCCESS(Status
))
1734 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1735 NtClose(FileHandle
);
1739 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1740 Status
= NtSetInformationFile(FileHandle
,
1742 &FileAllocationInfo
,
1743 sizeof(FILE_ALLOCATION_INFORMATION
),
1744 FileAllocationInformation
);
1745 if (!NT_SUCCESS(Status
))
1747 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1748 NtClose(FileHandle
);
1752 /* Flush the log file */
1753 Status
= NtFlushBuffersFile(FileHandle
,
1755 if (!NT_SUCCESS(Status
))
1757 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1760 NtClose(FileHandle
);
1767 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1769 OBJECT_ATTRIBUTES ObjectAttributes
;
1770 IO_STATUS_BLOCK IoStatusBlock
;
1772 LARGE_INTEGER FileOffset
;
1777 DPRINT("CmiStartHiveUpdate() called\n");
1779 /* Open hive for writing */
1780 InitializeObjectAttributes(&ObjectAttributes
,
1781 &RegistryHive
->HiveFileName
,
1786 Status
= NtCreateFile(&FileHandle
,
1791 FILE_ATTRIBUTE_NORMAL
,
1794 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1797 if (!NT_SUCCESS(Status
))
1799 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1803 /* Update firt update counter and checksum */
1804 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1805 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1807 /* Write hive block */
1808 FileOffset
.QuadPart
= (ULONGLONG
)0;
1809 Status
= NtWriteFile(FileHandle
,
1814 RegistryHive
->HiveHeader
,
1815 sizeof(HIVE_HEADER
),
1818 if (!NT_SUCCESS(Status
))
1820 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1821 NtClose(FileHandle
);
1828 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1831 if ((BlockIndex
== (ULONG
)-1) ||
1832 (BlockIndex
>= RegistryHive
->BlockListSize
))
1834 DPRINT("No more set bits\n");
1835 Status
= STATUS_SUCCESS
;
1839 DPRINT("Block %lu is dirty\n", BlockIndex
);
1841 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1842 DPRINT(" BlockPtr %p\n", BlockPtr
);
1844 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
1845 DPRINT(" File offset %I64x\n", FileOffset
.QuadPart
);
1847 /* Write hive block */
1848 Status
= NtWriteFile(FileHandle
,
1857 if (!NT_SUCCESS(Status
))
1859 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1860 NtClose(FileHandle
);
1867 Status
= NtFlushBuffersFile(FileHandle
,
1869 if (!NT_SUCCESS(Status
))
1871 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1874 NtClose(FileHandle
);
1881 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1883 OBJECT_ATTRIBUTES ObjectAttributes
;
1884 IO_STATUS_BLOCK IoStatusBlock
;
1885 LARGE_INTEGER FileOffset
;
1889 DPRINT("CmiFinishHiveUpdate() called\n");
1891 InitializeObjectAttributes(&ObjectAttributes
,
1892 &RegistryHive
->HiveFileName
,
1897 Status
= NtCreateFile(&FileHandle
,
1902 FILE_ATTRIBUTE_NORMAL
,
1905 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1908 if (!NT_SUCCESS(Status
))
1910 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1914 /* Update second update counter and checksum */
1915 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1916 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1917 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1919 /* Write hive block */
1920 FileOffset
.QuadPart
= (ULONGLONG
)0;
1921 Status
= NtWriteFile(FileHandle
,
1926 RegistryHive
->HiveHeader
,
1927 sizeof(HIVE_HEADER
),
1930 if (!NT_SUCCESS(Status
))
1932 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1933 NtClose(FileHandle
);
1937 Status
= NtFlushBuffersFile(FileHandle
,
1939 if (!NT_SUCCESS(Status
))
1941 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1944 NtClose(FileHandle
);
1951 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1955 DPRINT("CmiFlushRegistryHive() called\n");
1957 if (RegistryHive
->HiveDirty
== FALSE
)
1959 return(STATUS_SUCCESS
);
1962 DPRINT("Hive '%wZ' is dirty\n",
1963 &RegistryHive
->HiveFileName
);
1964 DPRINT("Log file: '%wZ'\n",
1965 &RegistryHive
->LogFileName
);
1967 /* Update hive header modification time */
1968 NtQuerySystemTime(&RegistryHive
->HiveHeader
->DateModified
);
1970 /* Start log update */
1971 Status
= CmiStartLogUpdate(RegistryHive
);
1972 if (!NT_SUCCESS(Status
))
1974 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1978 /* Finish log update */
1979 Status
= CmiFinishLogUpdate(RegistryHive
);
1980 if (!NT_SUCCESS(Status
))
1982 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1986 /* Start hive update */
1987 Status
= CmiStartHiveUpdate(RegistryHive
);
1988 if (!NT_SUCCESS(Status
))
1990 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1994 /* Finish the hive update */
1995 Status
= CmiFinishHiveUpdate(RegistryHive
);
1996 if (!NT_SUCCESS(Status
))
1998 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
2002 /* Cleanup log update */
2003 Status
= CmiCleanupLogUpdate(RegistryHive
);
2004 if (!NT_SUCCESS(Status
))
2006 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
2010 /* Increment hive update counter */
2011 RegistryHive
->UpdateCounter
++;
2013 /* Clear dirty bitmap and dirty flag */
2014 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
2015 RegistryHive
->HiveDirty
= FALSE
;
2017 DPRINT("CmiFlushRegistryHive() done\n");
2019 return(STATUS_SUCCESS
);
2024 CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject
)
2031 VERIFY_KEY_OBJECT(KeyObject
);
2033 KeyCell
= KeyObject
->KeyCell
;
2034 VERIFY_KEY_CELL(KeyCell
);
2036 SubKeyCount
= (KeyCell
== NULL
) ? 0 : KeyCell
->NumberOfSubKeys
;
2038 /* Search for volatile or 'foreign' keys */
2039 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2041 CurKey
= KeyObject
->SubKeys
[i
];
2042 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2043 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2054 CmiGetMaxNameLength(PKEY_OBJECT KeyObject
)
2056 PHASH_TABLE_CELL HashBlock
;
2058 PKEY_CELL CurSubKeyCell
;
2064 VERIFY_KEY_OBJECT(KeyObject
);
2066 KeyCell
= KeyObject
->KeyCell
;
2067 VERIFY_KEY_CELL(KeyCell
);
2070 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2071 KeyCell
->HashTableOffset
,
2073 if (HashBlock
== NULL
)
2075 DPRINT("CmiGetBlock() failed\n");
2079 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2081 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2083 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2084 HashBlock
->Table
[i
].KeyOffset
,
2086 if (CurSubKeyCell
== NULL
)
2088 DPRINT("CmiGetBlock() failed\n");
2092 NameSize
= CurSubKeyCell
->NameSize
;
2093 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2095 NameSize
*= sizeof(WCHAR
);
2098 if (NameSize
> MaxName
)
2106 DPRINT ("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2107 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2109 CurKey
= KeyObject
->SubKeys
[i
];
2110 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2111 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2113 CurSubKeyCell
= CurKey
->KeyCell
;
2114 if (CurSubKeyCell
== NULL
)
2116 DPRINT("CmiGetBlock() failed\n");
2120 if ((CurSubKeyCell
->Flags
& REG_KEY_ROOT_CELL
) == REG_KEY_ROOT_CELL
)
2122 /* Use name of the key object */
2123 NameSize
= CurKey
->Name
.Length
;
2127 /* Use name of the key cell */
2128 NameSize
= CurSubKeyCell
->NameSize
;
2129 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2131 NameSize
*= sizeof(WCHAR
);
2134 DPRINT ("NameSize %lu\n", NameSize
);
2136 if (NameSize
> MaxName
)
2143 DPRINT ("MaxName %lu\n", MaxName
);
2150 CmiGetMaxClassLength(PKEY_OBJECT KeyObject
)
2152 PHASH_TABLE_CELL HashBlock
;
2154 PKEY_CELL CurSubKeyCell
;
2159 VERIFY_KEY_OBJECT(KeyObject
);
2161 KeyCell
= KeyObject
->KeyCell
;
2162 VERIFY_KEY_CELL(KeyCell
);
2165 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2166 KeyCell
->HashTableOffset
,
2168 if (HashBlock
== NULL
)
2170 DPRINT("CmiGetBlock() failed\n");
2174 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2176 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2178 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2179 HashBlock
->Table
[i
].KeyOffset
,
2181 if (CurSubKeyCell
== NULL
)
2183 DPRINT("CmiGetBlock() failed\n");
2187 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2189 MaxClass
= CurSubKeyCell
->ClassSize
;
2195 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2196 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2198 CurKey
= KeyObject
->SubKeys
[i
];
2199 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2200 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2202 CurSubKeyCell
= CurKey
->KeyCell
;
2203 if (CurSubKeyCell
== NULL
)
2205 DPRINT("CmiGetBlock() failed\n");
2209 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2211 MaxClass
= CurSubKeyCell
->ClassSize
;
2221 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
2224 PVALUE_LIST_CELL ValueListCell
;
2225 PVALUE_CELL CurValueCell
;
2230 VERIFY_KEY_CELL(KeyCell
);
2233 ValueListCell
= CmiGetCell (RegistryHive
,
2234 KeyCell
->ValueListOffset
,
2236 if (ValueListCell
== NULL
)
2238 DPRINT("CmiGetBlock() failed\n");
2242 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2244 CurValueCell
= CmiGetCell (RegistryHive
,
2245 ValueListCell
->ValueOffset
[i
],
2247 if (CurValueCell
== NULL
)
2249 DPRINT("CmiGetBlock() failed\n");
2252 if (CurValueCell
!= NULL
)
2254 Size
= CurValueCell
->NameSize
;
2255 if (CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
2257 Size
*= sizeof(WCHAR
);
2259 if (MaxValueName
< Size
)
2261 MaxValueName
= Size
;
2266 return MaxValueName
;
2271 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
2274 PVALUE_LIST_CELL ValueListCell
;
2275 PVALUE_CELL CurValueCell
;
2279 VERIFY_KEY_CELL(KeyCell
);
2282 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2283 if (ValueListCell
== NULL
)
2288 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2290 CurValueCell
= CmiGetCell (RegistryHive
,
2291 ValueListCell
->ValueOffset
[i
],NULL
);
2292 if ((CurValueCell
!= NULL
) &&
2293 (MaxValueData
< (LONG
)(CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2295 MaxValueData
= CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2299 return MaxValueData
;
2304 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
2305 IN PKEY_CELL KeyCell
,
2306 OUT PKEY_CELL
*SubKeyCell
,
2307 OUT BLOCK_OFFSET
*BlockOffset
,
2308 IN PUNICODE_STRING KeyName
,
2309 IN ACCESS_MASK DesiredAccess
,
2310 IN ULONG Attributes
)
2312 PHASH_TABLE_CELL HashBlock
;
2313 PKEY_CELL CurSubKeyCell
;
2316 VERIFY_KEY_CELL(KeyCell
);
2318 DPRINT("Scanning for sub key %wZ\n", KeyName
);
2320 assert(RegistryHive
);
2324 /* The key does not have any subkeys */
2325 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
2327 return STATUS_SUCCESS
;
2330 /* Get hash table */
2331 HashBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2332 if (HashBlock
== NULL
)
2334 DPRINT("CmiGetBlock() failed\n");
2335 return STATUS_UNSUCCESSFUL
;
2338 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
) && (i
< HashBlock
->HashTableSize
); i
++)
2340 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2342 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2343 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1 &&
2344 (HashBlock
->Table
[i
].HashValue
== 0 ||
2345 CmiCompareHashI(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2347 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2348 HashBlock
->Table
[i
].KeyOffset
,
2350 if (CurSubKeyCell
== NULL
)
2352 DPRINT("CmiGetBlock() failed\n");
2353 return STATUS_UNSUCCESSFUL
;
2356 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2358 *SubKeyCell
= CurSubKeyCell
;
2359 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2366 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2367 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2368 (HashBlock
->Table
[i
].HashValue
== 0 ||
2369 CmiCompareHash(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2371 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2372 HashBlock
->Table
[i
].KeyOffset
,
2374 if (CurSubKeyCell
== NULL
)
2376 DPRINT("CmiGetBlock() failed\n");
2377 return STATUS_UNSUCCESSFUL
;
2380 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2382 *SubKeyCell
= CurSubKeyCell
;
2383 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2390 return STATUS_SUCCESS
;
2395 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2396 PKEY_OBJECT ParentKey
,
2398 PUNICODE_STRING SubKeyName
,
2400 PUNICODE_STRING Class
,
2401 ULONG CreateOptions
)
2403 PHASH_TABLE_CELL HashBlock
;
2404 BLOCK_OFFSET NKBOffset
;
2405 PKEY_CELL NewKeyCell
;
2407 PKEY_CELL ParentKeyCell
;
2408 PDATA_CELL ClassCell
;
2415 ParentKeyCell
= ParentKey
->KeyCell
;
2417 VERIFY_KEY_CELL(ParentKeyCell
);
2419 /* Skip leading backslash */
2420 if (SubKeyName
->Buffer
[0] == L
'\\')
2422 NamePtr
= &SubKeyName
->Buffer
[1];
2423 NameSize
= SubKeyName
->Length
- sizeof(WCHAR
);
2427 NamePtr
= SubKeyName
->Buffer
;
2428 NameSize
= SubKeyName
->Length
;
2431 /* Check whether key name can be packed */
2433 for (i
= 0; i
< NameSize
/ sizeof(WCHAR
); i
++)
2435 if (NamePtr
[i
] & 0xFF00)
2442 /* Adjust name size */
2445 NameSize
= NameSize
/ sizeof(WCHAR
);
2448 DPRINT("Key %S Length %lu %s\n", NamePtr
, NameSize
, (Packable
)?"True":"False");
2450 Status
= STATUS_SUCCESS
;
2452 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2453 Status
= CmiAllocateCell (RegistryHive
,
2455 (PVOID
) &NewKeyCell
,
2457 if (NewKeyCell
== NULL
)
2459 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2463 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2464 NewKeyCell
->Flags
= 0;
2465 NtQuerySystemTime(&NewKeyCell
->LastWriteTime
);
2466 NewKeyCell
->ParentKeyOffset
= -1;
2467 NewKeyCell
->NumberOfSubKeys
= 0;
2468 NewKeyCell
->HashTableOffset
= -1;
2469 NewKeyCell
->NumberOfValues
= 0;
2470 NewKeyCell
->ValueListOffset
= -1;
2471 NewKeyCell
->SecurityKeyOffset
= -1;
2472 NewKeyCell
->ClassNameOffset
= -1;
2474 /* Pack the key name */
2475 NewKeyCell
->NameSize
= NameSize
;
2478 NewKeyCell
->Flags
|= REG_KEY_NAME_PACKED
;
2479 for (i
= 0; i
< NameSize
; i
++)
2481 NewKeyCell
->Name
[i
] = (CHAR
)(NamePtr
[i
] & 0x00FF);
2486 RtlCopyMemory(NewKeyCell
->Name
,
2491 VERIFY_KEY_CELL(NewKeyCell
);
2495 NewKeyCell
->ClassSize
= Class
->Length
;
2496 Status
= CmiAllocateCell (RegistryHive
,
2497 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
2499 &NewKeyCell
->ClassNameOffset
);
2500 RtlCopyMemory (ClassCell
->Data
,
2506 if (!NT_SUCCESS(Status
))
2511 SubKey
->KeyCell
= NewKeyCell
;
2512 SubKey
->KeyCellOffset
= NKBOffset
;
2514 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2515 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(ParentKey
->RegistryHive
)))
2520 if (ParentKeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2522 Status
= CmiAllocateHashTableCell (RegistryHive
,
2524 &ParentKeyCell
->HashTableOffset
,
2525 REG_INIT_HASH_TABLE_SIZE
);
2526 if (!NT_SUCCESS(Status
))
2533 HashBlock
= CmiGetCell (RegistryHive
,
2534 ParentKeyCell
->HashTableOffset
,
2536 if (HashBlock
== NULL
)
2538 DPRINT("CmiGetCell() failed\n");
2539 return STATUS_UNSUCCESSFUL
;
2542 if (((ParentKeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2544 PHASH_TABLE_CELL NewHashBlock
;
2545 BLOCK_OFFSET HTOffset
;
2547 /* Reallocate the hash table cell */
2548 Status
= CmiAllocateHashTableCell (RegistryHive
,
2551 HashBlock
->HashTableSize
+
2552 REG_EXTEND_HASH_TABLE_SIZE
);
2553 if (!NT_SUCCESS(Status
))
2558 RtlZeroMemory(&NewHashBlock
->Table
[0],
2559 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2560 RtlCopyMemory(&NewHashBlock
->Table
[0],
2561 &HashBlock
->Table
[0],
2562 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2563 CmiDestroyCell (RegistryHive
,
2565 ParentKeyCell
->HashTableOffset
);
2566 ParentKeyCell
->HashTableOffset
= HTOffset
;
2567 HashBlock
= NewHashBlock
;
2571 Status
= CmiAddKeyToHashTable(RegistryHive
,
2573 ParentKeyCell
->HashTableOffset
,
2576 if (NT_SUCCESS(Status
))
2578 ParentKeyCell
->NumberOfSubKeys
++;
2581 NtQuerySystemTime (&ParentKeyCell
->LastWriteTime
);
2582 CmiMarkBlockDirty (RegistryHive
, ParentKey
->KeyCellOffset
);
2589 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2590 PKEY_OBJECT ParentKey
,
2593 PHASH_TABLE_CELL HashBlock
;
2594 PVALUE_LIST_CELL ValueList
;
2595 PVALUE_CELL ValueCell
;
2596 PDATA_CELL DataCell
;
2599 DPRINT("CmiRemoveSubKey() called\n");
2601 /* Remove all values */
2602 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2604 /* Get pointer to the value list cell */
2605 ValueList
= CmiGetCell (RegistryHive
,
2606 SubKey
->KeyCell
->ValueListOffset
,
2608 if (ValueList
== NULL
)
2610 DPRINT("CmiGetCell() failed\n");
2611 return STATUS_UNSUCCESSFUL
;
2614 if (ValueList
!= NULL
)
2616 /* Enumerate all values */
2617 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2619 /* Get pointer to value cell */
2620 ValueCell
= CmiGetCell (RegistryHive
,
2621 ValueList
->ValueOffset
[i
],
2623 if (ValueCell
!= NULL
)
2625 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
2627 DataCell
= CmiGetCell (RegistryHive
,
2628 ValueCell
->DataOffset
,
2630 if (DataCell
== NULL
)
2632 DPRINT("CmiGetCell() failed\n");
2633 return STATUS_UNSUCCESSFUL
;
2636 if (DataCell
!= NULL
)
2638 /* Destroy data cell */
2639 CmiDestroyCell (RegistryHive
,
2641 ValueCell
->DataOffset
);
2645 /* Destroy value cell */
2646 CmiDestroyCell (RegistryHive
,
2648 ValueList
->ValueOffset
[i
]);
2653 /* Destroy value list cell */
2654 CmiDestroyCell (RegistryHive
,
2656 SubKey
->KeyCell
->ValueListOffset
);
2658 SubKey
->KeyCell
->NumberOfValues
= 0;
2659 SubKey
->KeyCell
->ValueListOffset
= (BLOCK_OFFSET
)-1;
2662 /* Remove the key from the parent key's hash block */
2663 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2665 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2666 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2667 ParentKey
->KeyCell
->HashTableOffset
,
2669 if (HashBlock
== NULL
)
2671 DPRINT("CmiGetCell() failed\n");
2672 return STATUS_UNSUCCESSFUL
;
2674 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2675 if (HashBlock
!= NULL
)
2677 CmiRemoveKeyFromHashTable(ParentKey
->RegistryHive
,
2679 SubKey
->KeyCellOffset
);
2680 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2681 ParentKey
->KeyCell
->HashTableOffset
);
2685 /* Remove the key's hash block */
2686 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2688 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
);
2689 HashBlock
= CmiGetCell (RegistryHive
,
2690 SubKey
->KeyCell
->HashTableOffset
,
2692 if (HashBlock
== NULL
)
2694 DPRINT("CmiGetCell() failed\n");
2695 return STATUS_UNSUCCESSFUL
;
2697 DPRINT("SubKey HashBlock %p\n", HashBlock
);
2698 if (HashBlock
!= NULL
)
2700 CmiDestroyCell (RegistryHive
,
2702 SubKey
->KeyCell
->HashTableOffset
);
2703 SubKey
->KeyCell
->HashTableOffset
= -1;
2707 /* Decrement the number of the parent key's sub keys */
2708 if (ParentKey
!= NULL
)
2710 DPRINT("ParentKey %p\n", ParentKey
);
2711 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2713 /* Remove the parent key's hash table */
2714 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2716 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2717 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2718 ParentKey
->KeyCell
->HashTableOffset
,
2720 if (HashBlock
== NULL
)
2722 DPRINT("CmiGetCell() failed\n");
2723 return STATUS_UNSUCCESSFUL
;
2725 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2726 if (HashBlock
!= NULL
)
2728 CmiDestroyCell (ParentKey
->RegistryHive
,
2730 ParentKey
->KeyCell
->HashTableOffset
);
2731 ParentKey
->KeyCell
->HashTableOffset
= (BLOCK_OFFSET
)-1;
2735 NtQuerySystemTime(&ParentKey
->KeyCell
->LastWriteTime
);
2736 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2737 ParentKey
->KeyCellOffset
);
2740 /* Destroy key cell */
2741 CmiDestroyCell (RegistryHive
,
2743 SubKey
->KeyCellOffset
);
2744 SubKey
->KeyCell
= NULL
;
2745 SubKey
->KeyCellOffset
= (BLOCK_OFFSET
)-1;
2747 return(STATUS_SUCCESS
);
2752 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2753 IN PKEY_CELL KeyCell
,
2754 IN PUNICODE_STRING ValueName
,
2755 OUT PVALUE_CELL
*ValueCell
,
2756 OUT BLOCK_OFFSET
*ValueCellOffset
)
2758 PVALUE_LIST_CELL ValueListCell
;
2759 PVALUE_CELL CurValueCell
;
2763 if (ValueCellOffset
!= NULL
)
2764 *ValueCellOffset
= (BLOCK_OFFSET
)-1;
2766 /* The key does not have any values */
2767 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2769 return STATUS_OBJECT_NAME_NOT_FOUND
;
2772 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2773 if (ValueListCell
== NULL
)
2775 DPRINT("ValueListCell is NULL\n");
2776 return STATUS_UNSUCCESSFUL
;
2779 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2781 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2783 CurValueCell
= CmiGetCell (RegistryHive
,
2784 ValueListCell
->ValueOffset
[i
],
2786 if (CurValueCell
== NULL
)
2788 DPRINT("CmiGetBlock() failed\n");
2789 return STATUS_UNSUCCESSFUL
;
2792 if ((CurValueCell
!= NULL
) &&
2793 CmiComparePackedNames(ValueName
,
2795 CurValueCell
->NameSize
,
2796 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2798 *ValueCell
= CurValueCell
;
2799 if (ValueCellOffset
!= NULL
)
2800 *ValueCellOffset
= ValueListCell
->ValueOffset
[i
];
2801 //DPRINT("Found value %s\n", ValueName);
2802 return STATUS_SUCCESS
;
2806 return STATUS_OBJECT_NAME_NOT_FOUND
;
2811 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2812 IN PKEY_CELL KeyCell
,
2814 OUT PVALUE_CELL
*ValueCell
)
2816 PVALUE_LIST_CELL ValueListCell
;
2817 PVALUE_CELL CurValueCell
;
2821 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2823 return STATUS_NO_MORE_ENTRIES
;
2826 if (Index
>= KeyCell
->NumberOfValues
)
2828 return STATUS_NO_MORE_ENTRIES
;
2832 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2833 if (ValueListCell
== NULL
)
2835 DPRINT("CmiGetBlock() failed\n");
2836 return STATUS_UNSUCCESSFUL
;
2839 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2842 CurValueCell
= CmiGetCell (RegistryHive
,
2843 ValueListCell
->ValueOffset
[Index
],
2845 if (CurValueCell
== NULL
)
2847 DPRINT("CmiGetBlock() failed\n");
2848 return STATUS_UNSUCCESSFUL
;
2851 *ValueCell
= CurValueCell
;
2853 return STATUS_SUCCESS
;
2858 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2859 IN PKEY_CELL KeyCell
,
2860 IN BLOCK_OFFSET KeyCellOffset
,
2861 IN PUNICODE_STRING ValueName
,
2862 OUT PVALUE_CELL
*pValueCell
,
2863 OUT BLOCK_OFFSET
*pValueCellOffset
)
2865 PVALUE_LIST_CELL NewValueListCell
;
2866 PVALUE_LIST_CELL ValueListCell
;
2867 PVALUE_CELL NewValueCell
;
2868 BLOCK_OFFSET NewValueListCellOffset
;
2869 BLOCK_OFFSET ValueListCellOffset
;
2870 BLOCK_OFFSET NewValueCellOffset
;
2874 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG
)KeyCell
->ValueListOffset
);
2876 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2877 if (ValueListCell
== NULL
)
2879 CellSize
= sizeof(VALUE_LIST_CELL
) +
2880 (3 * sizeof(BLOCK_OFFSET
));
2881 Status
= CmiAllocateCell (RegistryHive
,
2883 (PVOID
) &ValueListCell
,
2884 &ValueListCellOffset
);
2885 if (!NT_SUCCESS(Status
))
2890 KeyCell
->ValueListOffset
= ValueListCellOffset
;
2891 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2892 CmiMarkBlockDirty(RegistryHive
, ValueListCellOffset
);
2894 else if (KeyCell
->NumberOfValues
>=
2895 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
)))
2897 CellSize
= sizeof(VALUE_LIST_CELL
) +
2898 ((KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) * sizeof(BLOCK_OFFSET
));
2899 Status
= CmiAllocateCell (RegistryHive
,
2901 (PVOID
) &NewValueListCell
,
2902 &NewValueListCellOffset
);
2903 if (!NT_SUCCESS(Status
))
2908 RtlCopyMemory(&NewValueListCell
->ValueOffset
[0],
2909 &ValueListCell
->ValueOffset
[0],
2910 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2911 CmiDestroyCell (RegistryHive
, ValueListCell
, KeyCell
->ValueListOffset
);
2912 CmiMarkBlockDirty (RegistryHive
, KeyCell
->ValueListOffset
);
2914 KeyCell
->ValueListOffset
= NewValueListCellOffset
;
2915 ValueListCell
= NewValueListCell
;
2916 CmiMarkBlockDirty (RegistryHive
, KeyCellOffset
);
2917 CmiMarkBlockDirty (RegistryHive
, NewValueListCellOffset
);
2920 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2921 KeyCell
->NumberOfValues
,
2922 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2923 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
),
2924 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
));
2926 Status
= CmiAllocateValueCell(RegistryHive
,
2928 &NewValueCellOffset
,
2930 if (!NT_SUCCESS(Status
))
2935 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = NewValueCellOffset
;
2936 KeyCell
->NumberOfValues
++;
2938 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2939 CmiMarkBlockDirty(RegistryHive
, KeyCell
->ValueListOffset
);
2940 CmiMarkBlockDirty(RegistryHive
, NewValueCellOffset
);
2942 *pValueCell
= NewValueCell
;
2943 *pValueCellOffset
= NewValueCellOffset
;
2945 return STATUS_SUCCESS
;
2950 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2951 IN PKEY_CELL KeyCell
,
2952 IN BLOCK_OFFSET KeyCellOffset
,
2953 IN PUNICODE_STRING ValueName
)
2955 PVALUE_LIST_CELL ValueListCell
;
2956 PVALUE_CELL CurValueCell
;
2959 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2961 if (ValueListCell
== NULL
)
2963 DPRINT("CmiGetBlock() failed\n");
2964 return STATUS_SUCCESS
;
2967 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2969 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2971 CurValueCell
= CmiGetCell (RegistryHive
, ValueListCell
->ValueOffset
[i
], NULL
);
2972 if (CurValueCell
== NULL
)
2974 DPRINT("CmiGetBlock() failed\n");
2975 return STATUS_UNSUCCESSFUL
;
2978 if ((CurValueCell
!= NULL
) &&
2979 CmiComparePackedNames(ValueName
,
2981 CurValueCell
->NameSize
,
2982 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2984 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->ValueOffset
[i
]);
2986 if ((KeyCell
->NumberOfValues
- 1) < i
)
2988 RtlCopyMemory(&ValueListCell
->ValueOffset
[i
],
2989 &ValueListCell
->ValueOffset
[i
+ 1],
2990 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2994 RtlZeroMemory(&ValueListCell
->ValueOffset
[i
], sizeof(BLOCK_OFFSET
));
2997 KeyCell
->NumberOfValues
-= 1;
3002 if (KeyCell
->NumberOfValues
== 0)
3004 CmiDestroyCell (RegistryHive
,
3006 KeyCell
->ValueListOffset
);
3010 CmiMarkBlockDirty(RegistryHive
,
3011 KeyCell
->ValueListOffset
);
3014 CmiMarkBlockDirty(RegistryHive
,
3017 return STATUS_SUCCESS
;
3022 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive
,
3023 OUT PHASH_TABLE_CELL
*HashBlock
,
3024 OUT BLOCK_OFFSET
*HBOffset
,
3025 IN ULONG SubKeyCount
)
3027 PHASH_TABLE_CELL NewHashBlock
;
3031 Status
= STATUS_SUCCESS
;
3033 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
3034 (SubKeyCount
* sizeof(HASH_RECORD
));
3035 Status
= CmiAllocateCell (RegistryHive
,
3037 (PVOID
*) &NewHashBlock
,
3040 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
3042 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3046 assert(SubKeyCount
<= 0xffff); /* should really be USHORT_MAX or similar */
3047 NewHashBlock
->Id
= REG_HASH_TABLE_CELL_ID
;
3048 NewHashBlock
->HashTableSize
= (USHORT
)SubKeyCount
;
3049 *HashBlock
= NewHashBlock
;
3057 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
3058 PHASH_TABLE_CELL HashBlock
,
3061 BLOCK_OFFSET KeyOffset
;
3064 if (HashBlock
== NULL
)
3067 if (IsPointerHive(RegistryHive
))
3069 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
3073 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
3074 KeyCell
= CmiGetCell (RegistryHive
, KeyOffset
, NULL
);
3082 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
3083 PHASH_TABLE_CELL HashCell
,
3084 BLOCK_OFFSET HashCellOffset
,
3085 PKEY_CELL NewKeyCell
,
3086 BLOCK_OFFSET NKBOffset
)
3090 for (i
= 0; i
< HashCell
->HashTableSize
; i
++)
3092 if (HashCell
->Table
[i
].KeyOffset
== 0)
3094 HashCell
->Table
[i
].KeyOffset
= NKBOffset
;
3095 HashCell
->Table
[i
].HashValue
= 0;
3096 if (NewKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3098 RtlCopyMemory(&HashCell
->Table
[i
].HashValue
,
3100 min(NewKeyCell
->NameSize
, sizeof(ULONG
)));
3102 CmiMarkBlockDirty(RegistryHive
, HashCellOffset
);
3103 return STATUS_SUCCESS
;
3107 return STATUS_UNSUCCESSFUL
;
3112 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
3113 PHASH_TABLE_CELL HashBlock
,
3114 BLOCK_OFFSET NKBOffset
)
3118 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3120 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
3122 HashBlock
->Table
[i
].KeyOffset
= 0;
3123 HashBlock
->Table
[i
].HashValue
= 0;
3124 return STATUS_SUCCESS
;
3128 return STATUS_UNSUCCESSFUL
;
3133 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
3134 PVALUE_CELL
*ValueCell
,
3135 BLOCK_OFFSET
*VBOffset
,
3136 IN PUNICODE_STRING ValueName
)
3138 PVALUE_CELL NewValueCell
;
3144 Status
= STATUS_SUCCESS
;
3146 NameSize
= CmiGetPackedNameLength(ValueName
,
3149 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
3151 Status
= CmiAllocateCell (RegistryHive
,
3152 sizeof(VALUE_CELL
) + NameSize
,
3153 (PVOID
*) &NewValueCell
,
3155 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
3157 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3161 assert(NameSize
<= 0xffff); /* should really be USHORT_MAX or similar */
3162 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
3163 NewValueCell
->NameSize
= (USHORT
)NameSize
;
3166 /* Pack the value name */
3167 for (i
= 0; i
< NameSize
; i
++)
3168 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
3169 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
3173 /* Copy the value name */
3174 RtlCopyMemory(NewValueCell
->Name
,
3177 NewValueCell
->Flags
= 0;
3179 NewValueCell
->DataType
= 0;
3180 NewValueCell
->DataSize
= 0;
3181 NewValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
3182 *ValueCell
= NewValueCell
;
3190 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
3191 PVALUE_CELL ValueCell
,
3192 BLOCK_OFFSET VBOffset
)
3198 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell
, VBOffset
);
3200 VERIFY_VALUE_CELL(ValueCell
);
3202 /* Destroy the data cell */
3203 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
3205 pBlock
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, &pBin
);
3208 DPRINT("CmiGetBlock() failed\n");
3209 return STATUS_UNSUCCESSFUL
;
3212 Status
= CmiDestroyCell (RegistryHive
, pBlock
, ValueCell
->DataOffset
);
3213 if (!NT_SUCCESS(Status
))
3218 /* Update time of heap */
3219 if (!IsNoFileHive(RegistryHive
))
3220 NtQuerySystemTime(&pBin
->DateModified
);
3223 /* Destroy the value cell */
3224 Status
= CmiDestroyCell (RegistryHive
, ValueCell
, VBOffset
);
3226 /* Update time of heap */
3227 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, VBOffset
, &pBin
))
3229 NtQuerySystemTime(&pBin
->DateModified
);
3237 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
3240 BLOCK_OFFSET
*NewBlockOffset
)
3242 PBLOCK_LIST_ENTRY BlockList
;
3243 PCELL_HEADER tmpBlock
;
3248 DPRINT ("CmiAddBin (BlockCount %lu)\n", BlockCount
);
3250 BinSize
= BlockCount
* REG_BLOCK_SIZE
;
3251 tmpBin
= ExAllocatePool(PagedPool
, BinSize
);
3254 return STATUS_INSUFFICIENT_RESOURCES
;
3256 RtlZeroMemory (tmpBin
,
3259 tmpBin
->HeaderId
= REG_BIN_ID
;
3260 tmpBin
->BinOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
3261 RegistryHive
->FileSize
+= BinSize
;
3262 tmpBin
->BinSize
= BinSize
;
3263 tmpBin
->Unused1
= 0;
3264 NtQuerySystemTime(&tmpBin
->DateModified
);
3265 tmpBin
->Unused2
= 0;
3267 DPRINT (" BinOffset %lx BinSize %lx\n", tmpBin
->BinOffset
,tmpBin
->BinSize
);
3269 /* Allocate new block list */
3270 BlockList
= ExAllocatePool(NonPagedPool
,
3271 sizeof(BLOCK_LIST_ENTRY
) * (RegistryHive
->BlockListSize
+ BlockCount
));
3272 if (BlockList
== NULL
)
3275 return STATUS_INSUFFICIENT_RESOURCES
;
3278 if (RegistryHive
->BlockListSize
> 0)
3280 RtlCopyMemory (BlockList
,
3281 RegistryHive
->BlockList
,
3282 sizeof(BLOCK_LIST_ENTRY
) * RegistryHive
->BlockListSize
);
3283 ExFreePool(RegistryHive
->BlockList
);
3286 RegistryHive
->BlockList
= BlockList
;
3287 for (i
= 0; i
< BlockCount
; i
++)
3289 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Block
=
3290 (PVOID
)((ULONG_PTR
)tmpBin
+ (i
* REG_BLOCK_SIZE
));
3291 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Bin
= tmpBin
;
3293 RegistryHive
->BlockListSize
+= BlockCount
;
3295 /* Initialize a free block in this heap : */
3296 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
3297 tmpBlock
->CellSize
= (BinSize
- REG_HBIN_DATA_OFFSET
);
3299 /* Grow bitmap if necessary */
3300 if (IsNoFileHive(RegistryHive
) &&
3301 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
3303 PULONG BitmapBuffer
;
3306 DPRINT("Grow hive bitmap\n");
3308 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3309 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
3310 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
3311 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
3312 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
3314 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
3315 RtlCopyMemory(BitmapBuffer
,
3316 RegistryHive
->DirtyBitMap
.Buffer
,
3317 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
3318 ExFreePool(RegistryHive
->BitmapBuffer
);
3319 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
3320 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
3321 RegistryHive
->BitmapBuffer
,
3325 *NewBlock
= (PVOID
) tmpBlock
;
3328 *NewBlockOffset
= tmpBin
->BinOffset
+ REG_HBIN_DATA_OFFSET
;
3330 /* Mark new bin dirty */
3331 CmiMarkBinDirty(RegistryHive
,
3334 return STATUS_SUCCESS
;
3339 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
3342 BLOCK_OFFSET
*CellOffset
)
3344 PCELL_HEADER NewCell
;
3350 /* Round to 16 bytes multiple */
3351 CellSize
= ROUND_UP(CellSize
, 16);
3353 /* Handle volatile hives first */
3354 if (IsPointerHive(RegistryHive
))
3356 NewCell
= ExAllocatePool(NonPagedPool
, CellSize
);
3357 if (NewCell
== NULL
)
3359 return STATUS_INSUFFICIENT_RESOURCES
;
3362 RtlZeroMemory (NewCell
,
3364 NewCell
->CellSize
= -CellSize
;
3367 if (CellOffset
!= NULL
)
3368 *CellOffset
= (BLOCK_OFFSET
) NewCell
;
3372 /* first search in free blocks */
3374 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3376 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
3378 NewCell
= RegistryHive
->FreeList
[i
];
3379 if (CellOffset
!= NULL
)
3380 *CellOffset
= RegistryHive
->FreeListOffset
[i
];
3382 /* Update time of heap */
3383 Temp
= CmiGetCell (RegistryHive
,
3384 RegistryHive
->FreeListOffset
[i
],
3388 DPRINT("CmiGetBlock() failed\n");
3389 return STATUS_UNSUCCESSFUL
;
3392 NtQuerySystemTime(&Bin
->DateModified
);
3393 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
3395 if ((i
+ 1) < RegistryHive
->FreeListSize
)
3397 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
3398 &RegistryHive
->FreeList
[i
+ 1],
3399 sizeof(RegistryHive
->FreeList
[0])
3400 * (RegistryHive
->FreeListSize
- i
- 1));
3401 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
3402 &RegistryHive
->FreeListOffset
[i
+ 1],
3403 sizeof(RegistryHive
->FreeListOffset
[0])
3404 * (RegistryHive
->FreeListSize
- i
- 1));
3406 RegistryHive
->FreeListSize
--;
3411 /* Need to extend hive file : */
3412 if (NewCell
== NULL
)
3415 Status
= CmiAddBin(RegistryHive
,
3416 ((CellSize
+ sizeof(HBIN
) - 1) / REG_BLOCK_SIZE
) + 1,
3419 if (!NT_SUCCESS(Status
))
3425 /* Split the block in two parts */
3426 if (NewCell
->CellSize
> CellSize
)
3428 NewCell
= (PCELL_HEADER
) ((ULONG_PTR
) NewCell
+ CellSize
);
3429 NewCell
->CellSize
= ((PCELL_HEADER
) (*Cell
))->CellSize
- CellSize
;
3430 CmiAddFree(RegistryHive
,
3432 *CellOffset
+ CellSize
,
3434 CmiMarkBlockDirty(RegistryHive
,
3435 *CellOffset
+ CellSize
);
3437 else if (NewCell
->CellSize
< CellSize
)
3439 return STATUS_UNSUCCESSFUL
;
3442 RtlZeroMemory(*Cell
,
3444 ((PCELL_HEADER
) (*Cell
))->CellSize
= -CellSize
;
3447 return STATUS_SUCCESS
;
3452 CmiDestroyCell (PREGISTRY_HIVE RegistryHive
,
3454 BLOCK_OFFSET CellOffset
)
3459 Status
= STATUS_SUCCESS
;
3461 if (IsPointerHive(RegistryHive
))
3467 PCELL_HEADER pFree
= Cell
;
3469 if (pFree
->CellSize
< 0)
3470 pFree
->CellSize
= -pFree
->CellSize
;
3472 /* Clear block (except the block size) */
3473 RtlZeroMemory(((char*)pFree
) + sizeof(ULONG
),
3474 pFree
->CellSize
- sizeof(ULONG
));
3476 /* Add block to the list of free blocks */
3477 CmiAddFree(RegistryHive
, Cell
, CellOffset
, TRUE
);
3479 /* Update time of heap */
3480 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, CellOffset
,&pBin
))
3481 NtQuerySystemTime(&pBin
->DateModified
);
3483 CmiMarkBlockDirty(RegistryHive
, CellOffset
);
3491 CmiGetCell (PREGISTRY_HIVE RegistryHive
,
3492 BLOCK_OFFSET CellOffset
,
3502 if (CellOffset
== (BLOCK_OFFSET
)-1)
3507 if (IsPointerHive (RegistryHive
))
3509 return (PVOID
)CellOffset
;
3512 if (CellOffset
> RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
)
3514 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3515 CellOffset
, RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
);
3519 pBin
= RegistryHive
->BlockList
[CellOffset
/ REG_BLOCK_SIZE
].Bin
;
3530 return((PVOID
)((ULONG_PTR
)pBin
+ (CellOffset
- pBin
->BinOffset
)));
3535 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3536 PCELL_HEADER FreeBlock
,
3537 BLOCK_OFFSET FreeOffset
)
3539 BLOCK_OFFSET BlockOffset
;
3540 BLOCK_OFFSET BinOffset
;
3546 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3547 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3549 CmiGetCell (RegistryHive
,
3552 DPRINT("Bin %p\n", Bin
);
3556 BinOffset
= Bin
->BinOffset
;
3557 BinSize
= Bin
->BinSize
;
3558 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3560 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3562 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3563 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3564 if (BlockOffset
> BinOffset
&&
3565 BlockOffset
< BinOffset
+ BinSize
)
3567 DPRINT("Free block: Offset %lx Size %lx\n",
3568 BlockOffset
, BlockSize
);
3570 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3571 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3572 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3574 DPRINT("Merge current block with previous and next block\n");
3576 RegistryHive
->FreeList
[i
]->CellSize
+=
3577 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3579 FreeBlock
->CellSize
= 0;
3580 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3583 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3585 RtlMoveMemory(&RegistryHive
->FreeList
[i
+ 1],
3586 &RegistryHive
->FreeList
[i
+ 2],
3587 sizeof(RegistryHive
->FreeList
[0])
3588 * (RegistryHive
->FreeListSize
- i
- 2));
3589 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3590 &RegistryHive
->FreeListOffset
[i
+ 2],
3591 sizeof(RegistryHive
->FreeListOffset
[0])
3592 * (RegistryHive
->FreeListSize
- i
- 2));
3594 RegistryHive
->FreeListSize
--;
3596 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3600 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3602 DPRINT("Merge current block with previous block\n");
3604 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3605 FreeBlock
->CellSize
= 0;
3607 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3611 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3613 DPRINT("Merge current block with next block\n");
3615 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3616 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3617 RegistryHive
->FreeList
[i
] = FreeBlock
;
3618 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3620 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3632 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3633 PCELL_HEADER FreeBlock
,
3634 BLOCK_OFFSET FreeOffset
,
3635 BOOLEAN MergeFreeBlocks
)
3637 PCELL_HEADER
*tmpList
;
3638 BLOCK_OFFSET
*tmpListOffset
;
3643 assert(RegistryHive
);
3646 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3647 FreeBlock
, FreeOffset
);
3649 /* Merge free blocks */
3650 if (MergeFreeBlocks
== TRUE
)
3652 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3653 return(STATUS_SUCCESS
);
3656 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3658 tmpList
= ExAllocatePool(PagedPool
,
3659 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3660 if (tmpList
== NULL
)
3661 return STATUS_INSUFFICIENT_RESOURCES
;
3663 tmpListOffset
= ExAllocatePool(PagedPool
,
3664 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3666 if (tmpListOffset
== NULL
)
3668 ExFreePool(tmpList
);
3669 return STATUS_INSUFFICIENT_RESOURCES
;
3672 if (RegistryHive
->FreeListMax
)
3674 RtlMoveMemory(tmpList
,
3675 RegistryHive
->FreeList
,
3676 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3677 RtlMoveMemory(tmpListOffset
,
3678 RegistryHive
->FreeListOffset
,
3679 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3680 ExFreePool(RegistryHive
->FreeList
);
3681 ExFreePool(RegistryHive
->FreeListOffset
);
3683 RegistryHive
->FreeList
= tmpList
;
3684 RegistryHive
->FreeListOffset
= tmpListOffset
;
3685 RegistryHive
->FreeListMax
+= 32;
3688 /* Add new offset to free list, maintaining list in ascending order */
3689 if ((RegistryHive
->FreeListSize
== 0)
3690 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3692 /* Add to end of list */
3693 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3694 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3696 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3698 /* Add to begin of list */
3699 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3700 &RegistryHive
->FreeList
[0],
3701 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3702 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3703 &RegistryHive
->FreeListOffset
[0],
3704 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3705 RegistryHive
->FreeList
[0] = FreeBlock
;
3706 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3707 RegistryHive
->FreeListSize
++;
3711 /* Search where to insert */
3713 maxInd
= RegistryHive
->FreeListSize
- 1;
3714 while ((maxInd
- minInd
) > 1)
3716 medInd
= (minInd
+ maxInd
) / 2;
3717 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3723 /* Insert before maxInd */
3724 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3725 &RegistryHive
->FreeList
[maxInd
],
3726 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3727 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3728 &RegistryHive
->FreeListOffset
[maxInd
],
3729 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3730 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3731 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3732 RegistryHive
->FreeListSize
++;
3735 return STATUS_SUCCESS
;
3740 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3741 BLOCK_OFFSET BlockOffset
)
3748 if (IsNoFileHive(RegistryHive
))
3751 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3753 BlockNumber
= (ULONG
)BlockOffset
/ REG_BLOCK_SIZE
;
3755 Cell
= CmiGetCell (RegistryHive
,
3759 CellSize
= Cell
->CellSize
;
3761 CellSize
= -CellSize
;
3763 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, REG_BLOCK_SIZE
) -
3764 ROUND_DOWN(BlockOffset
, REG_BLOCK_SIZE
)) / REG_BLOCK_SIZE
;
3766 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3769 (Cell
->CellSize
< 0) ? "used" : "free",
3772 RegistryHive
->HiveDirty
= TRUE
;
3773 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3780 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3781 BLOCK_OFFSET BinOffset
)
3787 if (IsNoFileHive(RegistryHive
))
3790 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3792 BlockNumber
= (ULONG
)BinOffset
/ REG_BLOCK_SIZE
;
3794 Bin
= RegistryHive
->BlockList
[BlockNumber
].Bin
;
3796 BlockCount
= Bin
->BinSize
/ REG_BLOCK_SIZE
;
3798 DPRINT(" BlockNumber %lu BinSize %lu BlockCount %lu\n",
3803 RegistryHive
->HiveDirty
= TRUE
;
3804 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3811 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3812 OUT PBOOLEAN Packable
)
3816 if (Packable
!= NULL
)
3819 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3821 if (Name
->Buffer
[i
] & 0xFF00)
3823 if (Packable
!= NULL
)
3825 return Name
->Length
;
3829 return (Name
->Length
/ sizeof(WCHAR
));
3834 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3835 IN PCHAR NameBuffer
,
3836 IN USHORT NameBufferSize
,
3837 IN BOOLEAN NamePacked
)
3842 if (NamePacked
== TRUE
)
3844 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3847 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3849 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3855 if (Name
->Length
!= NameBufferSize
)
3858 UNameBuffer
= (PWCHAR
)NameBuffer
;
3860 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3862 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3872 CmiCopyPackedName(PWCHAR NameBuffer
,
3873 PCHAR PackedNameBuffer
,
3874 ULONG PackedNameSize
)
3878 for (i
= 0; i
< PackedNameSize
; i
++)
3879 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];
3884 CmiCompareHash(PUNICODE_STRING KeyName
,
3889 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3890 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3891 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3892 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3894 return (strncmp(Buffer
, HashString
, 4) == 0);
3899 CmiCompareHashI(PUNICODE_STRING KeyName
,
3904 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3905 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3906 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3907 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3909 return (_strnicmp(Buffer
, HashString
, 4) == 0);
3914 CmiCompareKeyNames(PUNICODE_STRING KeyName
,
3920 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3922 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3924 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3927 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3929 if (KeyName
->Buffer
[i
] != (WCHAR
)KeyCell
->Name
[i
])
3935 if (KeyName
->Length
!= KeyCell
->NameSize
)
3938 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3939 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3941 if (KeyName
->Buffer
[i
] != UnicodeName
[i
])
3951 CmiCompareKeyNamesI(PUNICODE_STRING KeyName
,
3957 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3959 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3961 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3964 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3966 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3967 RtlUpcaseUnicodeChar((WCHAR
)KeyCell
->Name
[i
]))
3973 if (KeyName
->Length
!= KeyCell
->NameSize
)
3976 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3977 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3979 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3980 RtlUpcaseUnicodeChar(UnicodeName
[i
]))
3990 CmiCopyKey (PREGISTRY_HIVE DstHive
,
3991 PKEY_CELL DstKeyCell
,
3992 PREGISTRY_HIVE SrcHive
,
3993 PKEY_CELL SrcKeyCell
)
3995 PKEY_CELL NewKeyCell
;
3996 ULONG NewKeyCellSize
;
3997 BLOCK_OFFSET NewKeyCellOffset
;
3998 PHASH_TABLE_CELL NewHashTableCell
;
3999 ULONG NewHashTableSize
;
4000 BLOCK_OFFSET NewHashTableOffset
;
4004 DPRINT ("CmiCopyKey() called\n");
4006 if (DstKeyCell
== NULL
)
4008 /* Allocate and copy key cell */
4009 NewKeyCellSize
= sizeof(KEY_CELL
) + SrcKeyCell
->NameSize
;
4010 Status
= CmiAllocateCell (DstHive
,
4012 (PVOID
) &NewKeyCell
,
4014 if (!NT_SUCCESS(Status
))
4016 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4019 if (NewKeyCell
== NULL
)
4021 DPRINT1 ("Failed to allocate a key cell\n");
4022 return STATUS_INSUFFICIENT_RESOURCES
;
4025 RtlCopyMemory (NewKeyCell
,
4029 DstHive
->HiveHeader
->RootKeyOffset
= NewKeyCellOffset
;
4031 /* Copy class name */
4032 if (SrcKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4034 PDATA_CELL SrcClassNameCell
;
4035 PDATA_CELL NewClassNameCell
;
4036 BLOCK_OFFSET NewClassNameOffset
;
4038 SrcClassNameCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ClassNameOffset
, NULL
),
4040 NewKeyCell
->ClassSize
= SrcKeyCell
->ClassSize
;
4041 Status
= CmiAllocateCell (DstHive
,
4042 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
4043 (PVOID
)&NewClassNameCell
,
4044 &NewClassNameOffset
);
4045 if (!NT_SUCCESS(Status
))
4047 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4051 RtlCopyMemory (NewClassNameCell
,
4053 NewKeyCell
->ClassSize
);
4054 NewKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4059 NewKeyCell
= DstKeyCell
;
4062 /* Allocate hash table */
4063 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4065 NewHashTableSize
= ROUND_UP(SrcKeyCell
->NumberOfSubKeys
+ 1, 4) - 1;
4066 Status
= CmiAllocateHashTableCell (DstHive
,
4068 &NewHashTableOffset
,
4070 if (!NT_SUCCESS(Status
))
4072 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status
);
4075 NewKeyCell
->HashTableOffset
= NewHashTableOffset
;
4078 /* Allocate and copy value list and values */
4079 if (SrcKeyCell
->NumberOfValues
!= 0)
4081 PVALUE_LIST_CELL NewValueListCell
;
4082 PVALUE_LIST_CELL SrcValueListCell
;
4083 PVALUE_CELL NewValueCell
;
4084 PVALUE_CELL SrcValueCell
;
4085 PDATA_CELL SrcValueDataCell
;
4086 PDATA_CELL NewValueDataCell
;
4087 BLOCK_OFFSET ValueCellOffset
;
4088 BLOCK_OFFSET ValueDataCellOffset
;
4089 ULONG NewValueListCellSize
;
4090 ULONG NewValueCellSize
;
4093 NewValueListCellSize
=
4094 ROUND_UP(SrcKeyCell
->NumberOfValues
, 4) * sizeof(BLOCK_OFFSET
);
4095 Status
= CmiAllocateCell (DstHive
,
4096 NewValueListCellSize
,
4097 (PVOID
)&NewValueListCell
,
4098 &NewKeyCell
->ValueListOffset
);
4099 if (!NT_SUCCESS(Status
))
4101 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4105 RtlZeroMemory (NewValueListCell
,
4106 NewValueListCellSize
);
4109 SrcValueListCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ValueListOffset
, NULL
);
4110 for (i
= 0; i
< SrcKeyCell
->NumberOfValues
; i
++)
4112 /* Copy value cell */
4113 SrcValueCell
= CmiGetCell (SrcHive
, SrcValueListCell
->ValueOffset
[i
], NULL
);
4115 NewValueCellSize
= sizeof(VALUE_CELL
) + SrcValueCell
->NameSize
;
4116 Status
= CmiAllocateCell (DstHive
,
4118 (PVOID
*) &NewValueCell
,
4120 if (!NT_SUCCESS(Status
))
4122 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4126 NewValueListCell
->ValueOffset
[i
] = ValueCellOffset
;
4127 RtlCopyMemory (NewValueCell
,
4131 /* Copy value data cell */
4132 if (SrcValueCell
->DataSize
> (LONG
) sizeof(PVOID
))
4134 SrcValueDataCell
= CmiGetCell (SrcHive
, SrcValueCell
->DataOffset
, NULL
);
4136 Status
= CmiAllocateCell (DstHive
,
4137 sizeof(CELL_HEADER
) + SrcValueCell
->DataSize
,
4138 (PVOID
*) &NewValueDataCell
,
4139 &ValueDataCellOffset
);
4140 if (!NT_SUCCESS(Status
))
4142 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4145 RtlCopyMemory (NewValueDataCell
,
4147 SrcValueCell
->DataSize
);
4148 NewValueCell
->DataOffset
= ValueDataCellOffset
;
4154 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4156 PHASH_TABLE_CELL SrcHashTableCell
;
4157 PKEY_CELL SrcSubKeyCell
;
4158 PKEY_CELL NewSubKeyCell
;
4159 ULONG NewSubKeyCellSize
;
4160 BLOCK_OFFSET NewSubKeyCellOffset
;
4161 PHASH_RECORD SrcHashRecord
;
4163 SrcHashTableCell
= CmiGetCell (SrcHive
,
4164 SrcKeyCell
->HashTableOffset
,
4167 for (i
= 0; i
< SrcKeyCell
->NumberOfSubKeys
; i
++)
4169 SrcHashRecord
= &SrcHashTableCell
->Table
[i
];
4170 SrcSubKeyCell
= CmiGetCell (SrcHive
, SrcHashRecord
->KeyOffset
, NULL
);
4172 /* Allocate and copy key cell */
4173 NewSubKeyCellSize
= sizeof(KEY_CELL
) + SrcSubKeyCell
->NameSize
;
4174 Status
= CmiAllocateCell (DstHive
,
4176 (PVOID
)&NewSubKeyCell
,
4177 &NewSubKeyCellOffset
);
4178 if (!NT_SUCCESS(Status
))
4180 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4183 if (NewKeyCell
== NULL
)
4185 DPRINT1 ("Failed to allocate a sub key cell\n");
4186 return STATUS_INSUFFICIENT_RESOURCES
;
4189 NewHashTableCell
->Table
[i
].KeyOffset
= NewSubKeyCellOffset
;
4190 NewHashTableCell
->Table
[i
].HashValue
= SrcHashRecord
->HashValue
;
4192 RtlCopyMemory (NewSubKeyCell
,
4196 /* Copy class name */
4197 if (SrcSubKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4199 PDATA_CELL SrcClassNameCell
;
4200 PDATA_CELL NewClassNameCell
;
4201 BLOCK_OFFSET NewClassNameOffset
;
4203 SrcClassNameCell
= CmiGetCell (SrcHive
,
4204 SrcSubKeyCell
->ClassNameOffset
,
4207 NewSubKeyCell
->ClassSize
= SrcSubKeyCell
->ClassSize
;
4208 Status
= CmiAllocateCell (DstHive
,
4209 sizeof(CELL_HEADER
) + NewSubKeyCell
->ClassSize
,
4210 (PVOID
)&NewClassNameCell
,
4211 &NewClassNameOffset
);
4212 if (!NT_SUCCESS(Status
))
4214 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4218 NewSubKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4219 RtlCopyMemory (NewClassNameCell
,
4221 NewSubKeyCell
->ClassSize
);
4224 /* Copy subkey data and subkeys */
4225 Status
= CmiCopyKey (DstHive
,
4229 if (!NT_SUCCESS(Status
))
4231 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4237 return STATUS_SUCCESS
;
4242 CmiSaveTempHive (PREGISTRY_HIVE Hive
,
4245 IO_STATUS_BLOCK IoStatusBlock
;
4246 LARGE_INTEGER FileOffset
;
4251 DPRINT ("CmiSaveTempHive() called\n");
4253 Hive
->HiveHeader
->Checksum
= CmiCalcChecksum ((PULONG
)Hive
->HiveHeader
);
4255 /* Write hive block */
4256 FileOffset
.QuadPart
= (ULONGLONG
)0;
4257 Status
= NtWriteFile (FileHandle
,
4263 sizeof(HIVE_HEADER
),
4266 if (!NT_SUCCESS(Status
))
4268 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4272 DPRINT ("Saving %lu blocks\n", Hive
->BlockListSize
);
4273 for (BlockIndex
= 0; BlockIndex
< Hive
->BlockListSize
; BlockIndex
++)
4275 BlockPtr
= Hive
->BlockList
[BlockIndex
].Block
;
4276 DPRINT ("BlockPtr %p\n", BlockPtr
);
4278 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
4279 DPRINT ("File offset %I64x\n", FileOffset
.QuadPart
);
4281 /* Write hive block */
4282 Status
= NtWriteFile (FileHandle
,
4291 if (!NT_SUCCESS(Status
))
4293 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4298 Status
= NtFlushBuffersFile (FileHandle
,
4300 if (!NT_SUCCESS(Status
))
4302 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
4305 DPRINT ("CmiSaveTempHive() done\n");