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
12 #include <internal/ob.h>
13 #include <internal/registry.h>
14 #include <ntos/minmax.h>
15 #include <reactos/bugcodes.h>
18 #include <internal/debug.h>
23 /* uncomment to enable hive checks (incomplete and probably buggy) */
26 /* LOCAL MACROS *************************************************************/
28 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
30 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
32 BOOLEAN CmiDoVerify
= FALSE
;
35 CmiCalcChecksum(PULONG Buffer
);
37 /* FUNCTIONS ****************************************************************/
40 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header
)
43 RtlZeroMemory(Header
, sizeof(HIVE_HEADER
));
44 Header
->BlockId
= REG_HIVE_ID
;
45 Header
->UpdateCounter1
= 0;
46 Header
->UpdateCounter2
= 0;
47 Header
->DateModified
.u
.LowPart
= 0;
48 Header
->DateModified
.u
.HighPart
= 0;
54 Header
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
55 Header
->BlockSize
= REG_BLOCK_SIZE
;
62 CmiCreateDefaultBinCell(PHBIN BinCell
)
65 RtlZeroMemory(BinCell
, sizeof(HBIN
));
66 BinCell
->BlockId
= REG_BIN_ID
;
67 BinCell
->DateModified
.u
.LowPart
= 0;
68 BinCell
->DateModified
.u
.HighPart
= 0;
69 BinCell
->BlockSize
= REG_BLOCK_SIZE
;
74 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
)
77 RtlZeroMemory(RootKeyCell
, sizeof(KEY_CELL
));
78 RootKeyCell
->CellSize
= -sizeof(KEY_CELL
);
79 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
80 RootKeyCell
->Flags
= REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
;
81 NtQuerySystemTime(&RootKeyCell
->LastWriteTime
);
82 RootKeyCell
->ParentKeyOffset
= 0;
83 RootKeyCell
->NumberOfSubKeys
= 0;
84 RootKeyCell
->HashTableOffset
= -1;
85 RootKeyCell
->NumberOfValues
= 0;
86 RootKeyCell
->ValueListOffset
= -1;
87 RootKeyCell
->SecurityKeyOffset
= 0;
88 RootKeyCell
->ClassNameOffset
= -1;
89 RootKeyCell
->NameSize
= 0;
90 RootKeyCell
->ClassSize
= 0;
95 CmiVerifyBinCell(PHBIN BinCell
)
102 if (BinCell
->BlockId
!= REG_BIN_ID
)
104 DbgPrint("BlockId is %.08x (should be %.08x)\n",
105 BinCell
->BlockId
, REG_BIN_ID
);
106 assert(BinCell
->BlockId
== REG_BIN_ID
);
109 //BinCell->DateModified.dwLowDateTime
111 //BinCell->DateModified.dwHighDateTime
114 if (BinCell
->BlockSize
!= REG_BLOCK_SIZE
)
116 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
117 BinCell
->BlockSize
, REG_BLOCK_SIZE
);
118 assert(BinCell
->BlockSize
== REG_BLOCK_SIZE
);
126 CmiVerifyKeyCell(PKEY_CELL KeyCell
)
133 if (KeyCell
->CellSize
== 0)
135 DbgPrint("CellSize is %d (must not be 0)\n",
137 assert(KeyCell
->CellSize
!= 0);
140 if (KeyCell
->Id
!= REG_KEY_CELL_ID
)
142 DbgPrint("Id is %.08x (should be %.08x)\n",
143 KeyCell
->Id
, REG_KEY_CELL_ID
);
144 assert(KeyCell
->Id
== REG_KEY_CELL_ID
);
149 //KeyCell->LastWriteTime;
151 if (KeyCell
->ParentKeyOffset
< 0)
153 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
154 KeyCell
->ParentKeyOffset
);
155 assert(KeyCell
->ParentKeyOffset
>= 0);
158 if (KeyCell
->NumberOfSubKeys
< 0)
160 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
161 KeyCell
->NumberOfSubKeys
);
162 assert(KeyCell
->NumberOfSubKeys
>= 0);
165 //KeyCell->HashTableOffset;
167 if (KeyCell
->NumberOfValues
< 0)
169 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
170 KeyCell
->NumberOfValues
);
171 assert(KeyCell
->NumberOfValues
>= 0);
174 //KeyCell->ValuesOffset = -1;
176 if (KeyCell
->SecurityKeyOffset
< 0)
178 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
179 KeyCell
->SecurityKeyOffset
);
180 assert(KeyCell
->SecurityKeyOffset
>= 0);
183 //KeyCell->ClassNameOffset = -1;
194 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell
)
199 CmiVerifyKeyCell(RootKeyCell
);
201 if (!(RootKeyCell
->Flags
& REG_KEY_ROOT_CELL
))
203 DbgPrint("Flags is %.08x (should be %.08x)\n",
204 RootKeyCell
->Flags
, REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
);
205 assert(!(RootKeyCell
->Flags
& (REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
)));
213 CmiVerifyValueCell(PVALUE_CELL ValueCell
)
220 if (ValueCell
->CellSize
== 0)
222 DbgPrint("CellSize is %d (must not be 0)\n",
223 ValueCell
->CellSize
);
224 assert(ValueCell
->CellSize
!= 0);
227 if (ValueCell
->Id
!= REG_VALUE_CELL_ID
)
229 DbgPrint("Id is %.08x (should be %.08x)\n",
230 ValueCell
->Id
, REG_VALUE_CELL_ID
);
231 assert(ValueCell
->Id
== REG_VALUE_CELL_ID
);
234 //ValueCell->NameSize;
235 //ValueCell->LONG DataSize;
236 //ValueCell->DataOffset;
237 //ValueCell->ULONG DataType;
238 //ValueCell->USHORT Flags;
239 //ValueCell->USHORT Unused1;
240 //ValueCell->UCHAR Name[0];
246 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell
)
251 if (ValueListCell
->CellSize
== 0)
253 DbgPrint("CellSize is %d (must not be 0)\n",
254 ValueListCell
->CellSize
);
255 assert(ValueListCell
->CellSize
!= 0);
263 CmiVerifyKeyObject(PKEY_OBJECT KeyObject
)
268 if (KeyObject
->RegistryHive
== NULL
)
270 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
271 KeyObject
->RegistryHive
);
272 assert(KeyObject
->RegistryHive
!= NULL
);
275 if (KeyObject
->KeyCell
== NULL
)
277 DbgPrint("KeyCell is NULL (must not be NULL)\n",
279 assert(KeyObject
->KeyCell
!= NULL
);
282 if (KeyObject
->ParentKey
== NULL
)
284 DbgPrint("ParentKey is NULL (must not be NULL)\n",
285 KeyObject
->ParentKey
);
286 assert(KeyObject
->ParentKey
!= NULL
);
294 CmiVerifyHiveHeader(PHIVE_HEADER Header
)
299 if (Header
->BlockId
!= REG_HIVE_ID
)
301 DbgPrint("BlockId is %.08x (must be %.08x)\n",
304 assert(Header
->BlockId
== REG_HIVE_ID
);
307 if (Header
->Unused3
!= 1)
309 DbgPrint("Unused3 is %.08x (must be 1)\n",
311 assert(Header
->Unused3
== 1);
314 if (Header
->Unused4
!= 3)
316 DbgPrint("Unused4 is %.08x (must be 3)\n",
318 assert(Header
->Unused4
== 3);
321 if (Header
->Unused5
!= 0)
323 DbgPrint("Unused5 is %.08x (must be 0)\n",
325 assert(Header
->Unused5
== 0);
328 if (Header
->Unused6
!= 1)
330 DbgPrint("Unused6 is %.08x (must be 1)\n",
332 assert(Header
->Unused6
== 1);
335 if (Header
->Unused7
!= 1)
337 DbgPrint("Unused7 is %.08x (must be 1)\n",
339 assert(Header
->Unused7
== 1);
347 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive
)
352 CmiVerifyHiveHeader(RegistryHive
->HiveHeader
);
359 CmiCreateNewRegFile(HANDLE FileHandle
)
361 IO_STATUS_BLOCK IoStatusBlock
;
362 PCELL_HEADER FreeCell
;
363 PHIVE_HEADER HiveHeader
;
364 PKEY_CELL RootKeyCell
;
369 Buffer
= (PCHAR
) ExAllocatePool(NonPagedPool
, 2 * REG_BLOCK_SIZE
);
371 return STATUS_INSUFFICIENT_RESOURCES
;
373 HiveHeader
= (PHIVE_HEADER
)Buffer
;
374 BinCell
= (PHBIN
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
);
375 RootKeyCell
= (PKEY_CELL
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
);
376 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
378 CmiCreateDefaultHiveHeader(HiveHeader
);
379 CmiCreateDefaultBinCell(BinCell
);
380 CmiCreateDefaultRootKeyCell(RootKeyCell
);
383 BinCell
->BlockOffset
= 0;
385 /* Offset to root key block */
386 HiveHeader
->RootKeyOffset
= REG_HBIN_DATA_OFFSET
;
388 /* The rest of the block is free */
389 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
391 Status
= NtWriteFile(FileHandle
,
403 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
405 if (!NT_SUCCESS(Status
))
410 Status
= NtFlushBuffersFile(FileHandle
,
419 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive
)
421 OBJECT_ATTRIBUTES ObjectAttributes
;
422 FILE_STANDARD_INFORMATION fsi
;
423 IO_STATUS_BLOCK IoStatusBlock
;
424 HANDLE HiveHandle
= INVALID_HANDLE_VALUE
;
425 HANDLE LogHandle
= INVALID_HANDLE_VALUE
;
426 PHIVE_HEADER HiveHeader
= NULL
;
427 PHIVE_HEADER LogHeader
= NULL
;
428 LARGE_INTEGER FileOffset
;
432 RTL_BITMAP BlockBitMap
;
435 DPRINT("CmiCheckAndFixHive() called\n");
437 /* Try to open the hive file */
438 InitializeObjectAttributes(&ObjectAttributes
,
439 &RegistryHive
->HiveFileName
,
444 Status
= NtCreateFile(&HiveHandle
,
445 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
449 FILE_ATTRIBUTE_NORMAL
,
452 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
455 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
457 return(STATUS_SUCCESS
);
459 if (!NT_SUCCESS(Status
))
461 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
465 /* Try to open the log file */
466 InitializeObjectAttributes(&ObjectAttributes
,
467 &RegistryHive
->LogFileName
,
472 Status
= NtCreateFile(&LogHandle
,
473 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
477 FILE_ATTRIBUTE_NORMAL
,
480 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
483 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
485 LogHandle
= INVALID_HANDLE_VALUE
;
487 else if (!NT_SUCCESS(Status
))
489 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
494 /* Allocate hive header */
495 HiveHeader
= ExAllocatePool(PagedPool
,
496 sizeof(HIVE_HEADER
));
497 if (HiveHeader
== NULL
)
499 DPRINT("ExAllocatePool() failed\n");
500 Status
= STATUS_INSUFFICIENT_RESOURCES
;
504 /* Read hive base block */
505 FileOffset
.QuadPart
= 0ULL;
506 Status
= NtReadFile(HiveHandle
,
515 if (!NT_SUCCESS(Status
))
517 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
521 if (LogHandle
== INVALID_HANDLE_VALUE
)
523 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
524 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
526 /* There is no way to fix the hive without log file - BSOD! */
527 DPRINT("Hive header inconsistent and no log file available!\n");
528 KEBUGCHECK(CONFIG_LIST_FAILED
);
531 Status
= STATUS_SUCCESS
;
536 /* Allocate hive header */
537 LogHeader
= ExAllocatePool(PagedPool
,
538 sizeof(HIVE_HEADER
));
539 if (LogHeader
== NULL
)
541 DPRINT("ExAllocatePool() failed\n");
542 Status
= STATUS_INSUFFICIENT_RESOURCES
;
546 /* Read log file header */
547 FileOffset
.QuadPart
= 0ULL;
548 Status
= NtReadFile(LogHandle
,
557 if (!NT_SUCCESS(Status
))
559 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
563 /* Check log file header integrity */
564 if (LogHeader
->Checksum
!= CmiCalcChecksum((PULONG
)LogHeader
) ||
565 LogHeader
->UpdateCounter1
!= LogHeader
->UpdateCounter2
)
567 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
568 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
570 DPRINT("Hive file and log file are inconsistent!\n");
571 KEBUGCHECK(CONFIG_LIST_FAILED
);
574 /* Log file damaged but hive is okay */
575 Status
= STATUS_SUCCESS
;
579 if (HiveHeader
->UpdateCounter1
== HiveHeader
->UpdateCounter2
&&
580 HiveHeader
->UpdateCounter1
== LogHeader
->UpdateCounter1
)
582 /* Hive and log file are up-to-date */
583 Status
= STATUS_SUCCESS
;
588 * Hive needs an update!
592 Status
= NtQueryInformationFile(LogHandle
,
596 FileStandardInformation
);
597 if (!NT_SUCCESS(Status
))
599 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
602 FileSize
= fsi
.EndOfFile
.u
.LowPart
;
604 /* Calculate bitmap and block size */
605 BitmapSize
= ROUND_UP((FileSize
/ 4096) - 1, sizeof(ULONG
) * 8) / 8;
606 BufferSize
= sizeof(HIVE_HEADER
) +
609 BufferSize
= ROUND_UP(BufferSize
, 4096);
611 /* Reallocate log header block */
612 ExFreePool(LogHeader
);
613 LogHeader
= ExAllocatePool(PagedPool
,
615 if (LogHeader
== NULL
)
617 DPRINT("ExAllocatePool() failed\n");
618 Status
= STATUS_INSUFFICIENT_RESOURCES
;
622 /* Read log file header */
623 FileOffset
.QuadPart
= 0ULL;
624 Status
= NtReadFile(LogHandle
,
633 if (!NT_SUCCESS(Status
))
635 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
639 /* Initialize bitmap */
640 RtlInitializeBitMap(&BlockBitMap
,
641 (PVOID
)((ULONG
)LogHeader
+ 4096 + sizeof(ULONG
)),
644 /* FIXME: Update dirty blocks */
647 /* FIXME: Update hive header */
650 Status
= STATUS_SUCCESS
;
654 /* Clean up the mess */
656 if (HiveHeader
!= NULL
)
657 ExFreePool(HiveHeader
);
659 if (LogHeader
!= NULL
)
660 ExFreePool(LogHeader
);
662 if (LogHandle
!= INVALID_HANDLE_VALUE
)
673 CmiImportHiveBins(PREGISTRY_HIVE Hive
,
676 BLOCK_OFFSET BlockOffset
;
683 while (BlockIndex
< Hive
->BlockListSize
)
685 Bin
= (PHBIN
)((ULONG_PTR
)ChunkPtr
+ BlockOffset
);
687 if (Bin
->BlockId
!= REG_BIN_ID
)
689 DPRINT1 ("Bad BlockId %x, offset %x\n", Bin
->BlockId
, BlockOffset
);
690 return STATUS_REGISTRY_CORRUPT
;
693 assertmsg((Bin
->BlockSize
% 4096) == 0,
694 ("BlockSize (0x%.08x) must be multiple of 4K\n",
697 /* Allocate the hive block */
698 Hive
->BlockList
[BlockIndex
] = ExAllocatePool (PagedPool
,
700 if (Hive
->BlockList
[BlockIndex
] == NULL
)
702 DPRINT1 ("ExAllocatePool() failed\n");
703 return STATUS_INSUFFICIENT_RESOURCES
;
707 RtlCopyMemory (Hive
->BlockList
[BlockIndex
],
711 if (Bin
->BlockSize
> 4096)
713 for (j
= 1; j
< Bin
->BlockSize
/ 4096; j
++)
715 Hive
->BlockList
[BlockIndex
+ j
] = Hive
->BlockList
[BlockIndex
];
719 BlockIndex
+= Bin
->BlockSize
/ 4096;
720 BlockOffset
+= Bin
->BlockSize
;
723 return STATUS_SUCCESS
;
728 CmiFreeHiveBins (PREGISTRY_HIVE Hive
)
734 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
736 if (Hive
->BlockList
[i
] == NULL
)
739 if (Hive
->BlockList
[i
] != Bin
)
741 Bin
= Hive
->BlockList
[i
];
742 ExFreePool (Hive
->BlockList
[i
]);
744 Hive
->BlockList
[i
] = 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
];
771 /* Search free blocks and add to list */
772 FreeOffset
= REG_HBIN_DATA_OFFSET
;
773 while (FreeOffset
< Bin
->BlockSize
)
775 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) Bin
+ FreeOffset
);
776 if (FreeBlock
->CellSize
> 0)
778 Status
= CmiAddFree(Hive
,
780 Bin
->BlockOffset
+ FreeOffset
,
783 if (!NT_SUCCESS(Status
))
788 FreeOffset
+= FreeBlock
->CellSize
;
792 FreeOffset
-= FreeBlock
->CellSize
;
796 BlockIndex
+= Bin
->BlockSize
/ 4096;
797 BlockOffset
+= Bin
->BlockSize
;
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 HANDLE SectionHandle
;
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
= NtCreateSection(&SectionHandle
,
948 if (!NT_SUCCESS(Status
))
950 DPRINT1("NtCreateSection() failed (Status %lx)\n", Status
);
951 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
952 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
956 /* Map the hive file */
959 Status
= NtMapViewOfSection(SectionHandle
,
969 if (!NT_SUCCESS(Status
))
971 DPRINT1("MmMapViewInSystemSpace() failed (Status %lx)\n", Status
);
972 NtClose(SectionHandle
);
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
/ 4096) - 1;
985 RegistryHive
->UpdateCounter
= RegistryHive
->HiveHeader
->UpdateCounter1
;
987 /* Allocate hive block list */
988 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
989 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
990 if (RegistryHive
->BlockList
== NULL
)
992 DPRINT1("Failed to allocate the hive block list\n");
993 NtUnmapViewOfSection(NtCurrentProcess(),
995 NtClose(SectionHandle
);
996 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
997 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
998 return STATUS_INSUFFICIENT_RESOURCES
;
1001 /* Import the hive bins */
1002 Status
= CmiImportHiveBins (RegistryHive
,
1004 if (!NT_SUCCESS(Status
))
1006 ExFreePool(RegistryHive
->BlockList
);
1007 NtUnmapViewOfSection(NtCurrentProcess(),
1009 NtClose(SectionHandle
);
1010 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1011 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1015 /* Unmap and dereference the hive section */
1016 NtUnmapViewOfSection(NtCurrentProcess(),
1018 NtClose(SectionHandle
);
1020 /* Initialize the free cell list */
1021 Status
= CmiCreateHiveFreeCellList (RegistryHive
);
1022 if (!NT_SUCCESS(Status
))
1024 CmiFreeHiveBins(RegistryHive
);
1025 ExFreePool(RegistryHive
->BlockList
);
1026 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1027 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1031 /* Create the block bitmap */
1032 Status
= CmiCreateHiveBitmap (RegistryHive
);
1033 if (!NT_SUCCESS(Status
))
1035 CmiFreeHiveFreeCellList(RegistryHive
);
1036 CmiFreeHiveBins(RegistryHive
);
1037 ExFreePool(RegistryHive
->BlockList
);
1038 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1039 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1043 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n",
1044 RegistryHive
, Filename
);
1046 return(STATUS_SUCCESS
);
1051 CmiCreateVolatileHive(PREGISTRY_HIVE
*RegistryHive
)
1053 PKEY_CELL RootKeyCell
;
1054 PREGISTRY_HIVE Hive
;
1056 *RegistryHive
= NULL
;
1058 Hive
= ExAllocatePool (NonPagedPool
,
1059 sizeof(REGISTRY_HIVE
));
1061 return STATUS_INSUFFICIENT_RESOURCES
;
1063 RtlZeroMemory (Hive
,
1064 sizeof(REGISTRY_HIVE
));
1066 DPRINT("Hive %x\n", Hive
);
1068 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1069 sizeof(HIVE_HEADER
));
1070 if (Hive
->HiveHeader
== NULL
)
1073 return STATUS_INSUFFICIENT_RESOURCES
;
1076 Hive
->Flags
= (HIVE_NO_FILE
| HIVE_POINTER
);
1078 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1080 RootKeyCell
= (PKEY_CELL
)ExAllocatePool (NonPagedPool
,
1082 if (RootKeyCell
== NULL
)
1084 ExFreePool(Hive
->HiveHeader
);
1086 return STATUS_INSUFFICIENT_RESOURCES
;
1089 CmiCreateDefaultRootKeyCell (RootKeyCell
);
1090 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)RootKeyCell
;
1092 ExInitializeResourceLite (&Hive
->HiveResource
);
1094 /* Acquire hive list lock exclusively */
1095 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1098 /* Add the new hive to the hive list */
1099 InsertTailList (&CmiHiveListHead
,
1102 /* Release hive list lock */
1103 ExReleaseResourceLite (&CmiHiveListLock
);
1105 VERIFY_REGISTRY_HIVE (Hive
);
1107 *RegistryHive
= Hive
;
1109 return STATUS_SUCCESS
;
1114 CmiCreateTempHive(PREGISTRY_HIVE
*RegistryHive
)
1117 PCELL_HEADER FreeCell
;
1118 PREGISTRY_HIVE Hive
;
1121 DPRINT ("CmiCreateTempHive() called\n");
1123 *RegistryHive
= NULL
;
1125 Hive
= ExAllocatePool (NonPagedPool
,
1126 sizeof(REGISTRY_HIVE
));
1129 DPRINT1 ("Failed to allocate registry hive block\n");
1130 return STATUS_INSUFFICIENT_RESOURCES
;
1132 RtlZeroMemory (Hive
,
1133 sizeof(REGISTRY_HIVE
));
1135 DPRINT ("Hive %x\n", Hive
);
1137 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1139 if (Hive
->HiveHeader
== NULL
)
1141 DPRINT1 ("Failed to allocate hive header block\n");
1143 return STATUS_INSUFFICIENT_RESOURCES
;
1145 RtlZeroMemory (Hive
->HiveHeader
,
1148 DPRINT ("HiveHeader %x\n", Hive
->HiveHeader
);
1150 Hive
->Flags
= HIVE_NO_FILE
;
1152 RtlInitUnicodeString (&Hive
->HiveFileName
,
1154 RtlInitUnicodeString (&Hive
->LogFileName
,
1157 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1159 /* Allocate hive block list */
1160 Hive
->BlockList
= ExAllocatePool (NonPagedPool
,
1162 if (Hive
->BlockList
== NULL
)
1164 DPRINT1 ("Failed to allocate hive block list\n");
1165 ExFreePool(Hive
->HiveHeader
);
1167 return STATUS_INSUFFICIENT_RESOURCES
;
1170 /* Allocate first Bin */
1171 Hive
->BlockList
[0] = ExAllocatePool (NonPagedPool
,
1173 if (Hive
->BlockList
[0] == NULL
)
1175 DPRINT1 ("Failed to allocate first bin\n");
1176 ExFreePool(Hive
->BlockList
);
1177 ExFreePool(Hive
->HiveHeader
);
1179 return STATUS_INSUFFICIENT_RESOURCES
;
1182 Hive
->FileSize
= 2* REG_BLOCK_SIZE
;
1183 Hive
->BlockListSize
= 1;
1184 Hive
->UpdateCounter
= Hive
->HiveHeader
->UpdateCounter1
;
1187 BinCell
= (PHBIN
)Hive
->BlockList
[0];
1188 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)BinCell
+ REG_HBIN_DATA_OFFSET
);
1190 CmiCreateDefaultBinCell (BinCell
);
1193 BinCell
->BlockOffset
= 0;
1195 /* Offset to root key block */
1196 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
1198 /* The rest of the block is free */
1199 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
1201 /* Create the free cell list */
1202 Status
= CmiCreateHiveFreeCellList (Hive
);
1203 if (Hive
->BlockList
[0] == NULL
)
1205 DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status
);
1206 ExFreePool(Hive
->BlockList
[0]);
1207 ExFreePool(Hive
->BlockList
);
1208 ExFreePool(Hive
->HiveHeader
);
1214 ExInitializeResourceLite (&Hive
->HiveResource
);
1216 /* Acquire hive list lock exclusively */
1217 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1220 /* Add the new hive to the hive list */
1221 InsertTailList (&CmiHiveListHead
,
1224 /* Release hive list lock */
1225 ExReleaseResourceLite (&CmiHiveListLock
);
1227 VERIFY_REGISTRY_HIVE (Hive
);
1229 *RegistryHive
= Hive
;
1231 return STATUS_SUCCESS
;
1236 CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1237 IN PUNICODE_STRING FileName
,
1240 PREGISTRY_HIVE Hive
;
1243 DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName
);
1245 if (Flags
& ~REG_NO_LAZY_FLUSH
)
1246 return STATUS_INVALID_PARAMETER
;
1248 Hive
= ExAllocatePool (NonPagedPool
,
1249 sizeof(REGISTRY_HIVE
));
1252 DPRINT1 ("Failed to allocate hive header.\n");
1253 return STATUS_INSUFFICIENT_RESOURCES
;
1255 RtlZeroMemory (Hive
,
1256 sizeof(REGISTRY_HIVE
));
1258 DPRINT ("Hive %x\n", Hive
);
1259 Hive
->Flags
= (Flags
& REG_NO_LAZY_FLUSH
) ? HIVE_NO_SYNCH
: 0;
1261 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool(NonPagedPool
,
1262 sizeof(HIVE_HEADER
));
1263 if (Hive
->HiveHeader
== NULL
)
1265 DPRINT1 ("Failed to allocate hive header.\n");
1267 return STATUS_INSUFFICIENT_RESOURCES
;
1270 Status
= CmiInitNonVolatileRegistryHive (Hive
,
1272 if (!NT_SUCCESS (Status
))
1274 DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status
);
1275 ExFreePool (Hive
->HiveHeader
);
1280 ExInitializeResourceLite (&Hive
->HiveResource
);
1282 /* Add the new hive to the hive list */
1283 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1285 InsertTailList (&CmiHiveListHead
,
1287 ExReleaseResourceLite (&CmiHiveListLock
);
1290 VERIFY_REGISTRY_HIVE(Hive
);
1293 Status
= CmiConnectHive (KeyObjectAttributes
,
1295 if (!NT_SUCCESS(Status
))
1297 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status
);
1298 // CmiRemoveRegistryHive (Hive);
1301 DPRINT ("CmiLoadHive() done\n");
1308 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
1310 if (RegistryHive
->Flags
& HIVE_POINTER
)
1311 return STATUS_UNSUCCESSFUL
;
1313 /* Acquire hive list lock exclusively */
1314 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1317 /* Remove hive from hive list */
1318 RemoveEntryList (&RegistryHive
->HiveList
);
1320 /* Release hive list lock */
1321 ExReleaseResourceLite (&CmiHiveListLock
);
1323 /* Release file names */
1324 RtlFreeUnicodeString (&RegistryHive
->HiveFileName
);
1325 RtlFreeUnicodeString (&RegistryHive
->LogFileName
);
1327 /* Release hive bitmap */
1328 ExFreePool (RegistryHive
->BitmapBuffer
);
1330 /* Release free cell list */
1331 ExFreePool (RegistryHive
->FreeList
);
1332 ExFreePool (RegistryHive
->FreeListOffset
);
1334 /* Release hive resource */
1335 ExDeleteResource (&RegistryHive
->HiveResource
);
1337 /* Release bins and bin list */
1338 CmiFreeHiveBins (RegistryHive
);
1339 ExFreePool (RegistryHive
->BlockList
);
1341 /* Release hive header */
1342 ExFreePool (RegistryHive
->HiveHeader
);
1345 ExFreePool (RegistryHive
);
1347 return STATUS_SUCCESS
;
1352 CmiCalcChecksum(PULONG Buffer
)
1357 for (i
= 0; i
< 127; i
++)
1365 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
1367 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1368 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1369 OBJECT_ATTRIBUTES ObjectAttributes
;
1370 IO_STATUS_BLOCK IoStatusBlock
;
1372 LARGE_INTEGER FileOffset
;
1381 DPRINT("CmiStartLogUpdate() called\n");
1383 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1384 BufferSize
= sizeof(HIVE_HEADER
) +
1387 BufferSize
= ROUND_UP(BufferSize
, 4096);
1389 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1391 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1394 DPRINT("ExAllocatePool() failed\n");
1395 return(STATUS_INSUFFICIENT_RESOURCES
);
1398 /* Open log file for writing */
1399 InitializeObjectAttributes(&ObjectAttributes
,
1400 &RegistryHive
->LogFileName
,
1405 Status
= NtCreateFile(&FileHandle
,
1410 FILE_ATTRIBUTE_NORMAL
,
1413 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1416 if (!NT_SUCCESS(Status
))
1418 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1423 /* Update firt update counter and checksum */
1424 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1425 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1427 /* Copy hive header */
1428 RtlCopyMemory(Buffer
,
1429 RegistryHive
->HiveHeader
,
1430 sizeof(HIVE_HEADER
));
1431 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1438 RegistryHive
->DirtyBitMap
.Buffer
,
1441 /* Write hive block and block bitmap */
1442 FileOffset
.QuadPart
= 0ULL;
1443 Status
= NtWriteFile(FileHandle
,
1452 if (!NT_SUCCESS(Status
))
1454 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1455 NtClose(FileHandle
);
1461 /* Write dirty blocks */
1462 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1466 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1469 if ((BlockIndex
== (ULONG
)-1) ||
1470 (BlockIndex
>= RegistryHive
->BlockListSize
))
1472 DPRINT("No more set bits\n");
1473 Status
= STATUS_SUCCESS
;
1477 DPRINT("Block %lu is dirty\n", BlockIndex
);
1479 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
];
1480 DPRINT("BlockPtr %p\n", BlockPtr
);
1481 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1483 /* Write hive block */
1484 Status
= NtWriteFile(FileHandle
,
1493 if (!NT_SUCCESS(Status
))
1495 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1496 NtClose(FileHandle
);
1501 FileOffset
.QuadPart
+= 4096ULL;
1504 /* Truncate log file */
1505 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1506 Status
= NtSetInformationFile(FileHandle
,
1509 sizeof(FILE_END_OF_FILE_INFORMATION
),
1510 FileEndOfFileInformation
);
1511 if (!NT_SUCCESS(Status
))
1513 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1514 NtClose(FileHandle
);
1518 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1519 Status
= NtSetInformationFile(FileHandle
,
1521 &FileAllocationInfo
,
1522 sizeof(FILE_ALLOCATION_INFORMATION
),
1523 FileAllocationInformation
);
1524 if (!NT_SUCCESS(Status
))
1526 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1527 NtClose(FileHandle
);
1531 /* Flush the log file */
1532 Status
= NtFlushBuffersFile(FileHandle
,
1534 if (!NT_SUCCESS(Status
))
1536 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1539 NtClose(FileHandle
);
1546 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1548 OBJECT_ATTRIBUTES ObjectAttributes
;
1549 IO_STATUS_BLOCK IoStatusBlock
;
1551 LARGE_INTEGER FileOffset
;
1558 DPRINT("CmiFinishLogUpdate() called\n");
1560 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1561 BufferSize
= sizeof(HIVE_HEADER
) +
1564 BufferSize
= ROUND_UP(BufferSize
, 4096);
1566 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1568 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1571 DPRINT("ExAllocatePool() failed\n");
1572 return(STATUS_INSUFFICIENT_RESOURCES
);
1575 /* Open log file for writing */
1576 InitializeObjectAttributes(&ObjectAttributes
,
1577 &RegistryHive
->LogFileName
,
1582 Status
= NtCreateFile(&FileHandle
,
1587 FILE_ATTRIBUTE_NORMAL
,
1590 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1593 if (!NT_SUCCESS(Status
))
1595 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1600 /* Update first and second update counter and checksum */
1601 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1602 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1603 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1605 /* Copy hive header */
1606 RtlCopyMemory(Buffer
,
1607 RegistryHive
->HiveHeader
,
1608 sizeof(HIVE_HEADER
));
1609 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1611 /* Write empty block bitmap */
1619 /* Write hive block and block bitmap */
1620 FileOffset
.QuadPart
= 0ULL;
1621 Status
= NtWriteFile(FileHandle
,
1630 if (!NT_SUCCESS(Status
))
1632 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1633 NtClose(FileHandle
);
1640 /* Flush the log file */
1641 Status
= NtFlushBuffersFile(FileHandle
,
1643 if (!NT_SUCCESS(Status
))
1645 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1648 NtClose(FileHandle
);
1655 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1657 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1658 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1659 OBJECT_ATTRIBUTES ObjectAttributes
;
1660 IO_STATUS_BLOCK IoStatusBlock
;
1666 DPRINT("CmiCleanupLogUpdate() called\n");
1668 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1669 BufferSize
= sizeof(HIVE_HEADER
) +
1672 BufferSize
= ROUND_UP(BufferSize
, 4096);
1674 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1676 /* Open log file for writing */
1677 InitializeObjectAttributes(&ObjectAttributes
,
1678 &RegistryHive
->LogFileName
,
1683 Status
= NtCreateFile(&FileHandle
,
1688 FILE_ATTRIBUTE_NORMAL
,
1691 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1694 if (!NT_SUCCESS(Status
))
1696 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1700 /* Truncate log file */
1701 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1702 Status
= NtSetInformationFile(FileHandle
,
1705 sizeof(FILE_END_OF_FILE_INFORMATION
),
1706 FileEndOfFileInformation
);
1707 if (!NT_SUCCESS(Status
))
1709 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1710 NtClose(FileHandle
);
1714 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1715 Status
= NtSetInformationFile(FileHandle
,
1717 &FileAllocationInfo
,
1718 sizeof(FILE_ALLOCATION_INFORMATION
),
1719 FileAllocationInformation
);
1720 if (!NT_SUCCESS(Status
))
1722 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1723 NtClose(FileHandle
);
1727 /* Flush the log file */
1728 Status
= NtFlushBuffersFile(FileHandle
,
1730 if (!NT_SUCCESS(Status
))
1732 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1735 NtClose(FileHandle
);
1742 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1744 OBJECT_ATTRIBUTES ObjectAttributes
;
1745 IO_STATUS_BLOCK IoStatusBlock
;
1747 LARGE_INTEGER FileOffset
;
1752 DPRINT("CmiStartHiveUpdate() called\n");
1754 /* Open hive for writing */
1755 InitializeObjectAttributes(&ObjectAttributes
,
1756 &RegistryHive
->HiveFileName
,
1761 Status
= NtCreateFile(&FileHandle
,
1766 FILE_ATTRIBUTE_NORMAL
,
1769 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1772 if (!NT_SUCCESS(Status
))
1774 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1778 /* Update firt update counter and checksum */
1779 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1780 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1782 /* Write hive block */
1783 FileOffset
.QuadPart
= 0ULL;
1784 Status
= NtWriteFile(FileHandle
,
1789 RegistryHive
->HiveHeader
,
1790 sizeof(HIVE_HEADER
),
1793 if (!NT_SUCCESS(Status
))
1795 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1796 NtClose(FileHandle
);
1803 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1806 if ((BlockIndex
== (ULONG
)-1) ||
1807 (BlockIndex
>= RegistryHive
->BlockListSize
))
1809 DPRINT("No more set bits\n");
1810 Status
= STATUS_SUCCESS
;
1814 DPRINT("Block %lu is dirty\n", BlockIndex
);
1816 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
];
1817 DPRINT("BlockPtr %p\n", BlockPtr
);
1819 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096ULL;
1820 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1822 /* Write hive block */
1823 Status
= NtWriteFile(FileHandle
,
1832 if (!NT_SUCCESS(Status
))
1834 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1835 NtClose(FileHandle
);
1842 Status
= NtFlushBuffersFile(FileHandle
,
1844 if (!NT_SUCCESS(Status
))
1846 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1849 NtClose(FileHandle
);
1856 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1858 OBJECT_ATTRIBUTES ObjectAttributes
;
1859 IO_STATUS_BLOCK IoStatusBlock
;
1860 LARGE_INTEGER FileOffset
;
1864 DPRINT("CmiFinishHiveUpdate() called\n");
1866 InitializeObjectAttributes(&ObjectAttributes
,
1867 &RegistryHive
->HiveFileName
,
1872 Status
= NtCreateFile(&FileHandle
,
1877 FILE_ATTRIBUTE_NORMAL
,
1880 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1883 if (!NT_SUCCESS(Status
))
1885 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1889 /* Update second update counter and checksum */
1890 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1891 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1892 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1894 /* Write hive block */
1895 FileOffset
.QuadPart
= 0ULL;
1896 Status
= NtWriteFile(FileHandle
,
1901 RegistryHive
->HiveHeader
,
1902 sizeof(HIVE_HEADER
),
1905 if (!NT_SUCCESS(Status
))
1907 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1908 NtClose(FileHandle
);
1912 Status
= NtFlushBuffersFile(FileHandle
,
1914 if (!NT_SUCCESS(Status
))
1916 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1919 NtClose(FileHandle
);
1926 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1930 DPRINT("CmiFlushRegistryHive() called\n");
1932 if (RegistryHive
->HiveDirty
== FALSE
)
1934 return(STATUS_SUCCESS
);
1937 DPRINT("Hive '%wZ' is dirty\n",
1938 &RegistryHive
->HiveFileName
);
1939 DPRINT("Log file: '%wZ'\n",
1940 &RegistryHive
->LogFileName
);
1942 /* Update hive header modification time */
1943 NtQuerySystemTime(&RegistryHive
->HiveHeader
->DateModified
);
1945 /* Start log update */
1946 Status
= CmiStartLogUpdate(RegistryHive
);
1947 if (!NT_SUCCESS(Status
))
1949 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1953 /* Finish log update */
1954 Status
= CmiFinishLogUpdate(RegistryHive
);
1955 if (!NT_SUCCESS(Status
))
1957 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1961 /* Start hive update */
1962 Status
= CmiStartHiveUpdate(RegistryHive
);
1963 if (!NT_SUCCESS(Status
))
1965 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1969 /* Finish the hive update */
1970 Status
= CmiFinishHiveUpdate(RegistryHive
);
1971 if (!NT_SUCCESS(Status
))
1973 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
1977 /* Cleanup log update */
1978 Status
= CmiCleanupLogUpdate(RegistryHive
);
1979 if (!NT_SUCCESS(Status
))
1981 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1985 /* Increment hive update counter */
1986 RegistryHive
->UpdateCounter
++;
1988 /* Clear dirty bitmap and dirty flag */
1989 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
1990 RegistryHive
->HiveDirty
= FALSE
;
1992 DPRINT("CmiFlushRegistryHive() done\n");
1994 return(STATUS_SUCCESS
);
1999 CmiGetMaxNameLength(PKEY_OBJECT KeyObject
)
2001 PHASH_TABLE_CELL HashBlock
;
2003 PKEY_CELL CurSubKeyCell
;
2009 VERIFY_KEY_OBJECT(KeyObject
);
2011 KeyCell
= KeyObject
->KeyCell
;
2012 VERIFY_KEY_CELL(KeyCell
);
2015 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2016 KeyCell
->HashTableOffset
,
2018 if (HashBlock
== NULL
)
2020 DPRINT("CmiGetBlock() failed\n");
2024 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2026 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2028 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2029 HashBlock
->Table
[i
].KeyOffset
,
2031 if (CurSubKeyCell
== NULL
)
2033 DPRINT("CmiGetBlock() failed\n");
2036 NameSize
= CurSubKeyCell
->NameSize
;
2037 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2039 NameSize
*= sizeof(WCHAR
);
2041 if (MaxName
< NameSize
)
2048 if (KeyObject
->RegistryHive
!= CmiVolatileHive
)
2050 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2051 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2053 CurKey
= KeyObject
->SubKeys
[i
];
2054 if (CurKey
->RegistryHive
== CmiVolatileHive
)
2056 CurSubKeyCell
= CurKey
->KeyCell
;
2057 if (CurSubKeyCell
== NULL
)
2059 DPRINT("CmiGetBlock() failed\n");
2062 NameSize
= CurSubKeyCell
->NameSize
;
2063 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2065 NameSize
*= sizeof(WCHAR
);
2067 if (MaxName
< NameSize
)
2080 CmiGetMaxClassLength(PKEY_OBJECT KeyObject
)
2082 PHASH_TABLE_CELL HashBlock
;
2084 PKEY_CELL CurSubKeyCell
;
2089 VERIFY_KEY_OBJECT(KeyObject
);
2091 KeyCell
= KeyObject
->KeyCell
;
2092 VERIFY_KEY_CELL(KeyCell
);
2095 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2096 KeyCell
->HashTableOffset
,
2098 if (HashBlock
== NULL
)
2100 DPRINT("CmiGetBlock() failed\n");
2104 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2106 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2108 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2109 HashBlock
->Table
[i
].KeyOffset
,
2111 if (CurSubKeyCell
== NULL
)
2113 DPRINT("CmiGetBlock() failed\n");
2117 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2119 MaxClass
= CurSubKeyCell
->ClassSize
;
2124 if (KeyObject
->RegistryHive
!= CmiVolatileHive
)
2126 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2127 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2129 CurKey
= KeyObject
->SubKeys
[i
];
2130 if (CurKey
->RegistryHive
== CmiVolatileHive
)
2132 CurSubKeyCell
= CurKey
->KeyCell
;
2133 if (CurSubKeyCell
== NULL
)
2135 DPRINT("CmiGetBlock() failed\n");
2138 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2140 MaxClass
= CurSubKeyCell
->ClassSize
;
2151 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
2154 PVALUE_LIST_CELL ValueListCell
;
2155 PVALUE_CELL CurValueCell
;
2160 VERIFY_KEY_CELL(KeyCell
);
2163 ValueListCell
= CmiGetCell (RegistryHive
,
2164 KeyCell
->ValueListOffset
,
2166 if (ValueListCell
== NULL
)
2168 DPRINT("CmiGetBlock() failed\n");
2172 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2174 CurValueCell
= CmiGetCell (RegistryHive
,
2175 ValueListCell
->ValueOffset
[i
],
2177 if (CurValueCell
== NULL
)
2179 DPRINT("CmiGetBlock() failed\n");
2182 if (CurValueCell
!= NULL
)
2184 Size
= CurValueCell
->NameSize
;
2185 if (CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
2187 Size
*= sizeof(WCHAR
);
2189 if (MaxValueName
< Size
)
2191 MaxValueName
= Size
;
2196 return MaxValueName
;
2201 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
2204 PVALUE_LIST_CELL ValueListCell
;
2205 PVALUE_CELL CurValueCell
;
2209 VERIFY_KEY_CELL(KeyCell
);
2212 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2213 if (ValueListCell
== NULL
)
2218 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2220 CurValueCell
= CmiGetCell (RegistryHive
,
2221 ValueListCell
->ValueOffset
[i
],NULL
);
2222 if ((CurValueCell
!= NULL
) &&
2223 (MaxValueData
< (CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2225 MaxValueData
= CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2229 return MaxValueData
;
2234 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
2235 IN PKEY_CELL KeyCell
,
2236 OUT PKEY_CELL
*SubKeyCell
,
2237 OUT BLOCK_OFFSET
*BlockOffset
,
2238 IN PUNICODE_STRING KeyName
,
2239 IN ACCESS_MASK DesiredAccess
,
2240 IN ULONG Attributes
)
2242 PHASH_TABLE_CELL HashBlock
;
2243 PKEY_CELL CurSubKeyCell
;
2246 VERIFY_KEY_CELL(KeyCell
);
2248 DPRINT("Scanning for sub key %wZ\n", KeyName
);
2250 assert(RegistryHive
);
2254 /* The key does not have any subkeys */
2255 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
2257 return STATUS_SUCCESS
;
2260 /* Get hash table */
2261 HashBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2262 if (HashBlock
== NULL
)
2264 DPRINT("CmiGetBlock() failed\n");
2265 return STATUS_UNSUCCESSFUL
;
2268 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
) && (i
< HashBlock
->HashTableSize
); i
++)
2270 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2272 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2273 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1 &&
2274 (HashBlock
->Table
[i
].HashValue
== 0 ||
2275 CmiCompareHashI(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2277 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2278 HashBlock
->Table
[i
].KeyOffset
,
2280 if (CurSubKeyCell
== NULL
)
2282 DPRINT("CmiGetBlock() failed\n");
2283 return STATUS_UNSUCCESSFUL
;
2286 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2288 *SubKeyCell
= CurSubKeyCell
;
2289 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2296 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2297 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2298 (HashBlock
->Table
[i
].HashValue
== 0 ||
2299 CmiCompareHash(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2301 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2302 HashBlock
->Table
[i
].KeyOffset
,
2304 if (CurSubKeyCell
== NULL
)
2306 DPRINT("CmiGetBlock() failed\n");
2307 return STATUS_UNSUCCESSFUL
;
2310 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2312 *SubKeyCell
= CurSubKeyCell
;
2313 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2320 return STATUS_SUCCESS
;
2325 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2328 PUNICODE_STRING SubKeyName
,
2330 PUNICODE_STRING Class
,
2331 ULONG CreateOptions
)
2333 PHASH_TABLE_CELL NewHashBlock
;
2334 PHASH_TABLE_CELL HashBlock
;
2335 BLOCK_OFFSET NKBOffset
;
2336 PKEY_CELL NewKeyCell
;
2339 PDATA_CELL ClassCell
;
2346 KeyCell
= Parent
->KeyCell
;
2348 VERIFY_KEY_CELL(KeyCell
);
2350 /* Skip leading backslash */
2351 if (SubKeyName
->Buffer
[0] == L
'\\')
2353 NamePtr
= &SubKeyName
->Buffer
[1];
2354 NameSize
= SubKeyName
->Length
- sizeof(WCHAR
);
2358 NamePtr
= SubKeyName
->Buffer
;
2359 NameSize
= SubKeyName
->Length
;
2362 /* Check whether key name can be packed */
2364 for (i
= 0; i
< NameSize
/ sizeof(WCHAR
); i
++)
2366 if (NamePtr
[i
] & 0xFF00)
2373 /* Adjust name size */
2376 NameSize
= NameSize
/ sizeof(WCHAR
);
2379 DPRINT("Key %S Length %lu %s\n", NamePtr
, NameSize
, (Packable
)?"True":"False");
2381 Status
= STATUS_SUCCESS
;
2383 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2384 Status
= CmiAllocateCell (RegistryHive
,
2386 (PVOID
) &NewKeyCell
,
2388 if (NewKeyCell
== NULL
)
2390 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2394 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2395 NewKeyCell
->Flags
= 0;
2396 NtQuerySystemTime(&NewKeyCell
->LastWriteTime
);
2397 NewKeyCell
->ParentKeyOffset
= -1;
2398 NewKeyCell
->NumberOfSubKeys
= 0;
2399 NewKeyCell
->HashTableOffset
= -1;
2400 NewKeyCell
->NumberOfValues
= 0;
2401 NewKeyCell
->ValueListOffset
= -1;
2402 NewKeyCell
->SecurityKeyOffset
= -1;
2403 NewKeyCell
->ClassNameOffset
= -1;
2405 /* Pack the key name */
2406 NewKeyCell
->NameSize
= NameSize
;
2409 NewKeyCell
->Flags
|= REG_KEY_NAME_PACKED
;
2410 for (i
= 0; i
< NameSize
; i
++)
2412 NewKeyCell
->Name
[i
] = (CHAR
)(NamePtr
[i
] & 0x00FF);
2417 RtlCopyMemory(NewKeyCell
->Name
,
2422 VERIFY_KEY_CELL(NewKeyCell
);
2426 NewKeyCell
->ClassSize
= Class
->Length
;
2427 Status
= CmiAllocateCell (RegistryHive
,
2428 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
2430 &NewKeyCell
->ClassNameOffset
);
2431 RtlCopyMemory (ClassCell
->Data
,
2437 if (!NT_SUCCESS(Status
))
2442 SubKey
->KeyCell
= NewKeyCell
;
2443 SubKey
->KeyCellOffset
= NKBOffset
;
2445 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2446 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(Parent
->RegistryHive
)))
2451 if (KeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2453 Status
= CmiAllocateHashTableCell (RegistryHive
,
2455 &KeyCell
->HashTableOffset
,
2456 REG_INIT_HASH_TABLE_SIZE
);
2457 if (!NT_SUCCESS(Status
))
2464 HashBlock
= CmiGetCell (RegistryHive
,
2465 KeyCell
->HashTableOffset
,
2467 if (HashBlock
== NULL
)
2469 DPRINT("CmiGetBlock() failed\n");
2470 return STATUS_UNSUCCESSFUL
;
2473 if (((KeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2475 BLOCK_OFFSET HTOffset
;
2477 /* Reallocate the hash table cell */
2478 Status
= CmiAllocateHashTableCell (RegistryHive
,
2481 HashBlock
->HashTableSize
+
2482 REG_EXTEND_HASH_TABLE_SIZE
);
2483 if (!NT_SUCCESS(Status
))
2488 RtlZeroMemory(&NewHashBlock
->Table
[0],
2489 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2490 RtlCopyMemory(&NewHashBlock
->Table
[0],
2491 &HashBlock
->Table
[0],
2492 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2493 CmiDestroyCell (RegistryHive
,
2495 KeyCell
->HashTableOffset
);
2496 KeyCell
->HashTableOffset
= HTOffset
;
2497 HashBlock
= NewHashBlock
;
2501 Status
= CmiAddKeyToHashTable(RegistryHive
,
2505 if (NT_SUCCESS(Status
))
2507 KeyCell
->NumberOfSubKeys
++;
2515 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2516 PKEY_OBJECT ParentKey
,
2519 PHASH_TABLE_CELL HashBlock
;
2520 PVALUE_LIST_CELL ValueList
;
2521 PVALUE_CELL ValueCell
;
2522 PDATA_CELL DataCell
;
2525 DPRINT("CmiRemoveSubKey() called\n");
2527 /* Remove all values */
2528 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2530 /* Get pointer to the value list cell */
2531 ValueList
= CmiGetCell (RegistryHive
,
2532 SubKey
->KeyCell
->ValueListOffset
,
2534 if (ValueList
== NULL
)
2536 DPRINT("CmiGetBlock() failed\n");
2537 return STATUS_UNSUCCESSFUL
;
2540 if (ValueList
!= NULL
)
2542 /* Enumerate all values */
2543 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2545 /* Get pointer to value cell */
2546 ValueCell
= CmiGetCell (RegistryHive
,
2547 ValueList
->ValueOffset
[i
],
2549 if (ValueCell
!= NULL
)
2551 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
2553 DataCell
= CmiGetCell (RegistryHive
,
2554 ValueCell
->DataOffset
,
2556 if (DataCell
== NULL
)
2558 DPRINT("CmiGetBlock() failed\n");
2559 return STATUS_UNSUCCESSFUL
;
2562 if (DataCell
!= NULL
)
2564 /* Destroy data cell */
2565 CmiDestroyCell (RegistryHive
,
2567 ValueCell
->DataOffset
);
2571 /* Destroy value cell */
2572 CmiDestroyCell (RegistryHive
,
2574 ValueList
->ValueOffset
[i
]);
2579 /* Destroy value list cell */
2580 CmiDestroyCell (RegistryHive
,
2582 SubKey
->KeyCell
->ValueListOffset
);
2584 SubKey
->KeyCell
->NumberOfValues
= 0;
2585 SubKey
->KeyCell
->ValueListOffset
= (BLOCK_OFFSET
)-1;
2588 /* Remove the key from the parent key's hash block */
2589 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2591 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
)
2592 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2593 ParentKey
->KeyCell
->HashTableOffset
,
2595 if (HashBlock
== NULL
)
2597 DPRINT("CmiGetBlock() failed\n");
2598 return STATUS_UNSUCCESSFUL
;
2600 DPRINT("ParentKey HashBlock %p\n", HashBlock
)
2601 if (HashBlock
!= NULL
)
2603 CmiRemoveKeyFromHashTable(ParentKey
->RegistryHive
,
2605 SubKey
->KeyCellOffset
);
2606 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2607 ParentKey
->KeyCell
->HashTableOffset
);
2611 /* Remove the key's hash block */
2612 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2614 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
)
2615 HashBlock
= CmiGetCell (RegistryHive
,
2616 SubKey
->KeyCell
->HashTableOffset
,
2618 if (HashBlock
== NULL
)
2620 DPRINT("CmiGetBlock() failed\n");
2621 return STATUS_UNSUCCESSFUL
;
2623 DPRINT("SubKey HashBlock %p\n", HashBlock
)
2624 if (HashBlock
!= NULL
)
2626 CmiDestroyCell (RegistryHive
,
2628 SubKey
->KeyCell
->HashTableOffset
);
2629 SubKey
->KeyCell
->HashTableOffset
= -1;
2633 /* Decrement the number of the parent key's sub keys */
2634 if (ParentKey
!= NULL
)
2636 DPRINT("ParentKey %p\n", ParentKey
)
2637 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2639 /* Remove the parent key's hash table */
2640 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2642 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
)
2643 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2644 ParentKey
->KeyCell
->HashTableOffset
,
2646 if (HashBlock
== NULL
)
2648 DPRINT("CmiGetBlock() failed\n");
2649 return STATUS_UNSUCCESSFUL
;
2651 DPRINT("ParentKey HashBlock %p\n", HashBlock
)
2652 if (HashBlock
!= NULL
)
2654 CmiDestroyCell (ParentKey
->RegistryHive
,
2656 ParentKey
->KeyCell
->HashTableOffset
);
2657 ParentKey
->KeyCell
->HashTableOffset
= (BLOCK_OFFSET
)-1;
2661 NtQuerySystemTime(&ParentKey
->KeyCell
->LastWriteTime
);
2662 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2663 ParentKey
->KeyCellOffset
);
2666 /* Destroy key cell */
2667 CmiDestroyCell (RegistryHive
,
2669 SubKey
->KeyCellOffset
);
2670 SubKey
->KeyCell
= NULL
;
2671 SubKey
->KeyCellOffset
= (BLOCK_OFFSET
)-1;
2673 return(STATUS_SUCCESS
);
2678 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2679 IN PKEY_CELL KeyCell
,
2680 IN PUNICODE_STRING ValueName
,
2681 OUT PVALUE_CELL
*ValueCell
,
2682 OUT BLOCK_OFFSET
*VBOffset
)
2684 PVALUE_LIST_CELL ValueListCell
;
2685 PVALUE_CELL CurValueCell
;
2690 /* The key does not have any values */
2691 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2693 return STATUS_SUCCESS
;
2696 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2697 if (ValueListCell
== NULL
)
2699 DPRINT("ValueListCell is NULL\n");
2700 return STATUS_UNSUCCESSFUL
;
2703 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2705 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2707 CurValueCell
= CmiGetCell (RegistryHive
,
2708 ValueListCell
->ValueOffset
[i
],
2710 if (CurValueCell
== NULL
)
2712 DPRINT("CmiGetBlock() failed\n");
2713 return STATUS_UNSUCCESSFUL
;
2716 if ((CurValueCell
!= NULL
) &&
2717 CmiComparePackedNames(ValueName
,
2719 CurValueCell
->NameSize
,
2720 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
2722 *ValueCell
= CurValueCell
;
2724 *VBOffset
= ValueListCell
->ValueOffset
[i
];
2725 //DPRINT("Found value %s\n", ValueName);
2730 return STATUS_SUCCESS
;
2735 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2736 IN PKEY_CELL KeyCell
,
2738 OUT PVALUE_CELL
*ValueCell
)
2740 PVALUE_LIST_CELL ValueListCell
;
2741 PVALUE_CELL CurValueCell
;
2745 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2747 return STATUS_NO_MORE_ENTRIES
;
2750 if (Index
>= KeyCell
->NumberOfValues
)
2752 return STATUS_NO_MORE_ENTRIES
;
2756 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2757 if (ValueListCell
== NULL
)
2759 DPRINT("CmiGetBlock() failed\n");
2760 return STATUS_UNSUCCESSFUL
;
2763 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2766 CurValueCell
= CmiGetCell (RegistryHive
,
2767 ValueListCell
->ValueOffset
[Index
],
2769 if (CurValueCell
== NULL
)
2771 DPRINT("CmiGetBlock() failed\n");
2772 return STATUS_UNSUCCESSFUL
;
2775 *ValueCell
= CurValueCell
;
2777 return STATUS_SUCCESS
;
2782 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2783 IN PKEY_CELL KeyCell
,
2784 IN PUNICODE_STRING ValueName
,
2785 OUT PVALUE_CELL
*pValueCell
,
2786 OUT BLOCK_OFFSET
*pVBOffset
)
2788 PVALUE_LIST_CELL NewValueListCell
;
2789 PVALUE_LIST_CELL ValueListCell
;
2790 PVALUE_CELL NewValueCell
;
2791 BLOCK_OFFSET VLBOffset
;
2792 BLOCK_OFFSET VBOffset
;
2796 Status
= CmiAllocateValueCell(RegistryHive
,
2800 if (!NT_SUCCESS(Status
))
2805 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG
)KeyCell
->ValueListOffset
);
2807 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2809 if (ValueListCell
== NULL
)
2811 CellSize
= sizeof(VALUE_LIST_CELL
) +
2812 (3 * sizeof(BLOCK_OFFSET
));
2813 Status
= CmiAllocateCell (RegistryHive
,
2815 (PVOID
) &ValueListCell
,
2818 if (!NT_SUCCESS(Status
))
2820 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2823 KeyCell
->ValueListOffset
= VLBOffset
;
2825 else if (KeyCell
->NumberOfValues
>=
2826 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
)))
2828 CellSize
= sizeof(VALUE_LIST_CELL
) +
2829 ((KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) * sizeof(BLOCK_OFFSET
));
2830 Status
= CmiAllocateCell (RegistryHive
,
2832 (PVOID
) &NewValueListCell
,
2834 if (!NT_SUCCESS(Status
))
2836 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2840 RtlCopyMemory(&NewValueListCell
->ValueOffset
[0],
2841 &ValueListCell
->ValueOffset
[0],
2842 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2843 CmiDestroyCell (RegistryHive
, ValueListCell
, KeyCell
->ValueListOffset
);
2844 KeyCell
->ValueListOffset
= VLBOffset
;
2845 ValueListCell
= NewValueListCell
;
2848 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2849 KeyCell
->NumberOfValues
,
2850 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2851 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
),
2852 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
));
2854 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = VBOffset
;
2855 KeyCell
->NumberOfValues
++;
2857 *pValueCell
= NewValueCell
;
2858 *pVBOffset
= VBOffset
;
2860 return STATUS_SUCCESS
;
2865 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2866 IN PKEY_CELL KeyCell
,
2867 IN BLOCK_OFFSET KeyCellOffset
,
2868 IN PUNICODE_STRING ValueName
)
2870 PVALUE_LIST_CELL ValueListCell
;
2871 PVALUE_CELL CurValueCell
;
2874 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2876 if (ValueListCell
== NULL
)
2878 DPRINT("CmiGetBlock() failed\n");
2879 return STATUS_SUCCESS
;
2882 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2884 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2886 CurValueCell
= CmiGetCell (RegistryHive
, ValueListCell
->ValueOffset
[i
], NULL
);
2887 if (CurValueCell
== NULL
)
2889 DPRINT("CmiGetBlock() failed\n");
2890 return STATUS_UNSUCCESSFUL
;
2893 if ((CurValueCell
!= NULL
) &&
2894 CmiComparePackedNames(ValueName
,
2896 CurValueCell
->NameSize
,
2897 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
2899 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->ValueOffset
[i
]);
2901 if ((KeyCell
->NumberOfValues
- 1) < i
)
2903 RtlCopyMemory(&ValueListCell
->ValueOffset
[i
],
2904 &ValueListCell
->ValueOffset
[i
+ 1],
2905 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2909 RtlZeroMemory(&ValueListCell
->ValueOffset
[i
], sizeof(BLOCK_OFFSET
));
2912 KeyCell
->NumberOfValues
-= 1;
2917 if (KeyCell
->NumberOfValues
== 0)
2919 CmiDestroyCell (RegistryHive
,
2921 KeyCell
->ValueListOffset
);
2925 CmiMarkBlockDirty(RegistryHive
,
2926 KeyCell
->ValueListOffset
);
2929 CmiMarkBlockDirty(RegistryHive
,
2932 return STATUS_SUCCESS
;
2937 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive
,
2938 OUT PHASH_TABLE_CELL
*HashBlock
,
2939 OUT BLOCK_OFFSET
*HBOffset
,
2940 IN ULONG SubKeyCount
)
2942 PHASH_TABLE_CELL NewHashBlock
;
2946 Status
= STATUS_SUCCESS
;
2948 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
2949 (SubKeyCount
* sizeof(HASH_RECORD
));
2950 Status
= CmiAllocateCell (RegistryHive
,
2952 (PVOID
*) &NewHashBlock
,
2955 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
2957 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2961 NewHashBlock
->Id
= REG_HASH_TABLE_CELL_ID
;
2962 NewHashBlock
->HashTableSize
= SubKeyCount
;
2963 *HashBlock
= NewHashBlock
;
2971 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
2972 PHASH_TABLE_CELL HashBlock
,
2975 BLOCK_OFFSET KeyOffset
;
2978 if (HashBlock
== NULL
)
2981 if (IsPointerHive(RegistryHive
))
2983 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
2987 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
2988 KeyCell
= CmiGetCell (RegistryHive
, KeyOffset
, NULL
);
2996 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
2997 PHASH_TABLE_CELL HashBlock
,
2998 PKEY_CELL NewKeyCell
,
2999 BLOCK_OFFSET NKBOffset
)
3003 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3005 if (HashBlock
->Table
[i
].KeyOffset
== 0)
3007 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
3008 HashBlock
->Table
[i
].HashValue
= 0;
3009 if (NewKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3011 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
,
3013 min(NewKeyCell
->NameSize
, sizeof(ULONG
)));
3015 return STATUS_SUCCESS
;
3019 return STATUS_UNSUCCESSFUL
;
3024 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
3025 PHASH_TABLE_CELL HashBlock
,
3026 BLOCK_OFFSET NKBOffset
)
3030 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3032 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
3034 HashBlock
->Table
[i
].KeyOffset
= 0;
3035 HashBlock
->Table
[i
].HashValue
= 0;
3036 return STATUS_SUCCESS
;
3040 return STATUS_UNSUCCESSFUL
;
3045 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
3046 PVALUE_CELL
*ValueCell
,
3047 BLOCK_OFFSET
*VBOffset
,
3048 IN PUNICODE_STRING ValueName
)
3050 PVALUE_CELL NewValueCell
;
3056 Status
= STATUS_SUCCESS
;
3058 NameSize
= CmiGetPackedNameLength(ValueName
,
3061 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
3063 Status
= CmiAllocateCell (RegistryHive
,
3064 sizeof(VALUE_CELL
) + NameSize
,
3065 (PVOID
*) &NewValueCell
,
3067 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
3069 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3073 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
3074 NewValueCell
->NameSize
= NameSize
;
3077 /* Pack the value name */
3078 for (i
= 0; i
< NameSize
; i
++)
3079 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
3080 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
3084 /* Copy the value name */
3085 RtlCopyMemory(NewValueCell
->Name
,
3088 NewValueCell
->Flags
= 0;
3090 NewValueCell
->DataType
= 0;
3091 NewValueCell
->DataSize
= 0;
3092 NewValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
3093 *ValueCell
= NewValueCell
;
3101 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
3102 PVALUE_CELL ValueCell
,
3103 BLOCK_OFFSET VBOffset
)
3109 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell
, VBOffset
);
3111 VERIFY_VALUE_CELL(ValueCell
);
3113 /* Destroy the data cell */
3114 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
3116 pBlock
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, &pBin
);
3119 DPRINT("CmiGetBlock() failed\n");
3120 return STATUS_UNSUCCESSFUL
;
3123 Status
= CmiDestroyCell (RegistryHive
, pBlock
, ValueCell
->DataOffset
);
3124 if (!NT_SUCCESS(Status
))
3129 /* Update time of heap */
3130 if (!IsNoFileHive(RegistryHive
))
3131 NtQuerySystemTime(&pBin
->DateModified
);
3134 /* Destroy the value cell */
3135 Status
= CmiDestroyCell (RegistryHive
, ValueCell
, VBOffset
);
3137 /* Update time of heap */
3138 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, VBOffset
, &pBin
))
3140 NtQuerySystemTime(&pBin
->DateModified
);
3148 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
3150 BLOCK_OFFSET
*NewBlockOffset
)
3152 PCELL_HEADER tmpBlock
;
3153 PHBIN
* tmpBlockList
;
3156 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
3159 return STATUS_INSUFFICIENT_RESOURCES
;
3162 tmpBin
->BlockId
= REG_BIN_ID
;
3163 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
3164 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
3165 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
3166 tmpBin
->Unused1
= 0;
3167 ZwQuerySystemTime(&tmpBin
->DateModified
);
3168 tmpBin
->Unused2
= 0;
3170 /* Increase size of list of blocks */
3171 tmpBlockList
= ExAllocatePool(NonPagedPool
,
3172 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
3173 if (tmpBlockList
== NULL
)
3176 return STATUS_INSUFFICIENT_RESOURCES
;
3179 if (RegistryHive
->BlockListSize
> 0)
3181 RtlCopyMemory (tmpBlockList
,
3182 RegistryHive
->BlockList
,
3183 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
3184 ExFreePool(RegistryHive
->BlockList
);
3187 RegistryHive
->BlockList
= tmpBlockList
;
3188 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
] = tmpBin
;
3189 RegistryHive
->BlockListSize
++;
3191 /* Initialize a free block in this heap : */
3192 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
3193 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
3195 /* Grow bitmap if necessary */
3196 if (IsNoFileHive(RegistryHive
) &&
3197 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
3199 PULONG BitmapBuffer
;
3202 DPRINT("Grow hive bitmap\n");
3204 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3205 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
3206 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
3207 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
3208 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
3210 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
3211 RtlCopyMemory(BitmapBuffer
,
3212 RegistryHive
->DirtyBitMap
.Buffer
,
3213 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
3214 ExFreePool(RegistryHive
->BitmapBuffer
);
3215 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
3216 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
3217 RegistryHive
->BitmapBuffer
,
3221 *NewBlock
= (PVOID
) tmpBlock
;
3224 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
3226 /* Mark new bin dirty */
3227 CmiMarkBinDirty(RegistryHive
,
3228 tmpBin
->BlockOffset
);
3230 return STATUS_SUCCESS
;
3235 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
3238 BLOCK_OFFSET
*CellOffset
)
3240 PCELL_HEADER NewCell
;
3246 Status
= STATUS_SUCCESS
;
3248 /* Round to 16 bytes multiple */
3249 CellSize
= ROUND_UP(CellSize
, 16);
3251 /* Handle volatile hives first */
3252 if (IsPointerHive(RegistryHive
))
3254 NewCell
= ExAllocatePool(NonPagedPool
, CellSize
);
3256 if (NewCell
== NULL
)
3258 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3262 RtlZeroMemory(NewCell
, CellSize
);
3263 NewCell
->CellSize
= CellSize
;
3265 if (CellOffset
!= NULL
)
3266 *CellOffset
= (BLOCK_OFFSET
) NewCell
;
3271 /* first search in free blocks */
3273 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3275 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
3277 NewCell
= RegistryHive
->FreeList
[i
];
3278 if (CellOffset
!= NULL
)
3279 *CellOffset
= RegistryHive
->FreeListOffset
[i
];
3281 /* Update time of heap */
3282 Temp
= CmiGetCell (RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
3285 DPRINT("CmiGetBlock() failed\n");
3286 return STATUS_UNSUCCESSFUL
;
3291 NtQuerySystemTime(&pBin
->DateModified
);
3292 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
3295 if ((i
+ 1) < RegistryHive
->FreeListSize
)
3297 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
3298 &RegistryHive
->FreeList
[i
+ 1],
3299 sizeof(RegistryHive
->FreeList
[0])
3300 * (RegistryHive
->FreeListSize
- i
- 1));
3301 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
3302 &RegistryHive
->FreeListOffset
[i
+ 1],
3303 sizeof(RegistryHive
->FreeListOffset
[0])
3304 * (RegistryHive
->FreeListSize
- i
- 1));
3306 RegistryHive
->FreeListSize
--;
3311 /* Need to extend hive file : */
3312 if (NewCell
== NULL
)
3315 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewCell
, CellOffset
);
3318 if (NT_SUCCESS(Status
))
3322 /* Split the block in two parts */
3323 if (NewCell
->CellSize
> CellSize
)
3325 NewCell
= (PCELL_HEADER
) ((ULONG_PTR
) NewCell
+ CellSize
);
3326 NewCell
->CellSize
= ((PCELL_HEADER
) (*Cell
))->CellSize
- CellSize
;
3327 CmiAddFree(RegistryHive
,
3329 *CellOffset
+ CellSize
,
3331 CmiMarkBlockDirty(RegistryHive
,
3332 *CellOffset
+ CellSize
);
3334 else if (NewCell
->CellSize
< CellSize
)
3336 return(STATUS_UNSUCCESSFUL
);
3339 RtlZeroMemory(*Cell
, CellSize
);
3340 ((PCELL_HEADER
) (*Cell
))->CellSize
= -CellSize
;
3349 CmiDestroyCell (PREGISTRY_HIVE RegistryHive
,
3351 BLOCK_OFFSET CellOffset
)
3356 Status
= STATUS_SUCCESS
;
3358 if (IsPointerHive(RegistryHive
))
3364 PCELL_HEADER pFree
= Cell
;
3366 if (pFree
->CellSize
< 0)
3367 pFree
->CellSize
= -pFree
->CellSize
;
3369 /* Clear block (except the block size) */
3370 RtlZeroMemory(((PVOID
)pFree
) + sizeof(ULONG
),
3371 pFree
->CellSize
- sizeof(ULONG
));
3373 /* Add block to the list of free blocks */
3374 CmiAddFree(RegistryHive
, Cell
, CellOffset
, TRUE
);
3376 /* Update time of heap */
3377 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, CellOffset
,&pBin
))
3378 NtQuerySystemTime(&pBin
->DateModified
);
3380 CmiMarkBlockDirty(RegistryHive
, CellOffset
);
3388 CmiGetCell (PREGISTRY_HIVE RegistryHive
,
3389 BLOCK_OFFSET CellOffset
,
3399 if (CellOffset
== (BLOCK_OFFSET
)-1)
3404 if (IsPointerHive (RegistryHive
))
3406 return (PVOID
)CellOffset
;
3409 if (CellOffset
> RegistryHive
->BlockListSize
* 4096)
3411 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3412 CellOffset
, RegistryHive
->BlockListSize
* 4096);
3416 pBin
= RegistryHive
->BlockList
[CellOffset
/ 4096];
3427 return((PVOID
)((ULONG_PTR
)pBin
+ (CellOffset
- pBin
->BlockOffset
)));
3432 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3433 PCELL_HEADER FreeBlock
,
3434 BLOCK_OFFSET FreeOffset
)
3436 BLOCK_OFFSET BlockOffset
;
3437 BLOCK_OFFSET BinOffset
;
3443 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3444 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3446 CmiGetCell (RegistryHive
,
3449 DPRINT("Bin %p\n", Bin
);
3453 BinOffset
= Bin
->BlockOffset
;
3454 BinSize
= Bin
->BlockSize
;
3455 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3457 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3459 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3460 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3461 if (BlockOffset
> BinOffset
&&
3462 BlockOffset
< BinOffset
+ BinSize
)
3464 DPRINT("Free block: Offset %lx Size %lx\n",
3465 BlockOffset
, BlockSize
);
3467 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3468 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3469 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3471 DPRINT("Merge current block with previous and next block\n");
3473 RegistryHive
->FreeList
[i
]->CellSize
+=
3474 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3476 FreeBlock
->CellSize
= 0;
3477 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3480 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3482 RtlMoveMemory(&RegistryHive
->FreeList
[i
+ 1],
3483 &RegistryHive
->FreeList
[i
+ 2],
3484 sizeof(RegistryHive
->FreeList
[0])
3485 * (RegistryHive
->FreeListSize
- i
- 2));
3486 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3487 &RegistryHive
->FreeListOffset
[i
+ 2],
3488 sizeof(RegistryHive
->FreeListOffset
[0])
3489 * (RegistryHive
->FreeListSize
- i
- 2));
3491 RegistryHive
->FreeListSize
--;
3493 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3497 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3499 DPRINT("Merge current block with previous block\n");
3501 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3502 FreeBlock
->CellSize
= 0;
3504 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3508 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3510 DPRINT("Merge current block with next block\n");
3512 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3513 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3514 RegistryHive
->FreeList
[i
] = FreeBlock
;
3515 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3517 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3529 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3530 PCELL_HEADER FreeBlock
,
3531 BLOCK_OFFSET FreeOffset
,
3532 BOOLEAN MergeFreeBlocks
)
3534 PCELL_HEADER
*tmpList
;
3535 BLOCK_OFFSET
*tmpListOffset
;
3540 assert(RegistryHive
);
3543 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3544 FreeBlock
, FreeOffset
);
3546 /* Merge free blocks */
3547 if (MergeFreeBlocks
== TRUE
)
3549 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3550 return(STATUS_SUCCESS
);
3553 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3555 tmpList
= ExAllocatePool(PagedPool
,
3556 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3557 if (tmpList
== NULL
)
3558 return STATUS_INSUFFICIENT_RESOURCES
;
3560 tmpListOffset
= ExAllocatePool(PagedPool
,
3561 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3563 if (tmpListOffset
== NULL
)
3565 ExFreePool(tmpList
);
3566 return STATUS_INSUFFICIENT_RESOURCES
;
3569 if (RegistryHive
->FreeListMax
)
3571 RtlMoveMemory(tmpList
,
3572 RegistryHive
->FreeList
,
3573 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3574 RtlMoveMemory(tmpListOffset
,
3575 RegistryHive
->FreeListOffset
,
3576 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3577 ExFreePool(RegistryHive
->FreeList
);
3578 ExFreePool(RegistryHive
->FreeListOffset
);
3580 RegistryHive
->FreeList
= tmpList
;
3581 RegistryHive
->FreeListOffset
= tmpListOffset
;
3582 RegistryHive
->FreeListMax
+= 32;
3585 /* Add new offset to free list, maintaining list in ascending order */
3586 if ((RegistryHive
->FreeListSize
== 0)
3587 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3589 /* Add to end of list */
3590 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3591 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3593 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3595 /* Add to begin of list */
3596 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3597 &RegistryHive
->FreeList
[0],
3598 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3599 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3600 &RegistryHive
->FreeListOffset
[0],
3601 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3602 RegistryHive
->FreeList
[0] = FreeBlock
;
3603 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3604 RegistryHive
->FreeListSize
++;
3608 /* Search where to insert */
3610 maxInd
= RegistryHive
->FreeListSize
- 1;
3611 while ((maxInd
- minInd
) > 1)
3613 medInd
= (minInd
+ maxInd
) / 2;
3614 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3620 /* Insert before maxInd */
3621 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3622 &RegistryHive
->FreeList
[maxInd
],
3623 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3624 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3625 &RegistryHive
->FreeListOffset
[maxInd
],
3626 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3627 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3628 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3629 RegistryHive
->FreeListSize
++;
3632 return STATUS_SUCCESS
;
3637 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3638 BLOCK_OFFSET BlockOffset
)
3645 if (IsNoFileHive(RegistryHive
))
3648 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3650 BlockNumber
= (ULONG
)BlockOffset
/ 4096;
3652 Cell
= CmiGetCell (RegistryHive
,
3656 CellSize
= Cell
->CellSize
;
3658 CellSize
= -CellSize
;
3660 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, 4096) - ROUND_DOWN(BlockOffset
, 4096)) / 4096;
3662 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3665 (Cell
->CellSize
< 0) ? "used" : "free",
3668 RegistryHive
->HiveDirty
= TRUE
;
3669 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3676 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3677 BLOCK_OFFSET BinOffset
)
3683 if (IsNoFileHive(RegistryHive
))
3686 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3688 BlockNumber
= (ULONG
)BinOffset
/ 4096;
3690 Bin
= RegistryHive
->BlockList
[BlockNumber
];
3692 BlockCount
= Bin
->BlockSize
/ 4096;
3694 DPRINT(" BlockNumber %lu Size %lu BlockCount %lu\n",
3699 RegistryHive
->HiveDirty
= TRUE
;
3700 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3707 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3708 OUT PBOOLEAN Packable
)
3712 if (Packable
!= NULL
)
3715 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3717 if (Name
->Buffer
[i
] & 0xFF00)
3719 if (Packable
!= NULL
)
3721 return Name
->Length
;
3725 return (Name
->Length
/ sizeof(WCHAR
));
3730 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3731 IN PCHAR NameBuffer
,
3732 IN USHORT NameBufferSize
,
3733 IN BOOLEAN NamePacked
)
3738 if (NamePacked
== TRUE
)
3740 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3743 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3745 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3751 if (Name
->Length
!= NameBufferSize
)
3754 UNameBuffer
= (PWCHAR
)NameBuffer
;
3756 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3758 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3768 CmiCopyPackedName(PWCHAR NameBuffer
,
3769 PCHAR PackedNameBuffer
,
3770 ULONG PackedNameSize
)
3774 for (i
= 0; i
< PackedNameSize
; i
++)
3775 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];
3780 CmiCompareHash(PUNICODE_STRING KeyName
,
3785 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3786 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3787 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3788 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3790 return (strncmp(Buffer
, HashString
, 4) == 0);
3795 CmiCompareHashI(PUNICODE_STRING KeyName
,
3800 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3801 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3802 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3803 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3805 return (_strnicmp(Buffer
, HashString
, 4) == 0);
3810 CmiCompareKeyNames(PUNICODE_STRING KeyName
,
3816 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3818 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3820 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3823 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3825 if (KeyName
->Buffer
[i
] != (WCHAR
)KeyCell
->Name
[i
])
3831 if (KeyName
->Length
!= KeyCell
->NameSize
)
3834 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3835 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3837 if (KeyName
->Buffer
[i
] != UnicodeName
[i
])
3847 CmiCompareKeyNamesI(PUNICODE_STRING KeyName
,
3853 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3855 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3857 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3860 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3862 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3863 RtlUpcaseUnicodeChar((WCHAR
)KeyCell
->Name
[i
]))
3869 if (KeyName
->Length
!= KeyCell
->NameSize
)
3872 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3873 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3875 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3876 RtlUpcaseUnicodeChar(UnicodeName
[i
]))
3886 CmiCopyKey (PREGISTRY_HIVE DstHive
,
3887 PKEY_CELL DstKeyCell
,
3888 PREGISTRY_HIVE SrcHive
,
3889 PKEY_CELL SrcKeyCell
)
3891 PKEY_CELL NewKeyCell
;
3892 ULONG NewKeyCellSize
;
3893 BLOCK_OFFSET NewKeyCellOffset
;
3894 PHASH_TABLE_CELL NewHashTableCell
;
3895 ULONG NewHashTableSize
;
3896 BLOCK_OFFSET NewHashTableOffset
;
3900 DPRINT ("CmiCopyKey() called\n");
3902 if (DstKeyCell
== NULL
)
3904 /* Allocate and copy key cell */
3905 NewKeyCellSize
= sizeof(KEY_CELL
) + SrcKeyCell
->NameSize
;
3906 Status
= CmiAllocateCell (DstHive
,
3908 (PVOID
) &NewKeyCell
,
3910 if (!NT_SUCCESS(Status
))
3912 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
3915 if (NewKeyCell
== NULL
)
3917 DPRINT1 ("Failed to allocate a key cell\n");
3918 return STATUS_INSUFFICIENT_RESOURCES
;
3921 RtlCopyMemory (NewKeyCell
,
3925 DstHive
->HiveHeader
->RootKeyOffset
= NewKeyCellOffset
;
3927 /* Copy class name */
3928 if (SrcKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
3930 PDATA_CELL SrcClassNameCell
;
3931 PDATA_CELL NewClassNameCell
;
3932 BLOCK_OFFSET NewClassNameOffset
;
3934 SrcClassNameCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ClassNameOffset
, NULL
),
3936 NewKeyCell
->ClassSize
= SrcKeyCell
->ClassSize
;
3937 Status
= CmiAllocateCell (DstHive
,
3938 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
3939 (PVOID
)&NewClassNameCell
,
3940 &NewClassNameOffset
);
3941 if (!NT_SUCCESS(Status
))
3943 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
3947 RtlCopyMemory (NewClassNameCell
,
3949 NewKeyCell
->ClassSize
);
3950 NewKeyCell
->ClassNameOffset
= NewClassNameOffset
;
3955 NewKeyCell
= DstKeyCell
;
3958 /* Allocate hash table */
3959 if (SrcKeyCell
->NumberOfSubKeys
> 0)
3961 NewHashTableSize
= ROUND_UP(SrcKeyCell
->NumberOfSubKeys
+ 1, 4) - 1;
3962 Status
= CmiAllocateHashTableCell (DstHive
,
3964 &NewHashTableOffset
,
3966 if (!NT_SUCCESS(Status
))
3968 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status
);
3971 NewKeyCell
->HashTableOffset
= NewHashTableOffset
;
3974 /* Allocate and copy value list and values */
3975 if (SrcKeyCell
->NumberOfValues
!= 0)
3977 PVALUE_LIST_CELL NewValueListCell
;
3978 PVALUE_LIST_CELL SrcValueListCell
;
3979 PVALUE_CELL NewValueCell
;
3980 PVALUE_CELL SrcValueCell
;
3981 PDATA_CELL SrcValueDataCell
;
3982 PDATA_CELL NewValueDataCell
;
3983 BLOCK_OFFSET ValueCellOffset
;
3984 BLOCK_OFFSET ValueDataCellOffset
;
3985 ULONG NewValueListCellSize
;
3986 ULONG NewValueCellSize
;
3989 NewValueListCellSize
=
3990 ROUND_UP(SrcKeyCell
->NumberOfValues
, 4) * sizeof(BLOCK_OFFSET
);
3991 Status
= CmiAllocateCell (DstHive
,
3992 NewValueListCellSize
,
3993 (PVOID
)&NewValueListCell
,
3994 &NewKeyCell
->ValueListOffset
);
3995 if (!NT_SUCCESS(Status
))
3997 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4001 RtlZeroMemory (NewValueListCell
,
4002 NewValueListCellSize
);
4005 SrcValueListCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ValueListOffset
, NULL
);
4006 for (i
= 0; i
< SrcKeyCell
->NumberOfValues
; i
++)
4008 /* Copy value cell */
4009 SrcValueCell
= CmiGetCell (SrcHive
, SrcValueListCell
->ValueOffset
[i
], NULL
);
4011 NewValueCellSize
= sizeof(VALUE_CELL
) + SrcValueCell
->NameSize
;
4012 Status
= CmiAllocateCell (DstHive
,
4014 (PVOID
*) &NewValueCell
,
4016 if (!NT_SUCCESS(Status
))
4018 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4022 NewValueListCell
->ValueOffset
[i
] = ValueCellOffset
;
4023 RtlCopyMemory (NewValueCell
,
4027 /* Copy value data cell */
4028 if (SrcValueCell
->DataSize
> (LONG
) sizeof(PVOID
))
4030 SrcValueDataCell
= CmiGetCell (SrcHive
, SrcValueCell
->DataOffset
, NULL
);
4032 Status
= CmiAllocateCell (DstHive
,
4033 sizeof(CELL_HEADER
) + SrcValueCell
->DataSize
,
4034 (PVOID
*) &NewValueDataCell
,
4035 &ValueDataCellOffset
);
4036 if (!NT_SUCCESS(Status
))
4038 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4041 RtlCopyMemory (NewValueDataCell
,
4043 SrcValueCell
->DataSize
);
4044 NewValueCell
->DataOffset
= ValueDataCellOffset
;
4050 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4052 PHASH_TABLE_CELL SrcHashTableCell
;
4053 PKEY_CELL SrcSubKeyCell
;
4054 PKEY_CELL NewSubKeyCell
;
4055 ULONG NewSubKeyCellSize
;
4056 BLOCK_OFFSET NewSubKeyCellOffset
;
4057 PHASH_RECORD SrcHashRecord
;
4059 SrcHashTableCell
= CmiGetCell (SrcHive
,
4060 SrcKeyCell
->HashTableOffset
,
4063 for (i
= 0; i
< SrcKeyCell
->NumberOfSubKeys
; i
++)
4065 SrcHashRecord
= &SrcHashTableCell
->Table
[i
];
4066 SrcSubKeyCell
= CmiGetCell (SrcHive
, SrcHashRecord
->KeyOffset
, NULL
);
4068 /* Allocate and copy key cell */
4069 NewSubKeyCellSize
= sizeof(KEY_CELL
) + SrcSubKeyCell
->NameSize
;
4070 Status
= CmiAllocateCell (DstHive
,
4072 (PVOID
)&NewSubKeyCell
,
4073 &NewSubKeyCellOffset
);
4074 if (!NT_SUCCESS(Status
))
4076 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4079 if (NewKeyCell
== NULL
)
4081 DPRINT1 ("Failed to allocate a sub key cell\n");
4082 return STATUS_INSUFFICIENT_RESOURCES
;
4085 NewHashTableCell
->Table
[i
].KeyOffset
= NewSubKeyCellOffset
;
4086 NewHashTableCell
->Table
[i
].HashValue
= SrcHashRecord
->HashValue
;
4088 RtlCopyMemory (NewSubKeyCell
,
4092 /* Copy class name */
4093 if (SrcSubKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4095 PDATA_CELL SrcClassNameCell
;
4096 PDATA_CELL NewClassNameCell
;
4097 BLOCK_OFFSET NewClassNameOffset
;
4099 SrcClassNameCell
= CmiGetCell (SrcHive
,
4100 SrcSubKeyCell
->ClassNameOffset
,
4103 NewSubKeyCell
->ClassSize
= SrcSubKeyCell
->ClassSize
;
4104 Status
= CmiAllocateCell (DstHive
,
4105 sizeof(CELL_HEADER
) + NewSubKeyCell
->ClassSize
,
4106 (PVOID
)&NewClassNameCell
,
4107 &NewClassNameOffset
);
4108 if (!NT_SUCCESS(Status
))
4110 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4114 NewSubKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4115 RtlCopyMemory (NewClassNameCell
,
4117 NewSubKeyCell
->ClassSize
);
4120 /* Copy subkey data and subkeys */
4121 Status
= CmiCopyKey (DstHive
,
4125 if (!NT_SUCCESS(Status
))
4127 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4133 return STATUS_SUCCESS
;
4138 CmiSaveTempHive (PREGISTRY_HIVE Hive
,
4141 IO_STATUS_BLOCK IoStatusBlock
;
4142 LARGE_INTEGER FileOffset
;
4147 DPRINT ("CmiSaveTempHive() called\n");
4149 Hive
->HiveHeader
->Checksum
= CmiCalcChecksum ((PULONG
)Hive
->HiveHeader
);
4151 /* Write hive block */
4152 FileOffset
.QuadPart
= 0ULL;
4153 Status
= NtWriteFile (FileHandle
,
4159 sizeof(HIVE_HEADER
),
4162 if (!NT_SUCCESS(Status
))
4164 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4168 DPRINT ("Saving %lu blocks\n", Hive
->BlockListSize
);
4169 for (BlockIndex
= 0; BlockIndex
< Hive
->BlockListSize
; BlockIndex
++)
4171 BlockPtr
= Hive
->BlockList
[BlockIndex
];
4172 DPRINT ("BlockPtr %p\n", BlockPtr
);
4174 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096ULL;
4175 DPRINT ("File offset %I64x\n", FileOffset
.QuadPart
);
4177 /* Write hive block */
4178 Status
= NtWriteFile (FileHandle
,
4187 if (!NT_SUCCESS(Status
))
4189 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4194 Status
= NtFlushBuffersFile (FileHandle
,
4196 if (!NT_SUCCESS(Status
))
4198 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
4201 DPRINT ("CmiSaveTempHive() done\n");