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
)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
);
977 DPRINT("ViewBase %p ViewSize %lx\n", ViewBase
, ViewSize
);
979 /* Copy hive header and initalize hive */
980 RtlCopyMemory (RegistryHive
->HiveHeader
,
982 sizeof(HIVE_HEADER
));
983 RegistryHive
->FileSize
= ViewSize
;
984 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ REG_BLOCK_SIZE
) - 1;
985 RegistryHive
->UpdateCounter
= RegistryHive
->HiveHeader
->UpdateCounter1
;
987 /* Allocate hive block list */
988 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
989 RegistryHive
->BlockListSize
* sizeof(BLOCK_LIST_ENTRY
));
990 if (RegistryHive
->BlockList
== NULL
)
992 DPRINT1("Failed to allocate the hive block list\n");
993 MmUnmapViewOfSection(PsGetCurrentProcess(),
995 ObDereferenceObject(SectionObject
);
996 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
997 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
998 return STATUS_INSUFFICIENT_RESOURCES
;
1000 RtlZeroMemory (RegistryHive
->BlockList
,
1001 RegistryHive
->BlockListSize
* sizeof(BLOCK_LIST_ENTRY
));
1003 /* Import the hive bins */
1004 Status
= CmiImportHiveBins (RegistryHive
,
1005 ViewBase
+ REG_BLOCK_SIZE
);
1006 if (!NT_SUCCESS(Status
))
1008 ExFreePool(RegistryHive
->BlockList
);
1009 MmUnmapViewOfSection(PsGetCurrentProcess(),
1011 ObDereferenceObject(SectionObject
);
1012 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1013 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1017 /* Unmap and dereference the hive section */
1018 MmUnmapViewOfSection(PsGetCurrentProcess(),
1020 ObDereferenceObject(SectionObject
);
1022 /* Initialize the free cell list */
1023 Status
= CmiCreateHiveFreeCellList (RegistryHive
);
1024 if (!NT_SUCCESS(Status
))
1026 CmiFreeHiveBins(RegistryHive
);
1027 ExFreePool(RegistryHive
->BlockList
);
1028 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1029 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1033 /* Create the block bitmap */
1034 Status
= CmiCreateHiveBitmap (RegistryHive
);
1035 if (!NT_SUCCESS(Status
))
1037 CmiFreeHiveFreeCellList(RegistryHive
);
1038 CmiFreeHiveBins(RegistryHive
);
1039 ExFreePool(RegistryHive
->BlockList
);
1040 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1041 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1045 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n",
1046 RegistryHive
, Filename
);
1048 return STATUS_SUCCESS
;
1053 CmiCreateVolatileHive(PREGISTRY_HIVE
*RegistryHive
)
1055 PKEY_CELL RootKeyCell
;
1056 PREGISTRY_HIVE Hive
;
1058 *RegistryHive
= NULL
;
1060 Hive
= ExAllocatePool (NonPagedPool
,
1061 sizeof(REGISTRY_HIVE
));
1063 return STATUS_INSUFFICIENT_RESOURCES
;
1065 RtlZeroMemory (Hive
,
1066 sizeof(REGISTRY_HIVE
));
1068 DPRINT("Hive %x\n", Hive
);
1070 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1071 sizeof(HIVE_HEADER
));
1072 if (Hive
->HiveHeader
== NULL
)
1075 return STATUS_INSUFFICIENT_RESOURCES
;
1077 RtlZeroMemory (Hive
->HiveHeader
,
1078 sizeof(HIVE_HEADER
));
1080 Hive
->Flags
= (HIVE_NO_FILE
| HIVE_POINTER
);
1082 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1084 RootKeyCell
= (PKEY_CELL
)ExAllocatePool (NonPagedPool
,
1086 if (RootKeyCell
== NULL
)
1088 ExFreePool(Hive
->HiveHeader
);
1090 return STATUS_INSUFFICIENT_RESOURCES
;
1093 CmiCreateDefaultRootKeyCell (RootKeyCell
);
1094 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)RootKeyCell
;
1096 ExInitializeResourceLite (&Hive
->HiveResource
);
1098 /* Acquire hive list lock exclusively */
1099 KeEnterCriticalRegion();
1100 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1103 /* Add the new hive to the hive list */
1104 InsertTailList (&CmiHiveListHead
,
1107 /* Release hive list lock */
1108 ExReleaseResourceLite (&CmiHiveListLock
);
1109 KeLeaveCriticalRegion();
1111 VERIFY_REGISTRY_HIVE (Hive
);
1113 *RegistryHive
= Hive
;
1115 return STATUS_SUCCESS
;
1120 CmiCreateTempHive(PREGISTRY_HIVE
*RegistryHive
)
1123 PCELL_HEADER FreeCell
;
1124 PREGISTRY_HIVE Hive
;
1127 DPRINT ("CmiCreateTempHive() called\n");
1129 *RegistryHive
= NULL
;
1131 Hive
= ExAllocatePool (NonPagedPool
,
1132 sizeof(REGISTRY_HIVE
));
1135 DPRINT1 ("Failed to allocate registry hive block\n");
1136 return STATUS_INSUFFICIENT_RESOURCES
;
1138 RtlZeroMemory (Hive
,
1139 sizeof(REGISTRY_HIVE
));
1141 DPRINT ("Hive %x\n", Hive
);
1143 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1145 if (Hive
->HiveHeader
== NULL
)
1147 DPRINT1 ("Failed to allocate hive header block\n");
1149 return STATUS_INSUFFICIENT_RESOURCES
;
1151 RtlZeroMemory (Hive
->HiveHeader
,
1154 DPRINT ("HiveHeader %x\n", Hive
->HiveHeader
);
1156 Hive
->Flags
= HIVE_NO_FILE
;
1158 RtlInitUnicodeString (&Hive
->HiveFileName
,
1160 RtlInitUnicodeString (&Hive
->LogFileName
,
1163 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1165 /* Allocate hive block list */
1166 Hive
->BlockList
= ExAllocatePool (NonPagedPool
,
1167 sizeof(PBLOCK_LIST_ENTRY
));
1168 if (Hive
->BlockList
== NULL
)
1170 DPRINT1 ("Failed to allocate hive block list\n");
1171 ExFreePool(Hive
->HiveHeader
);
1173 return STATUS_INSUFFICIENT_RESOURCES
;
1176 /* Allocate first Bin */
1177 Hive
->BlockList
[0].Bin
= ExAllocatePool (NonPagedPool
,
1179 if (Hive
->BlockList
[0].Bin
== NULL
)
1181 DPRINT1 ("Failed to allocate first bin\n");
1182 ExFreePool(Hive
->BlockList
);
1183 ExFreePool(Hive
->HiveHeader
);
1185 return STATUS_INSUFFICIENT_RESOURCES
;
1187 Hive
->BlockList
[0].Block
= (PVOID
)Hive
->BlockList
[0].Bin
;
1189 Hive
->FileSize
= 2* REG_BLOCK_SIZE
;
1190 Hive
->BlockListSize
= 1;
1191 Hive
->UpdateCounter
= Hive
->HiveHeader
->UpdateCounter1
;
1194 BinHeader
= Hive
->BlockList
[0].Bin
;
1195 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)BinHeader
+ REG_HBIN_DATA_OFFSET
);
1197 CmiCreateDefaultBinHeader (BinHeader
);
1200 BinHeader
->BinOffset
= 0;
1202 /* Offset to root key block */
1203 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
1205 /* The rest of the block is free */
1206 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
1208 /* Create the free cell list */
1209 Status
= CmiCreateHiveFreeCellList (Hive
);
1210 if (Hive
->BlockList
[0].Bin
== NULL
)
1212 DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status
);
1213 ExFreePool(Hive
->BlockList
[0].Bin
);
1214 ExFreePool(Hive
->BlockList
);
1215 ExFreePool(Hive
->HiveHeader
);
1221 ExInitializeResourceLite (&Hive
->HiveResource
);
1223 /* Acquire hive list lock exclusively */
1224 KeEnterCriticalRegion();
1225 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1228 /* Add the new hive to the hive list */
1229 InsertTailList (&CmiHiveListHead
,
1232 /* Release hive list lock */
1233 ExReleaseResourceLite (&CmiHiveListLock
);
1234 KeLeaveCriticalRegion();
1236 VERIFY_REGISTRY_HIVE (Hive
);
1238 *RegistryHive
= Hive
;
1240 return STATUS_SUCCESS
;
1245 CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1246 IN PUNICODE_STRING FileName
,
1249 PREGISTRY_HIVE Hive
;
1252 DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName
);
1254 if (Flags
& ~REG_NO_LAZY_FLUSH
)
1255 return STATUS_INVALID_PARAMETER
;
1257 Hive
= ExAllocatePool (NonPagedPool
,
1258 sizeof(REGISTRY_HIVE
));
1261 DPRINT1 ("Failed to allocate hive header.\n");
1262 return STATUS_INSUFFICIENT_RESOURCES
;
1264 RtlZeroMemory (Hive
,
1265 sizeof(REGISTRY_HIVE
));
1267 DPRINT ("Hive %x\n", Hive
);
1268 Hive
->Flags
= (Flags
& REG_NO_LAZY_FLUSH
) ? HIVE_NO_SYNCH
: 0;
1270 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool(NonPagedPool
,
1271 sizeof(HIVE_HEADER
));
1272 if (Hive
->HiveHeader
== NULL
)
1274 DPRINT1 ("Failed to allocate hive header.\n");
1276 return STATUS_INSUFFICIENT_RESOURCES
;
1279 RtlZeroMemory (Hive
->HiveHeader
,
1280 sizeof(HIVE_HEADER
));
1282 Status
= CmiInitNonVolatileRegistryHive (Hive
,
1284 if (!NT_SUCCESS (Status
))
1286 DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status
);
1287 ExFreePool (Hive
->HiveHeader
);
1292 ExInitializeResourceLite (&Hive
->HiveResource
);
1294 /* Add the new hive to the hive list */
1295 KeEnterCriticalRegion();
1296 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1298 InsertTailList (&CmiHiveListHead
,
1300 ExReleaseResourceLite (&CmiHiveListLock
);
1301 KeLeaveCriticalRegion();
1304 VERIFY_REGISTRY_HIVE(Hive
);
1307 Status
= CmiConnectHive (KeyObjectAttributes
,
1309 if (!NT_SUCCESS(Status
))
1311 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status
);
1312 // CmiRemoveRegistryHive (Hive);
1315 DPRINT ("CmiLoadHive() done\n");
1322 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
1324 if (RegistryHive
->Flags
& HIVE_POINTER
)
1325 return STATUS_UNSUCCESSFUL
;
1327 /* Acquire hive list lock exclusively */
1328 KeEnterCriticalRegion();
1329 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1332 /* Remove hive from hive list */
1333 RemoveEntryList (&RegistryHive
->HiveList
);
1335 /* Release hive list lock */
1336 ExReleaseResourceLite (&CmiHiveListLock
);
1337 KeLeaveCriticalRegion();
1339 /* Release file names */
1340 RtlFreeUnicodeString (&RegistryHive
->HiveFileName
);
1341 RtlFreeUnicodeString (&RegistryHive
->LogFileName
);
1343 /* Release hive bitmap */
1344 ExFreePool (RegistryHive
->BitmapBuffer
);
1346 /* Release free cell list */
1347 ExFreePool (RegistryHive
->FreeList
);
1348 ExFreePool (RegistryHive
->FreeListOffset
);
1350 /* Release hive resource */
1351 ExDeleteResource (&RegistryHive
->HiveResource
);
1353 /* Release bins and bin list */
1354 CmiFreeHiveBins (RegistryHive
);
1355 ExFreePool (RegistryHive
->BlockList
);
1357 /* Release hive header */
1358 ExFreePool (RegistryHive
->HiveHeader
);
1361 ExFreePool (RegistryHive
);
1363 return STATUS_SUCCESS
;
1368 CmiCalcChecksum(PULONG Buffer
)
1373 for (i
= 0; i
< 127; i
++)
1381 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
1383 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1384 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1385 OBJECT_ATTRIBUTES ObjectAttributes
;
1386 IO_STATUS_BLOCK IoStatusBlock
;
1388 LARGE_INTEGER FileOffset
;
1397 DPRINT("CmiStartLogUpdate() called\n");
1399 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1400 BufferSize
= sizeof(HIVE_HEADER
) +
1403 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1405 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1407 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
,
1411 DPRINT("ExAllocatePool() failed\n");
1412 return(STATUS_INSUFFICIENT_RESOURCES
);
1414 RtlZeroMemory (Buffer
,
1417 /* Open log file for writing */
1418 InitializeObjectAttributes(&ObjectAttributes
,
1419 &RegistryHive
->LogFileName
,
1424 Status
= NtCreateFile(&FileHandle
,
1429 FILE_ATTRIBUTE_NORMAL
,
1432 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1435 if (!NT_SUCCESS(Status
))
1437 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1442 /* Update firt update counter and checksum */
1443 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1444 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1446 /* Copy hive header */
1447 RtlCopyMemory(Buffer
,
1448 RegistryHive
->HiveHeader
,
1449 sizeof(HIVE_HEADER
));
1450 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1457 RegistryHive
->DirtyBitMap
.Buffer
,
1460 /* Write hive block and block bitmap */
1461 FileOffset
.QuadPart
= (ULONGLONG
)0;
1462 Status
= NtWriteFile(FileHandle
,
1471 if (!NT_SUCCESS(Status
))
1473 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1474 NtClose(FileHandle
);
1480 /* Write dirty blocks */
1481 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1485 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1488 if ((BlockIndex
== (ULONG
)-1) ||
1489 (BlockIndex
>= RegistryHive
->BlockListSize
))
1491 DPRINT("No more set bits\n");
1492 Status
= STATUS_SUCCESS
;
1496 DPRINT("Block %lu is dirty\n", BlockIndex
);
1498 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1499 DPRINT("BlockPtr %p\n", BlockPtr
);
1500 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1502 /* Write hive block */
1503 Status
= NtWriteFile(FileHandle
,
1512 if (!NT_SUCCESS(Status
))
1514 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1515 NtClose(FileHandle
);
1520 FileOffset
.QuadPart
+= (ULONGLONG
)REG_BLOCK_SIZE
;
1523 /* Truncate log file */
1524 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1525 Status
= NtSetInformationFile(FileHandle
,
1528 sizeof(FILE_END_OF_FILE_INFORMATION
),
1529 FileEndOfFileInformation
);
1530 if (!NT_SUCCESS(Status
))
1532 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1533 NtClose(FileHandle
);
1537 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1538 Status
= NtSetInformationFile(FileHandle
,
1540 &FileAllocationInfo
,
1541 sizeof(FILE_ALLOCATION_INFORMATION
),
1542 FileAllocationInformation
);
1543 if (!NT_SUCCESS(Status
))
1545 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1546 NtClose(FileHandle
);
1550 /* Flush the log file */
1551 Status
= NtFlushBuffersFile(FileHandle
,
1553 if (!NT_SUCCESS(Status
))
1555 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1558 NtClose(FileHandle
);
1565 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1567 OBJECT_ATTRIBUTES ObjectAttributes
;
1568 IO_STATUS_BLOCK IoStatusBlock
;
1570 LARGE_INTEGER FileOffset
;
1577 DPRINT("CmiFinishLogUpdate() called\n");
1579 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1580 BufferSize
= sizeof(HIVE_HEADER
) +
1583 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1585 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1587 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1590 DPRINT("ExAllocatePool() failed\n");
1591 return(STATUS_INSUFFICIENT_RESOURCES
);
1594 /* Open log file for writing */
1595 InitializeObjectAttributes(&ObjectAttributes
,
1596 &RegistryHive
->LogFileName
,
1601 Status
= NtCreateFile(&FileHandle
,
1606 FILE_ATTRIBUTE_NORMAL
,
1609 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1612 if (!NT_SUCCESS(Status
))
1614 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1619 /* Update first and second update counter and checksum */
1620 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1621 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1622 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1624 /* Copy hive header */
1625 RtlCopyMemory(Buffer
,
1626 RegistryHive
->HiveHeader
,
1627 sizeof(HIVE_HEADER
));
1628 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1630 /* Write empty block bitmap */
1638 /* Write hive block and block bitmap */
1639 FileOffset
.QuadPart
= (ULONGLONG
)0;
1640 Status
= NtWriteFile(FileHandle
,
1649 if (!NT_SUCCESS(Status
))
1651 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1652 NtClose(FileHandle
);
1659 /* Flush the log file */
1660 Status
= NtFlushBuffersFile(FileHandle
,
1662 if (!NT_SUCCESS(Status
))
1664 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1667 NtClose(FileHandle
);
1674 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1676 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1677 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1678 OBJECT_ATTRIBUTES ObjectAttributes
;
1679 IO_STATUS_BLOCK IoStatusBlock
;
1685 DPRINT("CmiCleanupLogUpdate() called\n");
1687 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1688 BufferSize
= sizeof(HIVE_HEADER
) +
1691 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1693 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1695 /* Open log file for writing */
1696 InitializeObjectAttributes(&ObjectAttributes
,
1697 &RegistryHive
->LogFileName
,
1702 Status
= NtCreateFile(&FileHandle
,
1707 FILE_ATTRIBUTE_NORMAL
,
1710 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1713 if (!NT_SUCCESS(Status
))
1715 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1719 /* Truncate log file */
1720 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1721 Status
= NtSetInformationFile(FileHandle
,
1724 sizeof(FILE_END_OF_FILE_INFORMATION
),
1725 FileEndOfFileInformation
);
1726 if (!NT_SUCCESS(Status
))
1728 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1729 NtClose(FileHandle
);
1733 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1734 Status
= NtSetInformationFile(FileHandle
,
1736 &FileAllocationInfo
,
1737 sizeof(FILE_ALLOCATION_INFORMATION
),
1738 FileAllocationInformation
);
1739 if (!NT_SUCCESS(Status
))
1741 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1742 NtClose(FileHandle
);
1746 /* Flush the log file */
1747 Status
= NtFlushBuffersFile(FileHandle
,
1749 if (!NT_SUCCESS(Status
))
1751 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1754 NtClose(FileHandle
);
1761 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1763 OBJECT_ATTRIBUTES ObjectAttributes
;
1764 IO_STATUS_BLOCK IoStatusBlock
;
1766 LARGE_INTEGER FileOffset
;
1771 DPRINT("CmiStartHiveUpdate() called\n");
1773 /* Open hive for writing */
1774 InitializeObjectAttributes(&ObjectAttributes
,
1775 &RegistryHive
->HiveFileName
,
1780 Status
= NtCreateFile(&FileHandle
,
1785 FILE_ATTRIBUTE_NORMAL
,
1788 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1791 if (!NT_SUCCESS(Status
))
1793 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1797 /* Update firt update counter and checksum */
1798 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1799 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1801 /* Write hive block */
1802 FileOffset
.QuadPart
= (ULONGLONG
)0;
1803 Status
= NtWriteFile(FileHandle
,
1808 RegistryHive
->HiveHeader
,
1809 sizeof(HIVE_HEADER
),
1812 if (!NT_SUCCESS(Status
))
1814 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1815 NtClose(FileHandle
);
1822 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1825 if ((BlockIndex
== (ULONG
)-1) ||
1826 (BlockIndex
>= RegistryHive
->BlockListSize
))
1828 DPRINT("No more set bits\n");
1829 Status
= STATUS_SUCCESS
;
1833 DPRINT("Block %lu is dirty\n", BlockIndex
);
1835 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1836 DPRINT(" BlockPtr %p\n", BlockPtr
);
1838 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
1839 DPRINT(" File offset %I64x\n", FileOffset
.QuadPart
);
1841 /* Write hive block */
1842 Status
= NtWriteFile(FileHandle
,
1851 if (!NT_SUCCESS(Status
))
1853 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1854 NtClose(FileHandle
);
1861 Status
= NtFlushBuffersFile(FileHandle
,
1863 if (!NT_SUCCESS(Status
))
1865 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1868 NtClose(FileHandle
);
1875 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1877 OBJECT_ATTRIBUTES ObjectAttributes
;
1878 IO_STATUS_BLOCK IoStatusBlock
;
1879 LARGE_INTEGER FileOffset
;
1883 DPRINT("CmiFinishHiveUpdate() called\n");
1885 InitializeObjectAttributes(&ObjectAttributes
,
1886 &RegistryHive
->HiveFileName
,
1891 Status
= NtCreateFile(&FileHandle
,
1896 FILE_ATTRIBUTE_NORMAL
,
1899 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1902 if (!NT_SUCCESS(Status
))
1904 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1908 /* Update second update counter and checksum */
1909 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1910 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1911 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1913 /* Write hive block */
1914 FileOffset
.QuadPart
= (ULONGLONG
)0;
1915 Status
= NtWriteFile(FileHandle
,
1920 RegistryHive
->HiveHeader
,
1921 sizeof(HIVE_HEADER
),
1924 if (!NT_SUCCESS(Status
))
1926 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1927 NtClose(FileHandle
);
1931 Status
= NtFlushBuffersFile(FileHandle
,
1933 if (!NT_SUCCESS(Status
))
1935 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1938 NtClose(FileHandle
);
1945 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1949 DPRINT("CmiFlushRegistryHive() called\n");
1951 if (RegistryHive
->HiveDirty
== FALSE
)
1953 return(STATUS_SUCCESS
);
1956 DPRINT("Hive '%wZ' is dirty\n",
1957 &RegistryHive
->HiveFileName
);
1958 DPRINT("Log file: '%wZ'\n",
1959 &RegistryHive
->LogFileName
);
1961 /* Update hive header modification time */
1962 NtQuerySystemTime(&RegistryHive
->HiveHeader
->DateModified
);
1964 /* Start log update */
1965 Status
= CmiStartLogUpdate(RegistryHive
);
1966 if (!NT_SUCCESS(Status
))
1968 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1972 /* Finish log update */
1973 Status
= CmiFinishLogUpdate(RegistryHive
);
1974 if (!NT_SUCCESS(Status
))
1976 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1980 /* Start hive update */
1981 Status
= CmiStartHiveUpdate(RegistryHive
);
1982 if (!NT_SUCCESS(Status
))
1984 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1988 /* Finish the hive update */
1989 Status
= CmiFinishHiveUpdate(RegistryHive
);
1990 if (!NT_SUCCESS(Status
))
1992 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
1996 /* Cleanup log update */
1997 Status
= CmiCleanupLogUpdate(RegistryHive
);
1998 if (!NT_SUCCESS(Status
))
2000 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
2004 /* Increment hive update counter */
2005 RegistryHive
->UpdateCounter
++;
2007 /* Clear dirty bitmap and dirty flag */
2008 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
2009 RegistryHive
->HiveDirty
= FALSE
;
2011 DPRINT("CmiFlushRegistryHive() done\n");
2013 return(STATUS_SUCCESS
);
2018 CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject
)
2025 VERIFY_KEY_OBJECT(KeyObject
);
2027 KeyCell
= KeyObject
->KeyCell
;
2028 VERIFY_KEY_CELL(KeyCell
);
2030 SubKeyCount
= (KeyCell
== NULL
) ? 0 : KeyCell
->NumberOfSubKeys
;
2032 /* Search for volatile or 'foreign' keys */
2033 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2035 CurKey
= KeyObject
->SubKeys
[i
];
2036 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2037 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2048 CmiGetMaxNameLength(PKEY_OBJECT KeyObject
)
2050 PHASH_TABLE_CELL HashBlock
;
2052 PKEY_CELL CurSubKeyCell
;
2058 VERIFY_KEY_OBJECT(KeyObject
);
2060 KeyCell
= KeyObject
->KeyCell
;
2061 VERIFY_KEY_CELL(KeyCell
);
2064 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2065 KeyCell
->HashTableOffset
,
2067 if (HashBlock
== NULL
)
2069 DPRINT("CmiGetBlock() failed\n");
2073 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2075 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2077 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2078 HashBlock
->Table
[i
].KeyOffset
,
2080 if (CurSubKeyCell
== NULL
)
2082 DPRINT("CmiGetBlock() failed\n");
2086 NameSize
= CurSubKeyCell
->NameSize
;
2087 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2089 NameSize
*= sizeof(WCHAR
);
2092 if (NameSize
> MaxName
)
2100 DPRINT ("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2101 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2103 CurKey
= KeyObject
->SubKeys
[i
];
2104 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2105 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2107 CurSubKeyCell
= CurKey
->KeyCell
;
2108 if (CurSubKeyCell
== NULL
)
2110 DPRINT("CmiGetBlock() failed\n");
2114 if ((CurSubKeyCell
->Flags
& REG_KEY_ROOT_CELL
) == REG_KEY_ROOT_CELL
)
2116 /* Use name of the key object */
2117 NameSize
= CurKey
->Name
.Length
;
2121 /* Use name of the key cell */
2122 NameSize
= CurSubKeyCell
->NameSize
;
2123 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2125 NameSize
*= sizeof(WCHAR
);
2128 DPRINT ("NameSize %lu\n", NameSize
);
2130 if (NameSize
> MaxName
)
2137 DPRINT ("MaxName %lu\n", MaxName
);
2144 CmiGetMaxClassLength(PKEY_OBJECT KeyObject
)
2146 PHASH_TABLE_CELL HashBlock
;
2148 PKEY_CELL CurSubKeyCell
;
2153 VERIFY_KEY_OBJECT(KeyObject
);
2155 KeyCell
= KeyObject
->KeyCell
;
2156 VERIFY_KEY_CELL(KeyCell
);
2159 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2160 KeyCell
->HashTableOffset
,
2162 if (HashBlock
== NULL
)
2164 DPRINT("CmiGetBlock() failed\n");
2168 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2170 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2172 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2173 HashBlock
->Table
[i
].KeyOffset
,
2175 if (CurSubKeyCell
== NULL
)
2177 DPRINT("CmiGetBlock() failed\n");
2181 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2183 MaxClass
= CurSubKeyCell
->ClassSize
;
2189 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2190 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2192 CurKey
= KeyObject
->SubKeys
[i
];
2193 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2194 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2196 CurSubKeyCell
= CurKey
->KeyCell
;
2197 if (CurSubKeyCell
== NULL
)
2199 DPRINT("CmiGetBlock() failed\n");
2203 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2205 MaxClass
= CurSubKeyCell
->ClassSize
;
2215 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
2218 PVALUE_LIST_CELL ValueListCell
;
2219 PVALUE_CELL CurValueCell
;
2224 VERIFY_KEY_CELL(KeyCell
);
2227 ValueListCell
= CmiGetCell (RegistryHive
,
2228 KeyCell
->ValueListOffset
,
2230 if (ValueListCell
== NULL
)
2232 DPRINT("CmiGetBlock() failed\n");
2236 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2238 CurValueCell
= CmiGetCell (RegistryHive
,
2239 ValueListCell
->ValueOffset
[i
],
2241 if (CurValueCell
== NULL
)
2243 DPRINT("CmiGetBlock() failed\n");
2246 if (CurValueCell
!= NULL
)
2248 Size
= CurValueCell
->NameSize
;
2249 if (CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
2251 Size
*= sizeof(WCHAR
);
2253 if (MaxValueName
< Size
)
2255 MaxValueName
= Size
;
2260 return MaxValueName
;
2265 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
2268 PVALUE_LIST_CELL ValueListCell
;
2269 PVALUE_CELL CurValueCell
;
2273 VERIFY_KEY_CELL(KeyCell
);
2276 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2277 if (ValueListCell
== NULL
)
2282 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2284 CurValueCell
= CmiGetCell (RegistryHive
,
2285 ValueListCell
->ValueOffset
[i
],NULL
);
2286 if ((CurValueCell
!= NULL
) &&
2287 (MaxValueData
< (LONG
)(CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2289 MaxValueData
= CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2293 return MaxValueData
;
2298 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
2299 IN PKEY_CELL KeyCell
,
2300 OUT PKEY_CELL
*SubKeyCell
,
2301 OUT BLOCK_OFFSET
*BlockOffset
,
2302 IN PUNICODE_STRING KeyName
,
2303 IN ACCESS_MASK DesiredAccess
,
2304 IN ULONG Attributes
)
2306 PHASH_TABLE_CELL HashBlock
;
2307 PKEY_CELL CurSubKeyCell
;
2310 VERIFY_KEY_CELL(KeyCell
);
2312 DPRINT("Scanning for sub key %wZ\n", KeyName
);
2314 assert(RegistryHive
);
2318 /* The key does not have any subkeys */
2319 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
2321 return STATUS_SUCCESS
;
2324 /* Get hash table */
2325 HashBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2326 if (HashBlock
== NULL
)
2328 DPRINT("CmiGetBlock() failed\n");
2329 return STATUS_UNSUCCESSFUL
;
2332 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
) && (i
< HashBlock
->HashTableSize
); i
++)
2334 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2336 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2337 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1 &&
2338 (HashBlock
->Table
[i
].HashValue
== 0 ||
2339 CmiCompareHashI(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2341 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2342 HashBlock
->Table
[i
].KeyOffset
,
2344 if (CurSubKeyCell
== NULL
)
2346 DPRINT("CmiGetBlock() failed\n");
2347 return STATUS_UNSUCCESSFUL
;
2350 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2352 *SubKeyCell
= CurSubKeyCell
;
2353 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2360 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2361 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2362 (HashBlock
->Table
[i
].HashValue
== 0 ||
2363 CmiCompareHash(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2365 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2366 HashBlock
->Table
[i
].KeyOffset
,
2368 if (CurSubKeyCell
== NULL
)
2370 DPRINT("CmiGetBlock() failed\n");
2371 return STATUS_UNSUCCESSFUL
;
2374 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2376 *SubKeyCell
= CurSubKeyCell
;
2377 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2384 return STATUS_SUCCESS
;
2389 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2390 PKEY_OBJECT ParentKey
,
2392 PUNICODE_STRING SubKeyName
,
2394 PUNICODE_STRING Class
,
2395 ULONG CreateOptions
)
2397 PHASH_TABLE_CELL HashBlock
;
2398 BLOCK_OFFSET NKBOffset
;
2399 PKEY_CELL NewKeyCell
;
2401 PKEY_CELL ParentKeyCell
;
2402 PDATA_CELL ClassCell
;
2409 ParentKeyCell
= ParentKey
->KeyCell
;
2411 VERIFY_KEY_CELL(ParentKeyCell
);
2413 /* Skip leading backslash */
2414 if (SubKeyName
->Buffer
[0] == L
'\\')
2416 NamePtr
= &SubKeyName
->Buffer
[1];
2417 NameSize
= SubKeyName
->Length
- sizeof(WCHAR
);
2421 NamePtr
= SubKeyName
->Buffer
;
2422 NameSize
= SubKeyName
->Length
;
2425 /* Check whether key name can be packed */
2427 for (i
= 0; i
< NameSize
/ sizeof(WCHAR
); i
++)
2429 if (NamePtr
[i
] & 0xFF00)
2436 /* Adjust name size */
2439 NameSize
= NameSize
/ sizeof(WCHAR
);
2442 DPRINT("Key %S Length %lu %s\n", NamePtr
, NameSize
, (Packable
)?"True":"False");
2444 Status
= STATUS_SUCCESS
;
2446 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2447 Status
= CmiAllocateCell (RegistryHive
,
2449 (PVOID
) &NewKeyCell
,
2451 if (NewKeyCell
== NULL
)
2453 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2457 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2458 NewKeyCell
->Flags
= 0;
2459 NtQuerySystemTime(&NewKeyCell
->LastWriteTime
);
2460 NewKeyCell
->ParentKeyOffset
= -1;
2461 NewKeyCell
->NumberOfSubKeys
= 0;
2462 NewKeyCell
->HashTableOffset
= -1;
2463 NewKeyCell
->NumberOfValues
= 0;
2464 NewKeyCell
->ValueListOffset
= -1;
2465 NewKeyCell
->SecurityKeyOffset
= -1;
2466 NewKeyCell
->ClassNameOffset
= -1;
2468 /* Pack the key name */
2469 NewKeyCell
->NameSize
= NameSize
;
2472 NewKeyCell
->Flags
|= REG_KEY_NAME_PACKED
;
2473 for (i
= 0; i
< NameSize
; i
++)
2475 NewKeyCell
->Name
[i
] = (CHAR
)(NamePtr
[i
] & 0x00FF);
2480 RtlCopyMemory(NewKeyCell
->Name
,
2485 VERIFY_KEY_CELL(NewKeyCell
);
2489 NewKeyCell
->ClassSize
= Class
->Length
;
2490 Status
= CmiAllocateCell (RegistryHive
,
2491 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
2493 &NewKeyCell
->ClassNameOffset
);
2494 RtlCopyMemory (ClassCell
->Data
,
2500 if (!NT_SUCCESS(Status
))
2505 SubKey
->KeyCell
= NewKeyCell
;
2506 SubKey
->KeyCellOffset
= NKBOffset
;
2508 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2509 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(ParentKey
->RegistryHive
)))
2514 if (ParentKeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2516 Status
= CmiAllocateHashTableCell (RegistryHive
,
2518 &ParentKeyCell
->HashTableOffset
,
2519 REG_INIT_HASH_TABLE_SIZE
);
2520 if (!NT_SUCCESS(Status
))
2527 HashBlock
= CmiGetCell (RegistryHive
,
2528 ParentKeyCell
->HashTableOffset
,
2530 if (HashBlock
== NULL
)
2532 DPRINT("CmiGetCell() failed\n");
2533 return STATUS_UNSUCCESSFUL
;
2536 if (((ParentKeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2538 PHASH_TABLE_CELL NewHashBlock
;
2539 BLOCK_OFFSET HTOffset
;
2541 /* Reallocate the hash table cell */
2542 Status
= CmiAllocateHashTableCell (RegistryHive
,
2545 HashBlock
->HashTableSize
+
2546 REG_EXTEND_HASH_TABLE_SIZE
);
2547 if (!NT_SUCCESS(Status
))
2552 RtlZeroMemory(&NewHashBlock
->Table
[0],
2553 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2554 RtlCopyMemory(&NewHashBlock
->Table
[0],
2555 &HashBlock
->Table
[0],
2556 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2557 CmiDestroyCell (RegistryHive
,
2559 ParentKeyCell
->HashTableOffset
);
2560 ParentKeyCell
->HashTableOffset
= HTOffset
;
2561 HashBlock
= NewHashBlock
;
2565 Status
= CmiAddKeyToHashTable(RegistryHive
,
2567 ParentKeyCell
->HashTableOffset
,
2570 if (NT_SUCCESS(Status
))
2572 ParentKeyCell
->NumberOfSubKeys
++;
2575 NtQuerySystemTime (&ParentKeyCell
->LastWriteTime
);
2576 CmiMarkBlockDirty (RegistryHive
, ParentKey
->KeyCellOffset
);
2583 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2584 PKEY_OBJECT ParentKey
,
2587 PHASH_TABLE_CELL HashBlock
;
2588 PVALUE_LIST_CELL ValueList
;
2589 PVALUE_CELL ValueCell
;
2590 PDATA_CELL DataCell
;
2593 DPRINT("CmiRemoveSubKey() called\n");
2595 /* Remove all values */
2596 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2598 /* Get pointer to the value list cell */
2599 ValueList
= CmiGetCell (RegistryHive
,
2600 SubKey
->KeyCell
->ValueListOffset
,
2602 if (ValueList
== NULL
)
2604 DPRINT("CmiGetCell() failed\n");
2605 return STATUS_UNSUCCESSFUL
;
2608 if (ValueList
!= NULL
)
2610 /* Enumerate all values */
2611 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2613 /* Get pointer to value cell */
2614 ValueCell
= CmiGetCell (RegistryHive
,
2615 ValueList
->ValueOffset
[i
],
2617 if (ValueCell
!= NULL
)
2619 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
2621 DataCell
= CmiGetCell (RegistryHive
,
2622 ValueCell
->DataOffset
,
2624 if (DataCell
== NULL
)
2626 DPRINT("CmiGetCell() failed\n");
2627 return STATUS_UNSUCCESSFUL
;
2630 if (DataCell
!= NULL
)
2632 /* Destroy data cell */
2633 CmiDestroyCell (RegistryHive
,
2635 ValueCell
->DataOffset
);
2639 /* Destroy value cell */
2640 CmiDestroyCell (RegistryHive
,
2642 ValueList
->ValueOffset
[i
]);
2647 /* Destroy value list cell */
2648 CmiDestroyCell (RegistryHive
,
2650 SubKey
->KeyCell
->ValueListOffset
);
2652 SubKey
->KeyCell
->NumberOfValues
= 0;
2653 SubKey
->KeyCell
->ValueListOffset
= (BLOCK_OFFSET
)-1;
2656 /* Remove the key from the parent key's hash block */
2657 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2659 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2660 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2661 ParentKey
->KeyCell
->HashTableOffset
,
2663 if (HashBlock
== NULL
)
2665 DPRINT("CmiGetCell() failed\n");
2666 return STATUS_UNSUCCESSFUL
;
2668 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2669 if (HashBlock
!= NULL
)
2671 CmiRemoveKeyFromHashTable(ParentKey
->RegistryHive
,
2673 SubKey
->KeyCellOffset
);
2674 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2675 ParentKey
->KeyCell
->HashTableOffset
);
2679 /* Remove the key's hash block */
2680 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2682 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
);
2683 HashBlock
= CmiGetCell (RegistryHive
,
2684 SubKey
->KeyCell
->HashTableOffset
,
2686 if (HashBlock
== NULL
)
2688 DPRINT("CmiGetCell() failed\n");
2689 return STATUS_UNSUCCESSFUL
;
2691 DPRINT("SubKey HashBlock %p\n", HashBlock
);
2692 if (HashBlock
!= NULL
)
2694 CmiDestroyCell (RegistryHive
,
2696 SubKey
->KeyCell
->HashTableOffset
);
2697 SubKey
->KeyCell
->HashTableOffset
= -1;
2701 /* Decrement the number of the parent key's sub keys */
2702 if (ParentKey
!= NULL
)
2704 DPRINT("ParentKey %p\n", ParentKey
);
2705 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2707 /* Remove the parent key's hash table */
2708 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2710 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2711 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2712 ParentKey
->KeyCell
->HashTableOffset
,
2714 if (HashBlock
== NULL
)
2716 DPRINT("CmiGetCell() failed\n");
2717 return STATUS_UNSUCCESSFUL
;
2719 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2720 if (HashBlock
!= NULL
)
2722 CmiDestroyCell (ParentKey
->RegistryHive
,
2724 ParentKey
->KeyCell
->HashTableOffset
);
2725 ParentKey
->KeyCell
->HashTableOffset
= (BLOCK_OFFSET
)-1;
2729 NtQuerySystemTime(&ParentKey
->KeyCell
->LastWriteTime
);
2730 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2731 ParentKey
->KeyCellOffset
);
2734 /* Destroy key cell */
2735 CmiDestroyCell (RegistryHive
,
2737 SubKey
->KeyCellOffset
);
2738 SubKey
->KeyCell
= NULL
;
2739 SubKey
->KeyCellOffset
= (BLOCK_OFFSET
)-1;
2741 return(STATUS_SUCCESS
);
2746 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2747 IN PKEY_CELL KeyCell
,
2748 IN PUNICODE_STRING ValueName
,
2749 OUT PVALUE_CELL
*ValueCell
,
2750 OUT BLOCK_OFFSET
*ValueCellOffset
)
2752 PVALUE_LIST_CELL ValueListCell
;
2753 PVALUE_CELL CurValueCell
;
2757 if (ValueCellOffset
!= NULL
)
2758 *ValueCellOffset
= (BLOCK_OFFSET
)-1;
2760 /* The key does not have any values */
2761 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2763 return STATUS_OBJECT_NAME_NOT_FOUND
;
2766 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2767 if (ValueListCell
== NULL
)
2769 DPRINT("ValueListCell is NULL\n");
2770 return STATUS_UNSUCCESSFUL
;
2773 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2775 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2777 CurValueCell
= CmiGetCell (RegistryHive
,
2778 ValueListCell
->ValueOffset
[i
],
2780 if (CurValueCell
== NULL
)
2782 DPRINT("CmiGetBlock() failed\n");
2783 return STATUS_UNSUCCESSFUL
;
2786 if ((CurValueCell
!= NULL
) &&
2787 CmiComparePackedNames(ValueName
,
2789 CurValueCell
->NameSize
,
2790 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2792 *ValueCell
= CurValueCell
;
2793 if (ValueCellOffset
!= NULL
)
2794 *ValueCellOffset
= ValueListCell
->ValueOffset
[i
];
2795 //DPRINT("Found value %s\n", ValueName);
2796 return STATUS_SUCCESS
;
2800 return STATUS_OBJECT_NAME_NOT_FOUND
;
2805 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2806 IN PKEY_CELL KeyCell
,
2808 OUT PVALUE_CELL
*ValueCell
)
2810 PVALUE_LIST_CELL ValueListCell
;
2811 PVALUE_CELL CurValueCell
;
2815 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2817 return STATUS_NO_MORE_ENTRIES
;
2820 if (Index
>= KeyCell
->NumberOfValues
)
2822 return STATUS_NO_MORE_ENTRIES
;
2826 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2827 if (ValueListCell
== NULL
)
2829 DPRINT("CmiGetBlock() failed\n");
2830 return STATUS_UNSUCCESSFUL
;
2833 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2836 CurValueCell
= CmiGetCell (RegistryHive
,
2837 ValueListCell
->ValueOffset
[Index
],
2839 if (CurValueCell
== NULL
)
2841 DPRINT("CmiGetBlock() failed\n");
2842 return STATUS_UNSUCCESSFUL
;
2845 *ValueCell
= CurValueCell
;
2847 return STATUS_SUCCESS
;
2852 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2853 IN PKEY_CELL KeyCell
,
2854 IN BLOCK_OFFSET KeyCellOffset
,
2855 IN PUNICODE_STRING ValueName
,
2856 OUT PVALUE_CELL
*pValueCell
,
2857 OUT BLOCK_OFFSET
*pValueCellOffset
)
2859 PVALUE_LIST_CELL NewValueListCell
;
2860 PVALUE_LIST_CELL ValueListCell
;
2861 PVALUE_CELL NewValueCell
;
2862 BLOCK_OFFSET NewValueListCellOffset
;
2863 BLOCK_OFFSET ValueListCellOffset
;
2864 BLOCK_OFFSET NewValueCellOffset
;
2868 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG
)KeyCell
->ValueListOffset
);
2870 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2871 if (ValueListCell
== NULL
)
2873 CellSize
= sizeof(VALUE_LIST_CELL
) +
2874 (3 * sizeof(BLOCK_OFFSET
));
2875 Status
= CmiAllocateCell (RegistryHive
,
2877 (PVOID
) &ValueListCell
,
2878 &ValueListCellOffset
);
2879 if (!NT_SUCCESS(Status
))
2884 KeyCell
->ValueListOffset
= ValueListCellOffset
;
2885 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2886 CmiMarkBlockDirty(RegistryHive
, ValueListCellOffset
);
2888 else if (KeyCell
->NumberOfValues
>=
2889 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
)))
2891 CellSize
= sizeof(VALUE_LIST_CELL
) +
2892 ((KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) * sizeof(BLOCK_OFFSET
));
2893 Status
= CmiAllocateCell (RegistryHive
,
2895 (PVOID
) &NewValueListCell
,
2896 &NewValueListCellOffset
);
2897 if (!NT_SUCCESS(Status
))
2902 RtlCopyMemory(&NewValueListCell
->ValueOffset
[0],
2903 &ValueListCell
->ValueOffset
[0],
2904 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2905 CmiDestroyCell (RegistryHive
, ValueListCell
, KeyCell
->ValueListOffset
);
2906 CmiMarkBlockDirty (RegistryHive
, KeyCell
->ValueListOffset
);
2908 KeyCell
->ValueListOffset
= NewValueListCellOffset
;
2909 ValueListCell
= NewValueListCell
;
2910 CmiMarkBlockDirty (RegistryHive
, KeyCellOffset
);
2911 CmiMarkBlockDirty (RegistryHive
, NewValueListCellOffset
);
2914 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2915 KeyCell
->NumberOfValues
,
2916 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2917 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
),
2918 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
));
2920 Status
= CmiAllocateValueCell(RegistryHive
,
2922 &NewValueCellOffset
,
2924 if (!NT_SUCCESS(Status
))
2929 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = NewValueCellOffset
;
2930 KeyCell
->NumberOfValues
++;
2932 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2933 CmiMarkBlockDirty(RegistryHive
, KeyCell
->ValueListOffset
);
2934 CmiMarkBlockDirty(RegistryHive
, NewValueCellOffset
);
2936 *pValueCell
= NewValueCell
;
2937 *pValueCellOffset
= NewValueCellOffset
;
2939 return STATUS_SUCCESS
;
2944 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2945 IN PKEY_CELL KeyCell
,
2946 IN BLOCK_OFFSET KeyCellOffset
,
2947 IN PUNICODE_STRING ValueName
)
2949 PVALUE_LIST_CELL ValueListCell
;
2950 PVALUE_CELL CurValueCell
;
2953 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2955 if (ValueListCell
== NULL
)
2957 DPRINT("CmiGetBlock() failed\n");
2958 return STATUS_SUCCESS
;
2961 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2963 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2965 CurValueCell
= CmiGetCell (RegistryHive
, ValueListCell
->ValueOffset
[i
], NULL
);
2966 if (CurValueCell
== NULL
)
2968 DPRINT("CmiGetBlock() failed\n");
2969 return STATUS_UNSUCCESSFUL
;
2972 if ((CurValueCell
!= NULL
) &&
2973 CmiComparePackedNames(ValueName
,
2975 CurValueCell
->NameSize
,
2976 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2978 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->ValueOffset
[i
]);
2980 if ((KeyCell
->NumberOfValues
- 1) < i
)
2982 RtlCopyMemory(&ValueListCell
->ValueOffset
[i
],
2983 &ValueListCell
->ValueOffset
[i
+ 1],
2984 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2988 RtlZeroMemory(&ValueListCell
->ValueOffset
[i
], sizeof(BLOCK_OFFSET
));
2991 KeyCell
->NumberOfValues
-= 1;
2996 if (KeyCell
->NumberOfValues
== 0)
2998 CmiDestroyCell (RegistryHive
,
3000 KeyCell
->ValueListOffset
);
3004 CmiMarkBlockDirty(RegistryHive
,
3005 KeyCell
->ValueListOffset
);
3008 CmiMarkBlockDirty(RegistryHive
,
3011 return STATUS_SUCCESS
;
3016 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive
,
3017 OUT PHASH_TABLE_CELL
*HashBlock
,
3018 OUT BLOCK_OFFSET
*HBOffset
,
3019 IN ULONG SubKeyCount
)
3021 PHASH_TABLE_CELL NewHashBlock
;
3025 Status
= STATUS_SUCCESS
;
3027 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
3028 (SubKeyCount
* sizeof(HASH_RECORD
));
3029 Status
= CmiAllocateCell (RegistryHive
,
3031 (PVOID
*) &NewHashBlock
,
3034 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
3036 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3040 assert(SubKeyCount
<= 0xffff); /* should really be USHORT_MAX or similar */
3041 NewHashBlock
->Id
= REG_HASH_TABLE_CELL_ID
;
3042 NewHashBlock
->HashTableSize
= (USHORT
)SubKeyCount
;
3043 *HashBlock
= NewHashBlock
;
3051 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
3052 PHASH_TABLE_CELL HashBlock
,
3055 BLOCK_OFFSET KeyOffset
;
3058 if (HashBlock
== NULL
)
3061 if (IsPointerHive(RegistryHive
))
3063 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
3067 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
3068 KeyCell
= CmiGetCell (RegistryHive
, KeyOffset
, NULL
);
3076 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
3077 PHASH_TABLE_CELL HashCell
,
3078 BLOCK_OFFSET HashCellOffset
,
3079 PKEY_CELL NewKeyCell
,
3080 BLOCK_OFFSET NKBOffset
)
3084 for (i
= 0; i
< HashCell
->HashTableSize
; i
++)
3086 if (HashCell
->Table
[i
].KeyOffset
== 0)
3088 HashCell
->Table
[i
].KeyOffset
= NKBOffset
;
3089 HashCell
->Table
[i
].HashValue
= 0;
3090 if (NewKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3092 RtlCopyMemory(&HashCell
->Table
[i
].HashValue
,
3094 min(NewKeyCell
->NameSize
, sizeof(ULONG
)));
3096 CmiMarkBlockDirty(RegistryHive
, HashCellOffset
);
3097 return STATUS_SUCCESS
;
3101 return STATUS_UNSUCCESSFUL
;
3106 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
3107 PHASH_TABLE_CELL HashBlock
,
3108 BLOCK_OFFSET NKBOffset
)
3112 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3114 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
3116 HashBlock
->Table
[i
].KeyOffset
= 0;
3117 HashBlock
->Table
[i
].HashValue
= 0;
3118 return STATUS_SUCCESS
;
3122 return STATUS_UNSUCCESSFUL
;
3127 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
3128 PVALUE_CELL
*ValueCell
,
3129 BLOCK_OFFSET
*VBOffset
,
3130 IN PUNICODE_STRING ValueName
)
3132 PVALUE_CELL NewValueCell
;
3138 Status
= STATUS_SUCCESS
;
3140 NameSize
= CmiGetPackedNameLength(ValueName
,
3143 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
3145 Status
= CmiAllocateCell (RegistryHive
,
3146 sizeof(VALUE_CELL
) + NameSize
,
3147 (PVOID
*) &NewValueCell
,
3149 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
3151 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3155 assert(NameSize
<= 0xffff); /* should really be USHORT_MAX or similar */
3156 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
3157 NewValueCell
->NameSize
= (USHORT
)NameSize
;
3160 /* Pack the value name */
3161 for (i
= 0; i
< NameSize
; i
++)
3162 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
3163 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
3167 /* Copy the value name */
3168 RtlCopyMemory(NewValueCell
->Name
,
3171 NewValueCell
->Flags
= 0;
3173 NewValueCell
->DataType
= 0;
3174 NewValueCell
->DataSize
= 0;
3175 NewValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
3176 *ValueCell
= NewValueCell
;
3184 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
3185 PVALUE_CELL ValueCell
,
3186 BLOCK_OFFSET VBOffset
)
3192 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell
, VBOffset
);
3194 VERIFY_VALUE_CELL(ValueCell
);
3196 /* Destroy the data cell */
3197 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
3199 pBlock
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, &pBin
);
3202 DPRINT("CmiGetBlock() failed\n");
3203 return STATUS_UNSUCCESSFUL
;
3206 Status
= CmiDestroyCell (RegistryHive
, pBlock
, ValueCell
->DataOffset
);
3207 if (!NT_SUCCESS(Status
))
3212 /* Update time of heap */
3213 if (!IsNoFileHive(RegistryHive
))
3214 NtQuerySystemTime(&pBin
->DateModified
);
3217 /* Destroy the value cell */
3218 Status
= CmiDestroyCell (RegistryHive
, ValueCell
, VBOffset
);
3220 /* Update time of heap */
3221 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, VBOffset
, &pBin
))
3223 NtQuerySystemTime(&pBin
->DateModified
);
3231 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
3234 BLOCK_OFFSET
*NewBlockOffset
)
3236 PBLOCK_LIST_ENTRY BlockList
;
3237 PCELL_HEADER tmpBlock
;
3242 DPRINT ("CmiAddBin (BlockCount %lu)\n", BlockCount
);
3244 BinSize
= BlockCount
* REG_BLOCK_SIZE
;
3245 tmpBin
= ExAllocatePool(PagedPool
, BinSize
);
3248 return STATUS_INSUFFICIENT_RESOURCES
;
3250 RtlZeroMemory (tmpBin
,
3253 tmpBin
->HeaderId
= REG_BIN_ID
;
3254 tmpBin
->BinOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
3255 RegistryHive
->FileSize
+= BinSize
;
3256 tmpBin
->BinSize
= BinSize
;
3257 tmpBin
->Unused1
= 0;
3258 NtQuerySystemTime(&tmpBin
->DateModified
);
3259 tmpBin
->Unused2
= 0;
3261 DPRINT (" BinOffset %lx BinSize %lx\n", tmpBin
->BinOffset
,tmpBin
->BinSize
);
3263 /* Allocate new block list */
3264 BlockList
= ExAllocatePool(NonPagedPool
,
3265 sizeof(BLOCK_LIST_ENTRY
) * (RegistryHive
->BlockListSize
+ BlockCount
));
3266 if (BlockList
== NULL
)
3269 return STATUS_INSUFFICIENT_RESOURCES
;
3272 if (RegistryHive
->BlockListSize
> 0)
3274 RtlCopyMemory (BlockList
,
3275 RegistryHive
->BlockList
,
3276 sizeof(BLOCK_LIST_ENTRY
) * RegistryHive
->BlockListSize
);
3277 ExFreePool(RegistryHive
->BlockList
);
3280 RegistryHive
->BlockList
= BlockList
;
3281 for (i
= 0; i
< BlockCount
; i
++)
3283 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Block
=
3284 (PVOID
)((ULONG_PTR
)tmpBin
+ (i
* REG_BLOCK_SIZE
));
3285 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Bin
= tmpBin
;
3287 RegistryHive
->BlockListSize
+= BlockCount
;
3289 /* Initialize a free block in this heap : */
3290 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
3291 tmpBlock
->CellSize
= (BinSize
- REG_HBIN_DATA_OFFSET
);
3293 /* Grow bitmap if necessary */
3294 if (IsNoFileHive(RegistryHive
) &&
3295 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
3297 PULONG BitmapBuffer
;
3300 DPRINT("Grow hive bitmap\n");
3302 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3303 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
3304 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
3305 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
3306 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
3308 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
3309 RtlCopyMemory(BitmapBuffer
,
3310 RegistryHive
->DirtyBitMap
.Buffer
,
3311 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
3312 ExFreePool(RegistryHive
->BitmapBuffer
);
3313 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
3314 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
3315 RegistryHive
->BitmapBuffer
,
3319 *NewBlock
= (PVOID
) tmpBlock
;
3322 *NewBlockOffset
= tmpBin
->BinOffset
+ REG_HBIN_DATA_OFFSET
;
3324 /* Mark new bin dirty */
3325 CmiMarkBinDirty(RegistryHive
,
3328 return STATUS_SUCCESS
;
3333 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
3336 BLOCK_OFFSET
*CellOffset
)
3338 PCELL_HEADER NewCell
;
3344 /* Round to 16 bytes multiple */
3345 CellSize
= ROUND_UP(CellSize
, 16);
3347 /* Handle volatile hives first */
3348 if (IsPointerHive(RegistryHive
))
3350 NewCell
= ExAllocatePool(NonPagedPool
, CellSize
);
3351 if (NewCell
== NULL
)
3353 return STATUS_INSUFFICIENT_RESOURCES
;
3356 RtlZeroMemory (NewCell
,
3358 NewCell
->CellSize
= -CellSize
;
3361 if (CellOffset
!= NULL
)
3362 *CellOffset
= (BLOCK_OFFSET
) NewCell
;
3366 /* first search in free blocks */
3368 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3370 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
3372 NewCell
= RegistryHive
->FreeList
[i
];
3373 if (CellOffset
!= NULL
)
3374 *CellOffset
= RegistryHive
->FreeListOffset
[i
];
3376 /* Update time of heap */
3377 Temp
= CmiGetCell (RegistryHive
,
3378 RegistryHive
->FreeListOffset
[i
],
3382 DPRINT("CmiGetBlock() failed\n");
3383 return STATUS_UNSUCCESSFUL
;
3386 NtQuerySystemTime(&Bin
->DateModified
);
3387 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
3389 if ((i
+ 1) < RegistryHive
->FreeListSize
)
3391 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
3392 &RegistryHive
->FreeList
[i
+ 1],
3393 sizeof(RegistryHive
->FreeList
[0])
3394 * (RegistryHive
->FreeListSize
- i
- 1));
3395 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
3396 &RegistryHive
->FreeListOffset
[i
+ 1],
3397 sizeof(RegistryHive
->FreeListOffset
[0])
3398 * (RegistryHive
->FreeListSize
- i
- 1));
3400 RegistryHive
->FreeListSize
--;
3405 /* Need to extend hive file : */
3406 if (NewCell
== NULL
)
3409 Status
= CmiAddBin(RegistryHive
,
3410 ((CellSize
+ sizeof(HBIN
) - 1) / REG_BLOCK_SIZE
) + 1,
3413 if (!NT_SUCCESS(Status
))
3419 /* Split the block in two parts */
3420 if (NewCell
->CellSize
> CellSize
)
3422 NewCell
= (PCELL_HEADER
) ((ULONG_PTR
) NewCell
+ CellSize
);
3423 NewCell
->CellSize
= ((PCELL_HEADER
) (*Cell
))->CellSize
- CellSize
;
3424 CmiAddFree(RegistryHive
,
3426 *CellOffset
+ CellSize
,
3428 CmiMarkBlockDirty(RegistryHive
,
3429 *CellOffset
+ CellSize
);
3431 else if (NewCell
->CellSize
< CellSize
)
3433 return STATUS_UNSUCCESSFUL
;
3436 RtlZeroMemory(*Cell
,
3438 ((PCELL_HEADER
) (*Cell
))->CellSize
= -CellSize
;
3441 return STATUS_SUCCESS
;
3446 CmiDestroyCell (PREGISTRY_HIVE RegistryHive
,
3448 BLOCK_OFFSET CellOffset
)
3453 Status
= STATUS_SUCCESS
;
3455 if (IsPointerHive(RegistryHive
))
3461 PCELL_HEADER pFree
= Cell
;
3463 if (pFree
->CellSize
< 0)
3464 pFree
->CellSize
= -pFree
->CellSize
;
3466 /* Clear block (except the block size) */
3467 RtlZeroMemory(((char*)pFree
) + sizeof(ULONG
),
3468 pFree
->CellSize
- sizeof(ULONG
));
3470 /* Add block to the list of free blocks */
3471 CmiAddFree(RegistryHive
, Cell
, CellOffset
, TRUE
);
3473 /* Update time of heap */
3474 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, CellOffset
,&pBin
))
3475 NtQuerySystemTime(&pBin
->DateModified
);
3477 CmiMarkBlockDirty(RegistryHive
, CellOffset
);
3485 CmiGetCell (PREGISTRY_HIVE RegistryHive
,
3486 BLOCK_OFFSET CellOffset
,
3496 if (CellOffset
== (BLOCK_OFFSET
)-1)
3501 if (IsPointerHive (RegistryHive
))
3503 return (PVOID
)CellOffset
;
3506 if (CellOffset
> RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
)
3508 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3509 CellOffset
, RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
);
3513 pBin
= RegistryHive
->BlockList
[CellOffset
/ REG_BLOCK_SIZE
].Bin
;
3524 return((PVOID
)((ULONG_PTR
)pBin
+ (CellOffset
- pBin
->BinOffset
)));
3529 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3530 PCELL_HEADER FreeBlock
,
3531 BLOCK_OFFSET FreeOffset
)
3533 BLOCK_OFFSET BlockOffset
;
3534 BLOCK_OFFSET BinOffset
;
3540 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3541 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3543 CmiGetCell (RegistryHive
,
3546 DPRINT("Bin %p\n", Bin
);
3550 BinOffset
= Bin
->BinOffset
;
3551 BinSize
= Bin
->BinSize
;
3552 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3554 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3556 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3557 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3558 if (BlockOffset
> BinOffset
&&
3559 BlockOffset
< BinOffset
+ BinSize
)
3561 DPRINT("Free block: Offset %lx Size %lx\n",
3562 BlockOffset
, BlockSize
);
3564 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3565 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3566 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3568 DPRINT("Merge current block with previous and next block\n");
3570 RegistryHive
->FreeList
[i
]->CellSize
+=
3571 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3573 FreeBlock
->CellSize
= 0;
3574 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3577 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3579 RtlMoveMemory(&RegistryHive
->FreeList
[i
+ 1],
3580 &RegistryHive
->FreeList
[i
+ 2],
3581 sizeof(RegistryHive
->FreeList
[0])
3582 * (RegistryHive
->FreeListSize
- i
- 2));
3583 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3584 &RegistryHive
->FreeListOffset
[i
+ 2],
3585 sizeof(RegistryHive
->FreeListOffset
[0])
3586 * (RegistryHive
->FreeListSize
- i
- 2));
3588 RegistryHive
->FreeListSize
--;
3590 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3594 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3596 DPRINT("Merge current block with previous block\n");
3598 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3599 FreeBlock
->CellSize
= 0;
3601 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3605 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3607 DPRINT("Merge current block with next block\n");
3609 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3610 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3611 RegistryHive
->FreeList
[i
] = FreeBlock
;
3612 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3614 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3626 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3627 PCELL_HEADER FreeBlock
,
3628 BLOCK_OFFSET FreeOffset
,
3629 BOOLEAN MergeFreeBlocks
)
3631 PCELL_HEADER
*tmpList
;
3632 BLOCK_OFFSET
*tmpListOffset
;
3637 assert(RegistryHive
);
3640 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3641 FreeBlock
, FreeOffset
);
3643 /* Merge free blocks */
3644 if (MergeFreeBlocks
== TRUE
)
3646 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3647 return(STATUS_SUCCESS
);
3650 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3652 tmpList
= ExAllocatePool(PagedPool
,
3653 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3654 if (tmpList
== NULL
)
3655 return STATUS_INSUFFICIENT_RESOURCES
;
3657 tmpListOffset
= ExAllocatePool(PagedPool
,
3658 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3660 if (tmpListOffset
== NULL
)
3662 ExFreePool(tmpList
);
3663 return STATUS_INSUFFICIENT_RESOURCES
;
3666 if (RegistryHive
->FreeListMax
)
3668 RtlMoveMemory(tmpList
,
3669 RegistryHive
->FreeList
,
3670 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3671 RtlMoveMemory(tmpListOffset
,
3672 RegistryHive
->FreeListOffset
,
3673 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3674 ExFreePool(RegistryHive
->FreeList
);
3675 ExFreePool(RegistryHive
->FreeListOffset
);
3677 RegistryHive
->FreeList
= tmpList
;
3678 RegistryHive
->FreeListOffset
= tmpListOffset
;
3679 RegistryHive
->FreeListMax
+= 32;
3682 /* Add new offset to free list, maintaining list in ascending order */
3683 if ((RegistryHive
->FreeListSize
== 0)
3684 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3686 /* Add to end of list */
3687 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3688 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3690 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3692 /* Add to begin of list */
3693 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3694 &RegistryHive
->FreeList
[0],
3695 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3696 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3697 &RegistryHive
->FreeListOffset
[0],
3698 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3699 RegistryHive
->FreeList
[0] = FreeBlock
;
3700 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3701 RegistryHive
->FreeListSize
++;
3705 /* Search where to insert */
3707 maxInd
= RegistryHive
->FreeListSize
- 1;
3708 while ((maxInd
- minInd
) > 1)
3710 medInd
= (minInd
+ maxInd
) / 2;
3711 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3717 /* Insert before maxInd */
3718 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3719 &RegistryHive
->FreeList
[maxInd
],
3720 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3721 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3722 &RegistryHive
->FreeListOffset
[maxInd
],
3723 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3724 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3725 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3726 RegistryHive
->FreeListSize
++;
3729 return STATUS_SUCCESS
;
3734 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3735 BLOCK_OFFSET BlockOffset
)
3742 if (IsNoFileHive(RegistryHive
))
3745 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3747 BlockNumber
= (ULONG
)BlockOffset
/ REG_BLOCK_SIZE
;
3749 Cell
= CmiGetCell (RegistryHive
,
3753 CellSize
= Cell
->CellSize
;
3755 CellSize
= -CellSize
;
3757 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, REG_BLOCK_SIZE
) -
3758 ROUND_DOWN(BlockOffset
, REG_BLOCK_SIZE
)) / REG_BLOCK_SIZE
;
3760 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3763 (Cell
->CellSize
< 0) ? "used" : "free",
3766 RegistryHive
->HiveDirty
= TRUE
;
3767 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3774 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3775 BLOCK_OFFSET BinOffset
)
3781 if (IsNoFileHive(RegistryHive
))
3784 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3786 BlockNumber
= (ULONG
)BinOffset
/ REG_BLOCK_SIZE
;
3788 Bin
= RegistryHive
->BlockList
[BlockNumber
].Bin
;
3790 BlockCount
= Bin
->BinSize
/ REG_BLOCK_SIZE
;
3792 DPRINT(" BlockNumber %lu BinSize %lu BlockCount %lu\n",
3797 RegistryHive
->HiveDirty
= TRUE
;
3798 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3805 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3806 OUT PBOOLEAN Packable
)
3810 if (Packable
!= NULL
)
3813 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3815 if (Name
->Buffer
[i
] & 0xFF00)
3817 if (Packable
!= NULL
)
3819 return Name
->Length
;
3823 return (Name
->Length
/ sizeof(WCHAR
));
3828 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3829 IN PCHAR NameBuffer
,
3830 IN USHORT NameBufferSize
,
3831 IN BOOLEAN NamePacked
)
3836 if (NamePacked
== TRUE
)
3838 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3841 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3843 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3849 if (Name
->Length
!= NameBufferSize
)
3852 UNameBuffer
= (PWCHAR
)NameBuffer
;
3854 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3856 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3866 CmiCopyPackedName(PWCHAR NameBuffer
,
3867 PCHAR PackedNameBuffer
,
3868 ULONG PackedNameSize
)
3872 for (i
= 0; i
< PackedNameSize
; i
++)
3873 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];
3878 CmiCompareHash(PUNICODE_STRING KeyName
,
3883 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3884 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3885 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3886 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3888 return (strncmp(Buffer
, HashString
, 4) == 0);
3893 CmiCompareHashI(PUNICODE_STRING KeyName
,
3898 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3899 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3900 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3901 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3903 return (_strnicmp(Buffer
, HashString
, 4) == 0);
3908 CmiCompareKeyNames(PUNICODE_STRING KeyName
,
3914 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3916 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3918 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3921 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3923 if (KeyName
->Buffer
[i
] != (WCHAR
)KeyCell
->Name
[i
])
3929 if (KeyName
->Length
!= KeyCell
->NameSize
)
3932 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3933 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3935 if (KeyName
->Buffer
[i
] != UnicodeName
[i
])
3945 CmiCompareKeyNamesI(PUNICODE_STRING KeyName
,
3951 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3953 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3955 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3958 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3960 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3961 RtlUpcaseUnicodeChar((WCHAR
)KeyCell
->Name
[i
]))
3967 if (KeyName
->Length
!= KeyCell
->NameSize
)
3970 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3971 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3973 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3974 RtlUpcaseUnicodeChar(UnicodeName
[i
]))
3984 CmiCopyKey (PREGISTRY_HIVE DstHive
,
3985 PKEY_CELL DstKeyCell
,
3986 PREGISTRY_HIVE SrcHive
,
3987 PKEY_CELL SrcKeyCell
)
3989 PKEY_CELL NewKeyCell
;
3990 ULONG NewKeyCellSize
;
3991 BLOCK_OFFSET NewKeyCellOffset
;
3992 PHASH_TABLE_CELL NewHashTableCell
;
3993 ULONG NewHashTableSize
;
3994 BLOCK_OFFSET NewHashTableOffset
;
3998 DPRINT ("CmiCopyKey() called\n");
4000 if (DstKeyCell
== NULL
)
4002 /* Allocate and copy key cell */
4003 NewKeyCellSize
= sizeof(KEY_CELL
) + SrcKeyCell
->NameSize
;
4004 Status
= CmiAllocateCell (DstHive
,
4006 (PVOID
) &NewKeyCell
,
4008 if (!NT_SUCCESS(Status
))
4010 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4013 if (NewKeyCell
== NULL
)
4015 DPRINT1 ("Failed to allocate a key cell\n");
4016 return STATUS_INSUFFICIENT_RESOURCES
;
4019 RtlCopyMemory (NewKeyCell
,
4023 DstHive
->HiveHeader
->RootKeyOffset
= NewKeyCellOffset
;
4025 /* Copy class name */
4026 if (SrcKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4028 PDATA_CELL SrcClassNameCell
;
4029 PDATA_CELL NewClassNameCell
;
4030 BLOCK_OFFSET NewClassNameOffset
;
4032 SrcClassNameCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ClassNameOffset
, NULL
),
4034 NewKeyCell
->ClassSize
= SrcKeyCell
->ClassSize
;
4035 Status
= CmiAllocateCell (DstHive
,
4036 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
4037 (PVOID
)&NewClassNameCell
,
4038 &NewClassNameOffset
);
4039 if (!NT_SUCCESS(Status
))
4041 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4045 RtlCopyMemory (NewClassNameCell
,
4047 NewKeyCell
->ClassSize
);
4048 NewKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4053 NewKeyCell
= DstKeyCell
;
4056 /* Allocate hash table */
4057 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4059 NewHashTableSize
= ROUND_UP(SrcKeyCell
->NumberOfSubKeys
+ 1, 4) - 1;
4060 Status
= CmiAllocateHashTableCell (DstHive
,
4062 &NewHashTableOffset
,
4064 if (!NT_SUCCESS(Status
))
4066 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status
);
4069 NewKeyCell
->HashTableOffset
= NewHashTableOffset
;
4072 /* Allocate and copy value list and values */
4073 if (SrcKeyCell
->NumberOfValues
!= 0)
4075 PVALUE_LIST_CELL NewValueListCell
;
4076 PVALUE_LIST_CELL SrcValueListCell
;
4077 PVALUE_CELL NewValueCell
;
4078 PVALUE_CELL SrcValueCell
;
4079 PDATA_CELL SrcValueDataCell
;
4080 PDATA_CELL NewValueDataCell
;
4081 BLOCK_OFFSET ValueCellOffset
;
4082 BLOCK_OFFSET ValueDataCellOffset
;
4083 ULONG NewValueListCellSize
;
4084 ULONG NewValueCellSize
;
4087 NewValueListCellSize
=
4088 ROUND_UP(SrcKeyCell
->NumberOfValues
, 4) * sizeof(BLOCK_OFFSET
);
4089 Status
= CmiAllocateCell (DstHive
,
4090 NewValueListCellSize
,
4091 (PVOID
)&NewValueListCell
,
4092 &NewKeyCell
->ValueListOffset
);
4093 if (!NT_SUCCESS(Status
))
4095 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4099 RtlZeroMemory (NewValueListCell
,
4100 NewValueListCellSize
);
4103 SrcValueListCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ValueListOffset
, NULL
);
4104 for (i
= 0; i
< SrcKeyCell
->NumberOfValues
; i
++)
4106 /* Copy value cell */
4107 SrcValueCell
= CmiGetCell (SrcHive
, SrcValueListCell
->ValueOffset
[i
], NULL
);
4109 NewValueCellSize
= sizeof(VALUE_CELL
) + SrcValueCell
->NameSize
;
4110 Status
= CmiAllocateCell (DstHive
,
4112 (PVOID
*) &NewValueCell
,
4114 if (!NT_SUCCESS(Status
))
4116 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4120 NewValueListCell
->ValueOffset
[i
] = ValueCellOffset
;
4121 RtlCopyMemory (NewValueCell
,
4125 /* Copy value data cell */
4126 if (SrcValueCell
->DataSize
> (LONG
) sizeof(PVOID
))
4128 SrcValueDataCell
= CmiGetCell (SrcHive
, SrcValueCell
->DataOffset
, NULL
);
4130 Status
= CmiAllocateCell (DstHive
,
4131 sizeof(CELL_HEADER
) + SrcValueCell
->DataSize
,
4132 (PVOID
*) &NewValueDataCell
,
4133 &ValueDataCellOffset
);
4134 if (!NT_SUCCESS(Status
))
4136 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4139 RtlCopyMemory (NewValueDataCell
,
4141 SrcValueCell
->DataSize
);
4142 NewValueCell
->DataOffset
= ValueDataCellOffset
;
4148 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4150 PHASH_TABLE_CELL SrcHashTableCell
;
4151 PKEY_CELL SrcSubKeyCell
;
4152 PKEY_CELL NewSubKeyCell
;
4153 ULONG NewSubKeyCellSize
;
4154 BLOCK_OFFSET NewSubKeyCellOffset
;
4155 PHASH_RECORD SrcHashRecord
;
4157 SrcHashTableCell
= CmiGetCell (SrcHive
,
4158 SrcKeyCell
->HashTableOffset
,
4161 for (i
= 0; i
< SrcKeyCell
->NumberOfSubKeys
; i
++)
4163 SrcHashRecord
= &SrcHashTableCell
->Table
[i
];
4164 SrcSubKeyCell
= CmiGetCell (SrcHive
, SrcHashRecord
->KeyOffset
, NULL
);
4166 /* Allocate and copy key cell */
4167 NewSubKeyCellSize
= sizeof(KEY_CELL
) + SrcSubKeyCell
->NameSize
;
4168 Status
= CmiAllocateCell (DstHive
,
4170 (PVOID
)&NewSubKeyCell
,
4171 &NewSubKeyCellOffset
);
4172 if (!NT_SUCCESS(Status
))
4174 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4177 if (NewKeyCell
== NULL
)
4179 DPRINT1 ("Failed to allocate a sub key cell\n");
4180 return STATUS_INSUFFICIENT_RESOURCES
;
4183 NewHashTableCell
->Table
[i
].KeyOffset
= NewSubKeyCellOffset
;
4184 NewHashTableCell
->Table
[i
].HashValue
= SrcHashRecord
->HashValue
;
4186 RtlCopyMemory (NewSubKeyCell
,
4190 /* Copy class name */
4191 if (SrcSubKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4193 PDATA_CELL SrcClassNameCell
;
4194 PDATA_CELL NewClassNameCell
;
4195 BLOCK_OFFSET NewClassNameOffset
;
4197 SrcClassNameCell
= CmiGetCell (SrcHive
,
4198 SrcSubKeyCell
->ClassNameOffset
,
4201 NewSubKeyCell
->ClassSize
= SrcSubKeyCell
->ClassSize
;
4202 Status
= CmiAllocateCell (DstHive
,
4203 sizeof(CELL_HEADER
) + NewSubKeyCell
->ClassSize
,
4204 (PVOID
)&NewClassNameCell
,
4205 &NewClassNameOffset
);
4206 if (!NT_SUCCESS(Status
))
4208 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4212 NewSubKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4213 RtlCopyMemory (NewClassNameCell
,
4215 NewSubKeyCell
->ClassSize
);
4218 /* Copy subkey data and subkeys */
4219 Status
= CmiCopyKey (DstHive
,
4223 if (!NT_SUCCESS(Status
))
4225 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4231 return STATUS_SUCCESS
;
4236 CmiSaveTempHive (PREGISTRY_HIVE Hive
,
4239 IO_STATUS_BLOCK IoStatusBlock
;
4240 LARGE_INTEGER FileOffset
;
4245 DPRINT ("CmiSaveTempHive() called\n");
4247 Hive
->HiveHeader
->Checksum
= CmiCalcChecksum ((PULONG
)Hive
->HiveHeader
);
4249 /* Write hive block */
4250 FileOffset
.QuadPart
= (ULONGLONG
)0;
4251 Status
= NtWriteFile (FileHandle
,
4257 sizeof(HIVE_HEADER
),
4260 if (!NT_SUCCESS(Status
))
4262 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4266 DPRINT ("Saving %lu blocks\n", Hive
->BlockListSize
);
4267 for (BlockIndex
= 0; BlockIndex
< Hive
->BlockListSize
; BlockIndex
++)
4269 BlockPtr
= Hive
->BlockList
[BlockIndex
].Block
;
4270 DPRINT ("BlockPtr %p\n", BlockPtr
);
4272 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
4273 DPRINT ("File offset %I64x\n", FileOffset
.QuadPart
);
4275 /* Write hive block */
4276 Status
= NtWriteFile (FileHandle
,
4285 if (!NT_SUCCESS(Status
))
4287 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4292 Status
= NtFlushBuffersFile (FileHandle
,
4294 if (!NT_SUCCESS(Status
))
4296 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
4299 DPRINT ("CmiSaveTempHive() done\n");