3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/regfile.c
6 * PURPOSE: Registry file manipulation routines
8 * PROGRAMMERS: No programmer listed.
13 #include <internal/debug.h>
18 /* uncomment to enable hive checks (incomplete and probably buggy) */
21 /* LOCAL MACROS *************************************************************/
23 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
25 BOOLEAN CmiDoVerify
= FALSE
;
28 CmiCalcChecksum(PULONG Buffer
);
30 /* FUNCTIONS ****************************************************************/
33 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header
)
36 RtlZeroMemory(Header
, sizeof(HIVE_HEADER
));
37 Header
->BlockId
= REG_HIVE_ID
;
38 Header
->UpdateCounter1
= 0;
39 Header
->UpdateCounter2
= 0;
40 Header
->DateModified
.u
.LowPart
= 0;
41 Header
->DateModified
.u
.HighPart
= 0;
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 KeQuerySystemTime(&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
= ZwWriteFile(FileHandle
,
399 if (!NT_SUCCESS(Status
))
404 Status
= ZwFlushBuffersFile(FileHandle
,
413 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive
)
415 OBJECT_ATTRIBUTES ObjectAttributes
;
416 FILE_STANDARD_INFORMATION fsi
;
417 IO_STATUS_BLOCK IoStatusBlock
;
418 HANDLE HiveHandle
= INVALID_HANDLE_VALUE
;
419 HANDLE LogHandle
= INVALID_HANDLE_VALUE
;
420 PHIVE_HEADER HiveHeader
= NULL
;
421 PHIVE_HEADER LogHeader
= NULL
;
422 LARGE_INTEGER FileOffset
;
426 RTL_BITMAP BlockBitMap
;
429 DPRINT("CmiCheckAndFixHive() called\n");
431 /* Try to open the hive file */
432 InitializeObjectAttributes(&ObjectAttributes
,
433 &RegistryHive
->HiveFileName
,
434 OBJ_CASE_INSENSITIVE
,
438 Status
= ZwCreateFile(&HiveHandle
,
439 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
443 FILE_ATTRIBUTE_NORMAL
,
446 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
449 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
451 return(STATUS_SUCCESS
);
453 if (!NT_SUCCESS(Status
))
455 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
459 /* Try to open the log file */
460 InitializeObjectAttributes(&ObjectAttributes
,
461 &RegistryHive
->LogFileName
,
462 OBJ_CASE_INSENSITIVE
,
466 Status
= ZwCreateFile(&LogHandle
,
467 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
471 FILE_ATTRIBUTE_NORMAL
,
474 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
477 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
479 LogHandle
= INVALID_HANDLE_VALUE
;
481 else if (!NT_SUCCESS(Status
))
483 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
488 /* Allocate hive header */
489 HiveHeader
= ExAllocatePool(PagedPool
,
490 sizeof(HIVE_HEADER
));
491 if (HiveHeader
== NULL
)
493 DPRINT("ExAllocatePool() failed\n");
494 Status
= STATUS_INSUFFICIENT_RESOURCES
;
498 /* Read hive base block */
499 FileOffset
.QuadPart
= 0ULL;
500 Status
= ZwReadFile(HiveHandle
,
509 if (!NT_SUCCESS(Status
))
511 DPRINT("ZwReadFile() failed (Status %lx)\n", Status
);
515 if (LogHandle
== INVALID_HANDLE_VALUE
)
517 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
518 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
520 /* There is no way to fix the hive without log file - BSOD! */
521 DPRINT("Hive header inconsistent and no log file available!\n");
522 KEBUGCHECK(CONFIG_LIST_FAILED
);
525 Status
= STATUS_SUCCESS
;
530 /* Allocate hive header */
531 LogHeader
= ExAllocatePool(PagedPool
,
532 sizeof(HIVE_HEADER
));
533 if (LogHeader
== NULL
)
535 DPRINT("ExAllocatePool() failed\n");
536 Status
= STATUS_INSUFFICIENT_RESOURCES
;
540 /* Read log file header */
541 FileOffset
.QuadPart
= 0ULL;
542 Status
= ZwReadFile(LogHandle
,
551 if (!NT_SUCCESS(Status
))
553 DPRINT("ZwReadFile() failed (Status %lx)\n", Status
);
557 /* Check log file header integrity */
558 if (LogHeader
->Checksum
!= CmiCalcChecksum((PULONG
)LogHeader
) ||
559 LogHeader
->UpdateCounter1
!= LogHeader
->UpdateCounter2
)
561 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
562 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
564 DPRINT("Hive file and log file are inconsistent!\n");
565 KEBUGCHECK(CONFIG_LIST_FAILED
);
568 /* Log file damaged but hive is okay */
569 Status
= STATUS_SUCCESS
;
573 if (HiveHeader
->UpdateCounter1
== HiveHeader
->UpdateCounter2
&&
574 HiveHeader
->UpdateCounter1
== LogHeader
->UpdateCounter1
)
576 /* Hive and log file are up-to-date */
577 Status
= STATUS_SUCCESS
;
582 * Hive needs an update!
586 Status
= ZwQueryInformationFile(LogHandle
,
590 FileStandardInformation
);
591 if (!NT_SUCCESS(Status
))
593 DPRINT("ZwQueryInformationFile() failed (Status %lx)\n", Status
);
596 FileSize
= fsi
.EndOfFile
.u
.LowPart
;
598 /* Calculate bitmap and block size */
599 BitmapSize
= ROUND_UP((FileSize
/ REG_BLOCK_SIZE
) - 1, sizeof(ULONG
) * 8) / 8;
600 BufferSize
= sizeof(HIVE_HEADER
) +
603 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
605 /* Reallocate log header block */
606 ExFreePool(LogHeader
);
607 LogHeader
= ExAllocatePool(PagedPool
,
609 if (LogHeader
== NULL
)
611 DPRINT("ExAllocatePool() failed\n");
612 Status
= STATUS_INSUFFICIENT_RESOURCES
;
616 /* Read log file header */
617 FileOffset
.QuadPart
= 0ULL;
618 Status
= ZwReadFile(LogHandle
,
627 if (!NT_SUCCESS(Status
))
629 DPRINT("ZwReadFile() failed (Status %lx)\n", Status
);
633 /* Initialize bitmap */
634 RtlInitializeBitMap(&BlockBitMap
,
635 (PVOID
)((ULONG_PTR
)LogHeader
+ REG_BLOCK_SIZE
+ sizeof(ULONG
)),
638 /* FIXME: Update dirty blocks */
641 /* FIXME: Update hive header */
644 Status
= STATUS_SUCCESS
;
648 /* Clean up the mess */
650 if (HiveHeader
!= NULL
)
651 ExFreePool(HiveHeader
);
653 if (LogHeader
!= NULL
)
654 ExFreePool(LogHeader
);
656 if (LogHandle
!= INVALID_HANDLE_VALUE
)
667 CmiImportHiveBins(PREGISTRY_HIVE Hive
,
670 BLOCK_OFFSET BlockOffset
;
677 while (BlockIndex
< Hive
->BlockListSize
)
679 Bin
= (PHBIN
)((ULONG_PTR
)ChunkPtr
+ BlockOffset
);
681 if (Bin
->HeaderId
!= REG_BIN_ID
)
683 DPRINT1 ("Bad bin header id %x, offset %x\n", Bin
->HeaderId
, BlockOffset
);
684 return STATUS_REGISTRY_CORRUPT
;
687 ASSERTMSG("Bin size must be multiple of 4K\n",
688 (Bin
->BinSize
% REG_BLOCK_SIZE
) == 0);
690 /* Allocate the hive block */
691 Hive
->BlockList
[BlockIndex
].Bin
= ExAllocatePool (PagedPool
,
693 if (Hive
->BlockList
[BlockIndex
].Bin
== NULL
)
695 DPRINT1 ("ExAllocatePool() failed\n");
696 return STATUS_INSUFFICIENT_RESOURCES
;
698 Hive
->BlockList
[BlockIndex
].Block
= (PVOID
)Hive
->BlockList
[BlockIndex
].Bin
;
701 RtlCopyMemory (Hive
->BlockList
[BlockIndex
].Bin
,
705 if (Bin
->BinSize
> REG_BLOCK_SIZE
)
707 for (j
= 1; j
< Bin
->BinSize
/ REG_BLOCK_SIZE
; j
++)
709 Hive
->BlockList
[BlockIndex
+ j
].Bin
= Hive
->BlockList
[BlockIndex
].Bin
;
710 Hive
->BlockList
[BlockIndex
+ j
].Block
=
711 (PVOID
)((ULONG_PTR
)Hive
->BlockList
[BlockIndex
].Bin
+ (j
* REG_BLOCK_SIZE
));
715 BlockIndex
+= Bin
->BinSize
/ REG_BLOCK_SIZE
;
716 BlockOffset
+= Bin
->BinSize
;
719 return STATUS_SUCCESS
;
724 CmiFreeHiveBins (PREGISTRY_HIVE Hive
)
730 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
732 if (Hive
->BlockList
[i
].Bin
== NULL
)
735 if (Hive
->BlockList
[i
].Bin
!= Bin
)
737 Bin
= Hive
->BlockList
[i
].Bin
;
738 ExFreePool (Hive
->BlockList
[i
].Bin
);
740 Hive
->BlockList
[i
].Bin
= NULL
;
741 Hive
->BlockList
[i
].Block
= NULL
;
747 CmiCreateHiveFreeCellList(PREGISTRY_HIVE Hive
)
749 BLOCK_OFFSET BlockOffset
;
750 PCELL_HEADER FreeBlock
;
756 /* Initialize the free cell list */
757 Hive
->FreeListSize
= 0;
758 Hive
->FreeListMax
= 0;
759 Hive
->FreeList
= NULL
;
760 Hive
->FreeListOffset
= NULL
;
764 while (BlockIndex
< Hive
->BlockListSize
)
766 Bin
= Hive
->BlockList
[BlockIndex
].Bin
;
768 /* Search free blocks and add to list */
769 FreeOffset
= REG_HBIN_DATA_OFFSET
;
770 while (FreeOffset
< Bin
->BinSize
)
772 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) Bin
+ FreeOffset
);
773 if (FreeBlock
->CellSize
> 0)
775 Status
= CmiAddFree(Hive
,
777 Bin
->BinOffset
+ FreeOffset
,
780 if (!NT_SUCCESS(Status
))
785 FreeOffset
+= FreeBlock
->CellSize
;
789 FreeOffset
-= FreeBlock
->CellSize
;
793 BlockIndex
+= Bin
->BinSize
/ REG_BLOCK_SIZE
;
794 BlockOffset
+= Bin
->BinSize
;
797 return STATUS_SUCCESS
;
802 CmiFreeHiveFreeCellList(PREGISTRY_HIVE Hive
)
804 ExFreePool (Hive
->FreeList
);
805 ExFreePool (Hive
->FreeListOffset
);
807 Hive
->FreeListSize
= 0;
808 Hive
->FreeListMax
= 0;
809 Hive
->FreeList
= NULL
;
810 Hive
->FreeListOffset
= NULL
;
815 CmiCreateHiveBitmap(PREGISTRY_HIVE Hive
)
819 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
820 BitmapSize
= ROUND_UP(Hive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
821 DPRINT("Hive->BlockListSize: %lu\n", Hive
->BlockListSize
);
822 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
824 /* Allocate bitmap */
825 Hive
->BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
827 if (Hive
->BitmapBuffer
== NULL
)
829 return STATUS_INSUFFICIENT_RESOURCES
;
832 RtlInitializeBitMap(&Hive
->DirtyBitMap
,
836 /* Initialize bitmap */
837 RtlClearAllBits(&Hive
->DirtyBitMap
);
838 Hive
->HiveDirty
= FALSE
;
840 return STATUS_SUCCESS
;
845 CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive
,
848 OBJECT_ATTRIBUTES ObjectAttributes
;
849 ULONG CreateDisposition
;
850 IO_STATUS_BLOCK IoSB
;
852 PSECTION_OBJECT SectionObject
;
857 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) called\n",
858 RegistryHive
, Filename
);
860 /* Duplicate Filename */
861 Status
= RtlCreateUnicodeString(&RegistryHive
->HiveFileName
,
863 if (!NT_SUCCESS(Status
))
865 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status
);
869 /* Create log file name */
870 RegistryHive
->LogFileName
.Length
= (wcslen(Filename
) + 4) * sizeof(WCHAR
);
871 RegistryHive
->LogFileName
.MaximumLength
= RegistryHive
->LogFileName
.Length
+ sizeof(WCHAR
);
872 RegistryHive
->LogFileName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
873 RegistryHive
->LogFileName
.MaximumLength
,
874 TAG('U', 'S', 'T', 'R'));
875 if (RegistryHive
->LogFileName
.Buffer
== NULL
)
877 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
878 DPRINT("ExAllocatePool() failed\n");
879 return(STATUS_INSUFFICIENT_RESOURCES
);
881 wcscpy(RegistryHive
->LogFileName
.Buffer
,
883 wcscat(RegistryHive
->LogFileName
.Buffer
,
887 /* Check and eventually fix a hive */
888 Status
= CmiCheckAndFixHive(RegistryHive
);
889 if (!NT_SUCCESS(Status
))
891 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
892 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
893 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status
);
898 InitializeObjectAttributes(&ObjectAttributes
,
899 &RegistryHive
->HiveFileName
,
900 OBJ_CASE_INSENSITIVE
,
904 CreateDisposition
= FILE_OPEN_IF
;
905 Status
= ZwCreateFile(&FileHandle
,
910 FILE_ATTRIBUTE_NORMAL
,
913 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
916 if (!NT_SUCCESS(Status
))
918 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
919 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
920 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
924 if (IoSB
.Information
!= FILE_OPENED
)
926 Status
= CmiCreateNewRegFile(FileHandle
);
927 if (!NT_SUCCESS(Status
))
929 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status
);
931 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
932 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
937 /* Create the hive section */
938 Status
= MmCreateSection(&SectionObject
,
946 if (!NT_SUCCESS(Status
))
948 DPRINT1("MmCreateSection() failed (Status %lx)\n", Status
);
949 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
950 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
954 /* Map the hive file */
957 Status
= MmMapViewOfSection(SectionObject
,
958 PsGetCurrentProcess(),
967 if (!NT_SUCCESS(Status
))
969 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status
);
970 ObDereferenceObject(SectionObject
);
971 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
972 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
976 DPRINT("ViewBase %p ViewSize %lx\n", ViewBase
, ViewSize
);
978 /* Copy hive header and initalize hive */
979 RtlCopyMemory (RegistryHive
->HiveHeader
,
981 sizeof(HIVE_HEADER
));
982 RegistryHive
->FileSize
= ViewSize
;
983 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ REG_BLOCK_SIZE
) - 1;
984 RegistryHive
->UpdateCounter
= RegistryHive
->HiveHeader
->UpdateCounter1
;
986 /* Allocate hive block list */
987 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
988 RegistryHive
->BlockListSize
* sizeof(BLOCK_LIST_ENTRY
));
989 if (RegistryHive
->BlockList
== NULL
)
991 DPRINT1("Failed to allocate the hive block list\n");
992 MmUnmapViewOfSection(PsGetCurrentProcess(),
994 ObDereferenceObject(SectionObject
);
995 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
996 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
);
1014 ZwClose(FileHandle
);
1018 /* Unmap and dereference the hive section */
1019 MmUnmapViewOfSection(PsGetCurrentProcess(),
1021 ObDereferenceObject(SectionObject
);
1023 /* Close the hive file */
1024 ZwClose(FileHandle
);
1026 /* Initialize the free cell list */
1027 Status
= CmiCreateHiveFreeCellList (RegistryHive
);
1028 if (!NT_SUCCESS(Status
))
1030 CmiFreeHiveBins(RegistryHive
);
1031 ExFreePool(RegistryHive
->BlockList
);
1032 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1033 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1037 /* Create the block bitmap */
1038 Status
= CmiCreateHiveBitmap (RegistryHive
);
1039 if (!NT_SUCCESS(Status
))
1041 CmiFreeHiveFreeCellList(RegistryHive
);
1042 CmiFreeHiveBins(RegistryHive
);
1043 ExFreePool(RegistryHive
->BlockList
);
1044 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1045 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1049 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n",
1050 RegistryHive
, Filename
);
1052 return STATUS_SUCCESS
;
1057 CmiCreateVolatileHive(PREGISTRY_HIVE
*RegistryHive
)
1059 PKEY_CELL RootKeyCell
;
1060 PREGISTRY_HIVE Hive
;
1062 *RegistryHive
= NULL
;
1064 Hive
= ExAllocatePool (NonPagedPool
,
1065 sizeof(REGISTRY_HIVE
));
1067 return STATUS_INSUFFICIENT_RESOURCES
;
1069 RtlZeroMemory (Hive
,
1070 sizeof(REGISTRY_HIVE
));
1072 DPRINT("Hive 0x%p\n", Hive
);
1074 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1075 sizeof(HIVE_HEADER
));
1076 if (Hive
->HiveHeader
== NULL
)
1079 return STATUS_INSUFFICIENT_RESOURCES
;
1081 RtlZeroMemory (Hive
->HiveHeader
,
1082 sizeof(HIVE_HEADER
));
1084 Hive
->Flags
= (HIVE_NO_FILE
| HIVE_POINTER
);
1086 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1088 RootKeyCell
= (PKEY_CELL
)ExAllocatePool (NonPagedPool
,
1090 if (RootKeyCell
== NULL
)
1092 ExFreePool(Hive
->HiveHeader
);
1094 return STATUS_INSUFFICIENT_RESOURCES
;
1097 CmiCreateDefaultRootKeyCell (RootKeyCell
);
1098 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)RootKeyCell
;
1100 /* Acquire hive list lock exclusively */
1101 KeEnterCriticalRegion();
1102 ExAcquireResourceExclusiveLite (&CmiRegistryLock
, TRUE
);
1104 /* Add the new hive to the hive list */
1105 InsertTailList (&CmiHiveListHead
,
1108 /* Release hive list lock */
1109 ExReleaseResourceLite (&CmiRegistryLock
);
1110 KeLeaveCriticalRegion();
1112 VERIFY_REGISTRY_HIVE (Hive
);
1114 *RegistryHive
= Hive
;
1116 return STATUS_SUCCESS
;
1121 CmiCreateTempHive(PREGISTRY_HIVE
*RegistryHive
)
1124 PCELL_HEADER FreeCell
;
1125 PREGISTRY_HIVE Hive
;
1128 DPRINT ("CmiCreateTempHive() called\n");
1130 *RegistryHive
= NULL
;
1132 Hive
= ExAllocatePool (NonPagedPool
,
1133 sizeof(REGISTRY_HIVE
));
1136 DPRINT1 ("Failed to allocate registry hive block\n");
1137 return STATUS_INSUFFICIENT_RESOURCES
;
1139 RtlZeroMemory (Hive
,
1140 sizeof(REGISTRY_HIVE
));
1142 DPRINT ("Hive 0x%p\n", Hive
);
1144 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1146 if (Hive
->HiveHeader
== NULL
)
1148 DPRINT1 ("Failed to allocate hive header block\n");
1150 return STATUS_INSUFFICIENT_RESOURCES
;
1152 RtlZeroMemory (Hive
->HiveHeader
,
1155 DPRINT ("HiveHeader 0x%p\n", Hive
->HiveHeader
);
1157 Hive
->Flags
= HIVE_NO_FILE
;
1159 RtlInitUnicodeString (&Hive
->HiveFileName
,
1161 RtlInitUnicodeString (&Hive
->LogFileName
,
1164 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1166 /* Allocate hive block list */
1167 Hive
->BlockList
= ExAllocatePool (NonPagedPool
,
1168 sizeof(PBLOCK_LIST_ENTRY
));
1169 if (Hive
->BlockList
== NULL
)
1171 DPRINT1 ("Failed to allocate hive block list\n");
1172 ExFreePool(Hive
->HiveHeader
);
1174 return STATUS_INSUFFICIENT_RESOURCES
;
1177 /* Allocate first Bin */
1178 Hive
->BlockList
[0].Bin
= ExAllocatePool (NonPagedPool
,
1180 if (Hive
->BlockList
[0].Bin
== NULL
)
1182 DPRINT1 ("Failed to allocate first bin\n");
1183 ExFreePool(Hive
->BlockList
);
1184 ExFreePool(Hive
->HiveHeader
);
1186 return STATUS_INSUFFICIENT_RESOURCES
;
1188 Hive
->BlockList
[0].Block
= (PVOID
)Hive
->BlockList
[0].Bin
;
1190 Hive
->FileSize
= 2* REG_BLOCK_SIZE
;
1191 Hive
->BlockListSize
= 1;
1192 Hive
->UpdateCounter
= Hive
->HiveHeader
->UpdateCounter1
;
1195 BinHeader
= Hive
->BlockList
[0].Bin
;
1196 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)BinHeader
+ REG_HBIN_DATA_OFFSET
);
1198 CmiCreateDefaultBinHeader (BinHeader
);
1201 BinHeader
->BinOffset
= 0;
1203 /* Offset to root key block */
1204 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
1206 /* The rest of the block is free */
1207 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
1209 /* Create the free cell list */
1210 Status
= CmiCreateHiveFreeCellList (Hive
);
1211 if (Hive
->BlockList
[0].Bin
== NULL
)
1213 DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status
);
1214 ExFreePool(Hive
->BlockList
[0].Bin
);
1215 ExFreePool(Hive
->BlockList
);
1216 ExFreePool(Hive
->HiveHeader
);
1221 /* Acquire hive list lock exclusively */
1222 KeEnterCriticalRegion();
1223 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1225 /* Add the new hive to the hive list */
1226 InsertTailList (&CmiHiveListHead
,
1229 /* Release hive list lock */
1230 ExReleaseResourceLite(&CmiRegistryLock
);
1231 KeLeaveCriticalRegion();
1233 VERIFY_REGISTRY_HIVE (Hive
);
1235 *RegistryHive
= Hive
;
1237 return STATUS_SUCCESS
;
1242 CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1243 IN PUNICODE_STRING FileName
,
1246 PREGISTRY_HIVE Hive
;
1249 DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName
);
1251 if (Flags
& ~REG_NO_LAZY_FLUSH
)
1252 return STATUS_INVALID_PARAMETER
;
1254 Hive
= ExAllocatePool (NonPagedPool
,
1255 sizeof(REGISTRY_HIVE
));
1258 DPRINT1 ("Failed to allocate hive header.\n");
1259 return STATUS_INSUFFICIENT_RESOURCES
;
1261 RtlZeroMemory (Hive
,
1262 sizeof(REGISTRY_HIVE
));
1264 DPRINT ("Hive 0x%p\n", Hive
);
1265 Hive
->Flags
= (Flags
& REG_NO_LAZY_FLUSH
) ? HIVE_NO_SYNCH
: 0;
1267 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool(NonPagedPool
,
1268 sizeof(HIVE_HEADER
));
1269 if (Hive
->HiveHeader
== NULL
)
1271 DPRINT1 ("Failed to allocate hive header.\n");
1273 return STATUS_INSUFFICIENT_RESOURCES
;
1276 RtlZeroMemory (Hive
->HiveHeader
,
1277 sizeof(HIVE_HEADER
));
1279 Status
= CmiInitNonVolatileRegistryHive (Hive
,
1281 if (!NT_SUCCESS (Status
))
1283 DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status
);
1284 ExFreePool (Hive
->HiveHeader
);
1289 /* Add the new hive to the hive list */
1290 InsertTailList (&CmiHiveListHead
,
1293 VERIFY_REGISTRY_HIVE(Hive
);
1295 Status
= CmiConnectHive (KeyObjectAttributes
,
1297 if (!NT_SUCCESS(Status
))
1299 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status
);
1300 // CmiRemoveRegistryHive (Hive);
1303 DPRINT ("CmiLoadHive() done\n");
1310 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
1312 if (RegistryHive
->Flags
& HIVE_POINTER
)
1313 return STATUS_UNSUCCESSFUL
;
1315 /* Remove hive from hive list */
1316 RemoveEntryList (&RegistryHive
->HiveList
);
1318 /* Release file names */
1319 RtlFreeUnicodeString (&RegistryHive
->HiveFileName
);
1320 RtlFreeUnicodeString (&RegistryHive
->LogFileName
);
1322 /* Release hive bitmap */
1323 ExFreePool (RegistryHive
->BitmapBuffer
);
1325 /* Release free cell list */
1326 ExFreePool (RegistryHive
->FreeList
);
1327 ExFreePool (RegistryHive
->FreeListOffset
);
1329 /* Release bins and bin list */
1330 CmiFreeHiveBins (RegistryHive
);
1331 ExFreePool (RegistryHive
->BlockList
);
1333 /* Release hive header */
1334 ExFreePool (RegistryHive
->HiveHeader
);
1337 ExFreePool (RegistryHive
);
1339 return STATUS_SUCCESS
;
1344 CmiCalcChecksum(PULONG Buffer
)
1349 for (i
= 0; i
< 127; i
++)
1357 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
1359 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1360 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1361 OBJECT_ATTRIBUTES ObjectAttributes
;
1362 IO_STATUS_BLOCK IoStatusBlock
;
1364 LARGE_INTEGER FileOffset
;
1374 DPRINT("CmiStartLogUpdate() called\n");
1376 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1377 BufferSize
= sizeof(HIVE_HEADER
) +
1380 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1382 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1384 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
,
1388 DPRINT("ExAllocatePool() failed\n");
1389 return(STATUS_INSUFFICIENT_RESOURCES
);
1391 RtlZeroMemory (Buffer
,
1394 /* Open log file for writing */
1395 InitializeObjectAttributes(&ObjectAttributes
,
1396 &RegistryHive
->LogFileName
,
1397 OBJ_CASE_INSENSITIVE
,
1401 Status
= ZwCreateFile(&FileHandle
,
1406 FILE_ATTRIBUTE_NORMAL
,
1409 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1412 if (!NT_SUCCESS(Status
))
1414 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1419 /* Update firt update counter and checksum */
1420 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1421 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1423 /* Copy hive header */
1424 RtlCopyMemory(Buffer
,
1425 RegistryHive
->HiveHeader
,
1426 sizeof(HIVE_HEADER
));
1427 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1434 RegistryHive
->DirtyBitMap
.Buffer
,
1437 /* Write hive block and block bitmap */
1438 FileOffset
.QuadPart
= (ULONGLONG
)0;
1439 Status
= ZwWriteFile(FileHandle
,
1448 if (!NT_SUCCESS(Status
))
1450 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1451 ZwClose(FileHandle
);
1457 /* Write dirty blocks */
1458 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1460 while (BlockIndex
< RegistryHive
->BlockListSize
)
1462 LastIndex
= BlockIndex
;
1463 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1466 if (BlockIndex
== (ULONG
)-1 || BlockIndex
< LastIndex
)
1468 DPRINT("No more set bits\n");
1469 Status
= STATUS_SUCCESS
;
1473 DPRINT("Block %lu is dirty\n", BlockIndex
);
1475 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1476 DPRINT("BlockPtr %p\n", BlockPtr
);
1477 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1479 /* Write hive block */
1480 Status
= ZwWriteFile(FileHandle
,
1489 if (!NT_SUCCESS(Status
))
1491 DPRINT1("ZwWriteFile() failed (Status %lx)\n", Status
);
1492 ZwClose(FileHandle
);
1497 FileOffset
.QuadPart
+= (ULONGLONG
)REG_BLOCK_SIZE
;
1500 /* Truncate log file */
1501 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1502 Status
= ZwSetInformationFile(FileHandle
,
1505 sizeof(FILE_END_OF_FILE_INFORMATION
),
1506 FileEndOfFileInformation
);
1507 if (!NT_SUCCESS(Status
))
1509 DPRINT("ZwSetInformationFile() failed (Status %lx)\n", Status
);
1510 ZwClose(FileHandle
);
1514 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1515 Status
= ZwSetInformationFile(FileHandle
,
1517 &FileAllocationInfo
,
1518 sizeof(FILE_ALLOCATION_INFORMATION
),
1519 FileAllocationInformation
);
1520 if (!NT_SUCCESS(Status
))
1522 DPRINT("ZwSetInformationFile() failed (Status %lx)\n", Status
);
1523 ZwClose(FileHandle
);
1527 /* Flush the log file */
1528 Status
= ZwFlushBuffersFile(FileHandle
,
1530 if (!NT_SUCCESS(Status
))
1532 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1535 ZwClose(FileHandle
);
1542 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1544 OBJECT_ATTRIBUTES ObjectAttributes
;
1545 IO_STATUS_BLOCK IoStatusBlock
;
1547 LARGE_INTEGER FileOffset
;
1554 DPRINT("CmiFinishLogUpdate() called\n");
1556 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1557 BufferSize
= sizeof(HIVE_HEADER
) +
1560 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1562 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1564 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1567 DPRINT("ExAllocatePool() failed\n");
1568 return(STATUS_INSUFFICIENT_RESOURCES
);
1571 /* Open log file for writing */
1572 InitializeObjectAttributes(&ObjectAttributes
,
1573 &RegistryHive
->LogFileName
,
1574 OBJ_CASE_INSENSITIVE
,
1578 Status
= ZwCreateFile(&FileHandle
,
1583 FILE_ATTRIBUTE_NORMAL
,
1586 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1589 if (!NT_SUCCESS(Status
))
1591 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1596 /* Update first and second update counter and checksum */
1597 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1598 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1599 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1601 /* Copy hive header */
1602 RtlCopyMemory(Buffer
,
1603 RegistryHive
->HiveHeader
,
1604 sizeof(HIVE_HEADER
));
1605 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1607 /* Write empty block bitmap */
1615 /* Write hive block and block bitmap */
1616 FileOffset
.QuadPart
= (ULONGLONG
)0;
1617 Status
= ZwWriteFile(FileHandle
,
1626 if (!NT_SUCCESS(Status
))
1628 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1629 ZwClose(FileHandle
);
1636 /* Flush the log file */
1637 Status
= ZwFlushBuffersFile(FileHandle
,
1639 if (!NT_SUCCESS(Status
))
1641 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1644 ZwClose(FileHandle
);
1651 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1653 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1654 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1655 OBJECT_ATTRIBUTES ObjectAttributes
;
1656 IO_STATUS_BLOCK IoStatusBlock
;
1662 DPRINT("CmiCleanupLogUpdate() called\n");
1664 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1665 BufferSize
= sizeof(HIVE_HEADER
) +
1668 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1670 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1672 /* Open log file for writing */
1673 InitializeObjectAttributes(&ObjectAttributes
,
1674 &RegistryHive
->LogFileName
,
1675 OBJ_CASE_INSENSITIVE
,
1679 Status
= ZwCreateFile(&FileHandle
,
1684 FILE_ATTRIBUTE_NORMAL
,
1687 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1690 if (!NT_SUCCESS(Status
))
1692 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1696 /* Truncate log file */
1697 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1698 Status
= ZwSetInformationFile(FileHandle
,
1701 sizeof(FILE_END_OF_FILE_INFORMATION
),
1702 FileEndOfFileInformation
);
1703 if (!NT_SUCCESS(Status
))
1705 DPRINT("ZwSetInformationFile() failed (Status %lx)\n", Status
);
1706 ZwClose(FileHandle
);
1710 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1711 Status
= ZwSetInformationFile(FileHandle
,
1713 &FileAllocationInfo
,
1714 sizeof(FILE_ALLOCATION_INFORMATION
),
1715 FileAllocationInformation
);
1716 if (!NT_SUCCESS(Status
))
1718 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1719 ZwClose(FileHandle
);
1723 /* Flush the log file */
1724 Status
= ZwFlushBuffersFile(FileHandle
,
1726 if (!NT_SUCCESS(Status
))
1728 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1731 ZwClose(FileHandle
);
1738 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1740 OBJECT_ATTRIBUTES ObjectAttributes
;
1741 IO_STATUS_BLOCK IoStatusBlock
;
1743 LARGE_INTEGER FileOffset
;
1749 DPRINT("CmiStartHiveUpdate() called\n");
1751 /* Open hive for writing */
1752 InitializeObjectAttributes(&ObjectAttributes
,
1753 &RegistryHive
->HiveFileName
,
1754 OBJ_CASE_INSENSITIVE
,
1758 Status
= ZwCreateFile(&FileHandle
,
1763 FILE_ATTRIBUTE_NORMAL
,
1766 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1769 if (!NT_SUCCESS(Status
))
1771 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1775 /* Update firt update counter and checksum */
1776 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1777 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1779 /* Write hive block */
1780 FileOffset
.QuadPart
= (ULONGLONG
)0;
1781 Status
= ZwWriteFile(FileHandle
,
1786 RegistryHive
->HiveHeader
,
1787 sizeof(HIVE_HEADER
),
1790 if (!NT_SUCCESS(Status
))
1792 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1793 ZwClose(FileHandle
);
1798 while (BlockIndex
< RegistryHive
->BlockListSize
)
1800 LastIndex
= BlockIndex
;
1801 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1804 if (BlockIndex
== (ULONG
)-1 || BlockIndex
< LastIndex
)
1806 DPRINT("No more set bits\n");
1807 Status
= STATUS_SUCCESS
;
1811 DPRINT("Block %lu is dirty\n", BlockIndex
);
1813 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1814 DPRINT(" BlockPtr %p\n", BlockPtr
);
1816 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
1817 DPRINT(" File offset %I64x\n", FileOffset
.QuadPart
);
1819 /* Write hive block */
1820 Status
= ZwWriteFile(FileHandle
,
1829 if (!NT_SUCCESS(Status
))
1831 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1832 ZwClose(FileHandle
);
1839 Status
= ZwFlushBuffersFile(FileHandle
,
1841 if (!NT_SUCCESS(Status
))
1843 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1846 ZwClose(FileHandle
);
1853 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1855 OBJECT_ATTRIBUTES ObjectAttributes
;
1856 IO_STATUS_BLOCK IoStatusBlock
;
1857 LARGE_INTEGER FileOffset
;
1861 DPRINT("CmiFinishHiveUpdate() called\n");
1863 InitializeObjectAttributes(&ObjectAttributes
,
1864 &RegistryHive
->HiveFileName
,
1865 OBJ_CASE_INSENSITIVE
,
1869 Status
= ZwCreateFile(&FileHandle
,
1874 FILE_ATTRIBUTE_NORMAL
,
1877 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1880 if (!NT_SUCCESS(Status
))
1882 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status
);
1886 /* Update second update counter and checksum */
1887 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1888 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1889 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1891 /* Write hive block */
1892 FileOffset
.QuadPart
= (ULONGLONG
)0;
1893 Status
= ZwWriteFile(FileHandle
,
1898 RegistryHive
->HiveHeader
,
1899 sizeof(HIVE_HEADER
),
1902 if (!NT_SUCCESS(Status
))
1904 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status
);
1905 ZwClose(FileHandle
);
1909 Status
= ZwFlushBuffersFile(FileHandle
,
1911 if (!NT_SUCCESS(Status
))
1913 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
1916 ZwClose(FileHandle
);
1923 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1927 DPRINT("CmiFlushRegistryHive() called\n");
1929 if (RegistryHive
->HiveDirty
== FALSE
)
1931 return(STATUS_SUCCESS
);
1934 DPRINT("Hive '%wZ' is dirty\n",
1935 &RegistryHive
->HiveFileName
);
1936 DPRINT("Log file: '%wZ'\n",
1937 &RegistryHive
->LogFileName
);
1939 /* Update hive header modification time */
1940 KeQuerySystemTime(&RegistryHive
->HiveHeader
->DateModified
);
1942 /* Start log update */
1943 Status
= CmiStartLogUpdate(RegistryHive
);
1944 if (!NT_SUCCESS(Status
))
1946 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1950 /* Finish log update */
1951 Status
= CmiFinishLogUpdate(RegistryHive
);
1952 if (!NT_SUCCESS(Status
))
1954 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1958 /* Start hive update */
1959 Status
= CmiStartHiveUpdate(RegistryHive
);
1960 if (!NT_SUCCESS(Status
))
1962 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1966 /* Finish the hive update */
1967 Status
= CmiFinishHiveUpdate(RegistryHive
);
1968 if (!NT_SUCCESS(Status
))
1970 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
1974 /* Cleanup log update */
1975 Status
= CmiCleanupLogUpdate(RegistryHive
);
1976 if (!NT_SUCCESS(Status
))
1978 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1982 /* Increment hive update counter */
1983 RegistryHive
->UpdateCounter
++;
1985 /* Clear dirty bitmap and dirty flag */
1986 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
1987 RegistryHive
->HiveDirty
= FALSE
;
1989 DPRINT("CmiFlushRegistryHive() done\n");
1991 return(STATUS_SUCCESS
);
1996 CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject
)
2003 VERIFY_KEY_OBJECT(KeyObject
);
2005 KeyCell
= KeyObject
->KeyCell
;
2006 VERIFY_KEY_CELL(KeyCell
);
2008 SubKeyCount
= (KeyCell
== NULL
) ? 0 : KeyCell
->NumberOfSubKeys
;
2010 /* Search for volatile or 'foreign' keys */
2011 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2013 CurKey
= KeyObject
->SubKeys
[i
];
2014 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2015 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2026 CmiGetMaxNameLength(PKEY_OBJECT KeyObject
)
2028 PHASH_TABLE_CELL HashBlock
;
2030 PKEY_CELL CurSubKeyCell
;
2036 VERIFY_KEY_OBJECT(KeyObject
);
2038 KeyCell
= KeyObject
->KeyCell
;
2039 VERIFY_KEY_CELL(KeyCell
);
2042 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2043 KeyCell
->HashTableOffset
,
2045 if (HashBlock
== NULL
)
2047 DPRINT("CmiGetBlock() failed\n");
2051 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2053 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2055 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2056 HashBlock
->Table
[i
].KeyOffset
,
2058 if (CurSubKeyCell
== NULL
)
2060 DPRINT("CmiGetBlock() failed\n");
2064 NameSize
= CurSubKeyCell
->NameSize
;
2065 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2067 NameSize
*= sizeof(WCHAR
);
2070 if (NameSize
> MaxName
)
2078 DPRINT ("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2079 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2081 CurKey
= KeyObject
->SubKeys
[i
];
2082 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2083 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2085 CurSubKeyCell
= CurKey
->KeyCell
;
2086 if (CurSubKeyCell
== NULL
)
2088 DPRINT("CmiGetBlock() failed\n");
2092 if ((CurSubKeyCell
->Flags
& REG_KEY_ROOT_CELL
) == REG_KEY_ROOT_CELL
)
2094 /* Use name of the key object */
2095 NameSize
= CurKey
->Name
.Length
;
2099 /* Use name of the key cell */
2100 NameSize
= CurSubKeyCell
->NameSize
;
2101 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2103 NameSize
*= sizeof(WCHAR
);
2106 DPRINT ("NameSize %lu\n", NameSize
);
2108 if (NameSize
> MaxName
)
2115 DPRINT ("MaxName %lu\n", MaxName
);
2122 CmiGetMaxClassLength(PKEY_OBJECT KeyObject
)
2124 PHASH_TABLE_CELL HashBlock
;
2126 PKEY_CELL CurSubKeyCell
;
2131 VERIFY_KEY_OBJECT(KeyObject
);
2133 KeyCell
= KeyObject
->KeyCell
;
2134 VERIFY_KEY_CELL(KeyCell
);
2137 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2138 KeyCell
->HashTableOffset
,
2140 if (HashBlock
== NULL
)
2142 DPRINT("CmiGetBlock() failed\n");
2146 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2148 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2150 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2151 HashBlock
->Table
[i
].KeyOffset
,
2153 if (CurSubKeyCell
== NULL
)
2155 DPRINT("CmiGetBlock() failed\n");
2159 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2161 MaxClass
= CurSubKeyCell
->ClassSize
;
2167 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2168 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2170 CurKey
= KeyObject
->SubKeys
[i
];
2171 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2172 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2174 CurSubKeyCell
= CurKey
->KeyCell
;
2175 if (CurSubKeyCell
== NULL
)
2177 DPRINT("CmiGetBlock() failed\n");
2181 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2183 MaxClass
= CurSubKeyCell
->ClassSize
;
2193 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
2196 PVALUE_LIST_CELL ValueListCell
;
2197 PVALUE_CELL CurValueCell
;
2202 VERIFY_KEY_CELL(KeyCell
);
2205 ValueListCell
= CmiGetCell (RegistryHive
,
2206 KeyCell
->ValueListOffset
,
2208 if (ValueListCell
== NULL
)
2210 DPRINT("CmiGetBlock() failed\n");
2214 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2216 CurValueCell
= CmiGetCell (RegistryHive
,
2217 ValueListCell
->ValueOffset
[i
],
2219 if (CurValueCell
== NULL
)
2221 DPRINT("CmiGetBlock() failed\n");
2224 if (CurValueCell
!= NULL
)
2226 Size
= CurValueCell
->NameSize
;
2227 if (CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
2229 Size
*= sizeof(WCHAR
);
2231 if (MaxValueName
< Size
)
2233 MaxValueName
= Size
;
2238 return MaxValueName
;
2243 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
2246 PVALUE_LIST_CELL ValueListCell
;
2247 PVALUE_CELL CurValueCell
;
2251 VERIFY_KEY_CELL(KeyCell
);
2254 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2255 if (ValueListCell
== NULL
)
2260 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2262 CurValueCell
= CmiGetCell (RegistryHive
,
2263 ValueListCell
->ValueOffset
[i
],NULL
);
2264 if ((CurValueCell
!= NULL
) &&
2265 (MaxValueData
< (LONG
)(CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2267 MaxValueData
= CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2271 return MaxValueData
;
2276 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
2277 IN PKEY_CELL KeyCell
,
2278 OUT PKEY_CELL
*SubKeyCell
,
2279 OUT BLOCK_OFFSET
*BlockOffset
,
2280 IN PUNICODE_STRING KeyName
,
2281 IN ACCESS_MASK DesiredAccess
,
2282 IN ULONG Attributes
)
2284 PHASH_TABLE_CELL HashBlock
;
2285 PKEY_CELL CurSubKeyCell
;
2288 VERIFY_KEY_CELL(KeyCell
);
2290 DPRINT("Scanning for sub key %wZ\n", KeyName
);
2292 ASSERT(RegistryHive
);
2296 /* The key does not have any subkeys */
2297 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
2299 return STATUS_SUCCESS
;
2302 /* Get hash table */
2303 HashBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2304 if (HashBlock
== NULL
)
2306 DPRINT("CmiGetBlock() failed\n");
2307 return STATUS_UNSUCCESSFUL
;
2310 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
) && (i
< HashBlock
->HashTableSize
); i
++)
2312 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2314 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2315 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1 &&
2316 (HashBlock
->Table
[i
].HashValue
== 0 ||
2317 CmiCompareHashI(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2319 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2320 HashBlock
->Table
[i
].KeyOffset
,
2322 if (CurSubKeyCell
== NULL
)
2324 DPRINT("CmiGetBlock() failed\n");
2325 return STATUS_UNSUCCESSFUL
;
2328 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2330 *SubKeyCell
= CurSubKeyCell
;
2331 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2338 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2339 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2340 (HashBlock
->Table
[i
].HashValue
== 0 ||
2341 CmiCompareHash(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2343 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2344 HashBlock
->Table
[i
].KeyOffset
,
2346 if (CurSubKeyCell
== NULL
)
2348 DPRINT("CmiGetBlock() failed\n");
2349 return STATUS_UNSUCCESSFUL
;
2352 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2354 *SubKeyCell
= CurSubKeyCell
;
2355 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2362 return STATUS_SUCCESS
;
2367 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2368 PKEY_OBJECT ParentKey
,
2370 PUNICODE_STRING SubKeyName
,
2372 PUNICODE_STRING Class
,
2373 ULONG CreateOptions
)
2375 PHASH_TABLE_CELL HashBlock
;
2376 BLOCK_OFFSET NKBOffset
;
2377 PKEY_CELL NewKeyCell
;
2379 PKEY_CELL ParentKeyCell
;
2380 PDATA_CELL ClassCell
;
2387 ParentKeyCell
= ParentKey
->KeyCell
;
2389 VERIFY_KEY_CELL(ParentKeyCell
);
2391 /* Skip leading backslash */
2392 if (SubKeyName
->Buffer
[0] == L
'\\')
2394 NamePtr
= &SubKeyName
->Buffer
[1];
2395 NameSize
= SubKeyName
->Length
- sizeof(WCHAR
);
2399 NamePtr
= SubKeyName
->Buffer
;
2400 NameSize
= SubKeyName
->Length
;
2403 /* Check whether key name can be packed */
2405 for (i
= 0; i
< NameSize
/ sizeof(WCHAR
); i
++)
2407 if (NamePtr
[i
] & 0xFF00)
2414 /* Adjust name size */
2417 NameSize
= NameSize
/ sizeof(WCHAR
);
2420 DPRINT("Key %S Length %lu %s\n", NamePtr
, NameSize
, (Packable
)?"True":"False");
2422 Status
= STATUS_SUCCESS
;
2424 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2425 Status
= CmiAllocateCell (RegistryHive
,
2427 (PVOID
) &NewKeyCell
,
2429 if (NewKeyCell
== NULL
)
2431 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2435 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2436 NewKeyCell
->Flags
= 0;
2437 KeQuerySystemTime(&NewKeyCell
->LastWriteTime
);
2438 NewKeyCell
->ParentKeyOffset
= -1;
2439 NewKeyCell
->NumberOfSubKeys
= 0;
2440 NewKeyCell
->HashTableOffset
= -1;
2441 NewKeyCell
->NumberOfValues
= 0;
2442 NewKeyCell
->ValueListOffset
= -1;
2443 NewKeyCell
->SecurityKeyOffset
= -1;
2444 NewKeyCell
->ClassNameOffset
= -1;
2446 /* Pack the key name */
2447 NewKeyCell
->NameSize
= NameSize
;
2450 NewKeyCell
->Flags
|= REG_KEY_NAME_PACKED
;
2451 for (i
= 0; i
< NameSize
; i
++)
2453 NewKeyCell
->Name
[i
] = (CHAR
)(NamePtr
[i
] & 0x00FF);
2458 RtlCopyMemory(NewKeyCell
->Name
,
2463 VERIFY_KEY_CELL(NewKeyCell
);
2467 NewKeyCell
->ClassSize
= Class
->Length
;
2468 Status
= CmiAllocateCell (RegistryHive
,
2469 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
2471 &NewKeyCell
->ClassNameOffset
);
2472 RtlCopyMemory (ClassCell
->Data
,
2478 if (!NT_SUCCESS(Status
))
2483 SubKey
->KeyCell
= NewKeyCell
;
2484 SubKey
->KeyCellOffset
= NKBOffset
;
2486 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2487 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(ParentKey
->RegistryHive
)))
2492 if (ParentKeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2494 Status
= CmiAllocateHashTableCell (RegistryHive
,
2496 &ParentKeyCell
->HashTableOffset
,
2497 REG_INIT_HASH_TABLE_SIZE
);
2498 if (!NT_SUCCESS(Status
))
2505 HashBlock
= CmiGetCell (RegistryHive
,
2506 ParentKeyCell
->HashTableOffset
,
2508 if (HashBlock
== NULL
)
2510 DPRINT("CmiGetCell() failed\n");
2511 return STATUS_UNSUCCESSFUL
;
2514 if (((ParentKeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2516 PHASH_TABLE_CELL NewHashBlock
;
2517 BLOCK_OFFSET HTOffset
;
2519 /* Reallocate the hash table cell */
2520 Status
= CmiAllocateHashTableCell (RegistryHive
,
2523 HashBlock
->HashTableSize
+
2524 REG_EXTEND_HASH_TABLE_SIZE
);
2525 if (!NT_SUCCESS(Status
))
2530 RtlZeroMemory(&NewHashBlock
->Table
[0],
2531 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2532 RtlCopyMemory(&NewHashBlock
->Table
[0],
2533 &HashBlock
->Table
[0],
2534 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2535 CmiDestroyCell (RegistryHive
,
2537 ParentKeyCell
->HashTableOffset
);
2538 ParentKeyCell
->HashTableOffset
= HTOffset
;
2539 HashBlock
= NewHashBlock
;
2543 Status
= CmiAddKeyToHashTable(RegistryHive
,
2545 ParentKeyCell
->HashTableOffset
,
2548 if (NT_SUCCESS(Status
))
2550 ParentKeyCell
->NumberOfSubKeys
++;
2553 KeQuerySystemTime (&ParentKeyCell
->LastWriteTime
);
2554 CmiMarkBlockDirty (RegistryHive
, ParentKey
->KeyCellOffset
);
2561 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2562 PKEY_OBJECT ParentKey
,
2565 PHASH_TABLE_CELL HashBlock
;
2566 PVALUE_LIST_CELL ValueList
;
2567 PVALUE_CELL ValueCell
;
2568 PDATA_CELL DataCell
;
2571 DPRINT("CmiRemoveSubKey() called\n");
2573 /* Remove all values */
2574 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2576 /* Get pointer to the value list cell */
2577 ValueList
= CmiGetCell (RegistryHive
,
2578 SubKey
->KeyCell
->ValueListOffset
,
2580 if (ValueList
== NULL
)
2582 DPRINT("CmiGetCell() failed\n");
2583 return STATUS_UNSUCCESSFUL
;
2586 /* Enumerate all values */
2587 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2589 /* Get pointer to value cell */
2590 ValueCell
= CmiGetCell(RegistryHive
,
2591 ValueList
->ValueOffset
[i
],
2593 if (ValueCell
== NULL
)
2595 DPRINT("CmiGetCell() failed\n");
2596 return STATUS_UNSUCCESSFUL
;
2599 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
)
2600 && ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
2602 DataCell
= CmiGetCell (RegistryHive
,
2603 ValueCell
->DataOffset
,
2605 if (DataCell
== NULL
)
2607 DPRINT("CmiGetCell() failed\n");
2608 return STATUS_UNSUCCESSFUL
;
2611 if (DataCell
!= NULL
)
2613 /* Destroy data cell */
2614 CmiDestroyCell (RegistryHive
,
2616 ValueCell
->DataOffset
);
2620 /* Destroy value cell */
2621 CmiDestroyCell (RegistryHive
,
2623 ValueList
->ValueOffset
[i
]);
2626 /* Destroy value list cell */
2627 CmiDestroyCell (RegistryHive
,
2629 SubKey
->KeyCell
->ValueListOffset
);
2631 SubKey
->KeyCell
->NumberOfValues
= 0;
2632 SubKey
->KeyCell
->ValueListOffset
= (BLOCK_OFFSET
)-1;
2634 CmiMarkBlockDirty(RegistryHive
,
2635 SubKey
->KeyCellOffset
);
2638 /* Remove the key from the parent key's hash block */
2639 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2641 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2642 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2643 ParentKey
->KeyCell
->HashTableOffset
,
2645 if (HashBlock
== NULL
)
2647 DPRINT("CmiGetCell() failed\n");
2648 return STATUS_UNSUCCESSFUL
;
2650 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2651 if (HashBlock
!= NULL
)
2653 CmiRemoveKeyFromHashTable(ParentKey
->RegistryHive
,
2655 SubKey
->KeyCellOffset
);
2656 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2657 ParentKey
->KeyCell
->HashTableOffset
);
2661 /* Remove the key's hash block */
2662 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2664 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
);
2665 HashBlock
= CmiGetCell (RegistryHive
,
2666 SubKey
->KeyCell
->HashTableOffset
,
2668 if (HashBlock
== NULL
)
2670 DPRINT("CmiGetCell() failed\n");
2671 return STATUS_UNSUCCESSFUL
;
2673 DPRINT("SubKey HashBlock %p\n", HashBlock
);
2674 if (HashBlock
!= NULL
)
2676 CmiDestroyCell (RegistryHive
,
2678 SubKey
->KeyCell
->HashTableOffset
);
2679 SubKey
->KeyCell
->HashTableOffset
= -1;
2683 /* Decrement the number of the parent key's sub keys */
2684 if (ParentKey
!= NULL
)
2686 DPRINT("ParentKey %p\n", ParentKey
);
2687 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2689 /* Remove the parent key's hash table */
2690 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2692 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2693 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2694 ParentKey
->KeyCell
->HashTableOffset
,
2696 if (HashBlock
== NULL
)
2698 DPRINT("CmiGetCell() failed\n");
2699 return STATUS_UNSUCCESSFUL
;
2701 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2702 if (HashBlock
!= NULL
)
2704 CmiDestroyCell (ParentKey
->RegistryHive
,
2706 ParentKey
->KeyCell
->HashTableOffset
);
2707 ParentKey
->KeyCell
->HashTableOffset
= (BLOCK_OFFSET
)-1;
2711 KeQuerySystemTime(&ParentKey
->KeyCell
->LastWriteTime
);
2712 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2713 ParentKey
->KeyCellOffset
);
2716 /* Destroy key cell */
2717 CmiDestroyCell (RegistryHive
,
2719 SubKey
->KeyCellOffset
);
2720 SubKey
->KeyCell
= NULL
;
2721 SubKey
->KeyCellOffset
= (BLOCK_OFFSET
)-1;
2723 DPRINT("CmiRemoveSubKey() done\n");
2725 return STATUS_SUCCESS
;
2730 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2731 IN PKEY_CELL KeyCell
,
2732 IN PUNICODE_STRING ValueName
,
2733 OUT PVALUE_CELL
*ValueCell
,
2734 OUT BLOCK_OFFSET
*ValueCellOffset
)
2736 PVALUE_LIST_CELL ValueListCell
;
2737 PVALUE_CELL CurValueCell
;
2741 if (ValueCellOffset
!= NULL
)
2742 *ValueCellOffset
= (BLOCK_OFFSET
)-1;
2744 /* The key does not have any values */
2745 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2747 return STATUS_OBJECT_NAME_NOT_FOUND
;
2750 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2751 if (ValueListCell
== NULL
)
2753 DPRINT("ValueListCell is NULL\n");
2754 return STATUS_UNSUCCESSFUL
;
2757 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2759 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2761 CurValueCell
= CmiGetCell (RegistryHive
,
2762 ValueListCell
->ValueOffset
[i
],
2764 if (CurValueCell
== NULL
)
2766 DPRINT("CmiGetBlock() failed\n");
2767 return STATUS_UNSUCCESSFUL
;
2770 if ((CurValueCell
!= NULL
) &&
2771 CmiComparePackedNames(ValueName
,
2773 CurValueCell
->NameSize
,
2774 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2776 *ValueCell
= CurValueCell
;
2777 if (ValueCellOffset
!= NULL
)
2778 *ValueCellOffset
= ValueListCell
->ValueOffset
[i
];
2779 //DPRINT("Found value %s\n", ValueName);
2780 return STATUS_SUCCESS
;
2784 return STATUS_OBJECT_NAME_NOT_FOUND
;
2789 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2790 IN PKEY_CELL KeyCell
,
2792 OUT PVALUE_CELL
*ValueCell
)
2794 PVALUE_LIST_CELL ValueListCell
;
2795 PVALUE_CELL CurValueCell
;
2799 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2801 return STATUS_NO_MORE_ENTRIES
;
2804 if (Index
>= KeyCell
->NumberOfValues
)
2806 return STATUS_NO_MORE_ENTRIES
;
2810 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2811 if (ValueListCell
== NULL
)
2813 DPRINT("CmiGetBlock() failed\n");
2814 return STATUS_UNSUCCESSFUL
;
2817 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2820 CurValueCell
= CmiGetCell (RegistryHive
,
2821 ValueListCell
->ValueOffset
[Index
],
2823 if (CurValueCell
== NULL
)
2825 DPRINT("CmiGetBlock() failed\n");
2826 return STATUS_UNSUCCESSFUL
;
2829 *ValueCell
= CurValueCell
;
2831 return STATUS_SUCCESS
;
2836 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2837 IN PKEY_CELL KeyCell
,
2838 IN BLOCK_OFFSET KeyCellOffset
,
2839 IN PUNICODE_STRING ValueName
,
2840 OUT PVALUE_CELL
*pValueCell
,
2841 OUT BLOCK_OFFSET
*pValueCellOffset
)
2843 PVALUE_LIST_CELL NewValueListCell
;
2844 PVALUE_LIST_CELL ValueListCell
;
2845 PVALUE_CELL NewValueCell
;
2846 BLOCK_OFFSET NewValueListCellOffset
;
2847 BLOCK_OFFSET ValueListCellOffset
;
2848 BLOCK_OFFSET NewValueCellOffset
;
2852 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG
)KeyCell
->ValueListOffset
);
2854 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2855 if (ValueListCell
== NULL
)
2857 CellSize
= sizeof(VALUE_LIST_CELL
) +
2858 (3 * sizeof(BLOCK_OFFSET
));
2859 Status
= CmiAllocateCell (RegistryHive
,
2861 (PVOID
) &ValueListCell
,
2862 &ValueListCellOffset
);
2863 if (!NT_SUCCESS(Status
))
2868 KeyCell
->ValueListOffset
= ValueListCellOffset
;
2869 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2870 CmiMarkBlockDirty(RegistryHive
, ValueListCellOffset
);
2872 else if (KeyCell
->NumberOfValues
>=
2873 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
)))
2876 CellSize
= sizeof(VALUE_LIST_CELL
) +
2877 ((KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) * sizeof(BLOCK_OFFSET
));
2879 CellSize
= 2 * (ULONG
)ABS_VALUE(ValueListCell
->CellSize
);
2880 Status
= CmiAllocateCell (RegistryHive
,
2882 (PVOID
) &NewValueListCell
,
2883 &NewValueListCellOffset
);
2884 if (!NT_SUCCESS(Status
))
2889 RtlCopyMemory(&NewValueListCell
->ValueOffset
[0],
2890 &ValueListCell
->ValueOffset
[0],
2891 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2892 CmiDestroyCell (RegistryHive
, ValueListCell
, KeyCell
->ValueListOffset
);
2893 CmiMarkBlockDirty (RegistryHive
, KeyCell
->ValueListOffset
);
2895 KeyCell
->ValueListOffset
= NewValueListCellOffset
;
2896 ValueListCell
= NewValueListCell
;
2897 CmiMarkBlockDirty (RegistryHive
, KeyCellOffset
);
2898 CmiMarkBlockDirty (RegistryHive
, NewValueListCellOffset
);
2901 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2902 KeyCell
->NumberOfValues
,
2903 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2904 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
),
2905 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
));
2907 Status
= CmiAllocateValueCell(RegistryHive
,
2909 &NewValueCellOffset
,
2911 if (!NT_SUCCESS(Status
))
2916 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = NewValueCellOffset
;
2917 KeyCell
->NumberOfValues
++;
2919 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2920 CmiMarkBlockDirty(RegistryHive
, KeyCell
->ValueListOffset
);
2921 CmiMarkBlockDirty(RegistryHive
, NewValueCellOffset
);
2923 *pValueCell
= NewValueCell
;
2924 *pValueCellOffset
= NewValueCellOffset
;
2926 return STATUS_SUCCESS
;
2931 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2932 IN PKEY_CELL KeyCell
,
2933 IN BLOCK_OFFSET KeyCellOffset
,
2934 IN PUNICODE_STRING ValueName
)
2936 PVALUE_LIST_CELL ValueListCell
;
2937 PVALUE_CELL CurValueCell
;
2941 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2942 if (ValueListCell
== NULL
)
2944 DPRINT1("CmiGetBlock() failed\n");
2945 return STATUS_SUCCESS
;
2948 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2950 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2952 CurValueCell
= CmiGetCell (RegistryHive
, ValueListCell
->ValueOffset
[i
], NULL
);
2953 if (CurValueCell
== NULL
)
2955 DPRINT1("CmiGetBlock() failed\n");
2956 return STATUS_UNSUCCESSFUL
;
2959 if (CmiComparePackedNames(ValueName
,
2961 CurValueCell
->NameSize
,
2962 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2964 Status
= CmiDestroyValueCell(RegistryHive
,
2966 ValueListCell
->ValueOffset
[i
]);
2967 if (CurValueCell
== NULL
)
2969 DPRINT1("CmiDestroyValueCell() failed\n");
2973 if (i
< (KeyCell
->NumberOfValues
- 1))
2975 RtlMoveMemory(&ValueListCell
->ValueOffset
[i
],
2976 &ValueListCell
->ValueOffset
[i
+ 1],
2977 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2979 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
- 1] = 0;
2982 KeyCell
->NumberOfValues
--;
2984 if (KeyCell
->NumberOfValues
== 0)
2986 CmiDestroyCell(RegistryHive
,
2988 KeyCell
->ValueListOffset
);
2989 KeyCell
->ValueListOffset
= -1;
2993 CmiMarkBlockDirty(RegistryHive
,
2994 KeyCell
->ValueListOffset
);
2997 CmiMarkBlockDirty(RegistryHive
,
3000 return STATUS_SUCCESS
;
3004 DPRINT("Couldn't find the desired value\n");
3006 return STATUS_OBJECT_NAME_NOT_FOUND
;
3011 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive
,
3012 OUT PHASH_TABLE_CELL
*HashBlock
,
3013 OUT BLOCK_OFFSET
*HBOffset
,
3014 IN ULONG SubKeyCount
)
3016 PHASH_TABLE_CELL NewHashBlock
;
3020 Status
= STATUS_SUCCESS
;
3022 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
3023 (SubKeyCount
* sizeof(HASH_RECORD
));
3024 Status
= CmiAllocateCell (RegistryHive
,
3026 (PVOID
*) &NewHashBlock
,
3029 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
3031 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3035 ASSERT(SubKeyCount
<= 0xffff); /* should really be USHORT_MAX or similar */
3036 NewHashBlock
->Id
= REG_HASH_TABLE_CELL_ID
;
3037 NewHashBlock
->HashTableSize
= (USHORT
)SubKeyCount
;
3038 *HashBlock
= NewHashBlock
;
3046 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
3047 PHASH_TABLE_CELL HashBlock
,
3050 BLOCK_OFFSET KeyOffset
;
3053 if (HashBlock
== NULL
)
3056 if (IsPointerHive(RegistryHive
))
3058 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
3062 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
3063 KeyCell
= CmiGetCell (RegistryHive
, KeyOffset
, NULL
);
3071 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
3072 PHASH_TABLE_CELL HashCell
,
3073 BLOCK_OFFSET HashCellOffset
,
3074 PKEY_CELL NewKeyCell
,
3075 BLOCK_OFFSET NKBOffset
)
3079 for (i
= 0; i
< HashCell
->HashTableSize
; i
++)
3081 if (HashCell
->Table
[i
].KeyOffset
== 0)
3083 HashCell
->Table
[i
].KeyOffset
= NKBOffset
;
3084 HashCell
->Table
[i
].HashValue
= 0;
3085 if (NewKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3087 RtlCopyMemory(&HashCell
->Table
[i
].HashValue
,
3089 min(NewKeyCell
->NameSize
, sizeof(ULONG
)));
3091 CmiMarkBlockDirty(RegistryHive
, HashCellOffset
);
3092 return STATUS_SUCCESS
;
3096 return STATUS_UNSUCCESSFUL
;
3101 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
3102 PHASH_TABLE_CELL HashBlock
,
3103 BLOCK_OFFSET NKBOffset
)
3107 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3109 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
3111 HashBlock
->Table
[i
].KeyOffset
= 0;
3112 HashBlock
->Table
[i
].HashValue
= 0;
3113 return STATUS_SUCCESS
;
3117 return STATUS_UNSUCCESSFUL
;
3122 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
3123 PVALUE_CELL
*ValueCell
,
3124 BLOCK_OFFSET
*VBOffset
,
3125 IN PUNICODE_STRING ValueName
)
3127 PVALUE_CELL NewValueCell
;
3133 Status
= STATUS_SUCCESS
;
3135 NameSize
= CmiGetPackedNameLength(ValueName
,
3138 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
3140 Status
= CmiAllocateCell (RegistryHive
,
3141 sizeof(VALUE_CELL
) + NameSize
,
3142 (PVOID
*) &NewValueCell
,
3144 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
3146 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3150 ASSERT(NameSize
<= 0xffff); /* should really be USHORT_MAX or similar */
3151 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
3152 NewValueCell
->NameSize
= (USHORT
)NameSize
;
3155 /* Pack the value name */
3156 for (i
= 0; i
< NameSize
; i
++)
3157 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
3158 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
3162 /* Copy the value name */
3163 RtlCopyMemory(NewValueCell
->Name
,
3166 NewValueCell
->Flags
= 0;
3168 NewValueCell
->DataType
= 0;
3169 NewValueCell
->DataSize
= 0;
3170 NewValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
3171 *ValueCell
= NewValueCell
;
3179 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
3180 PVALUE_CELL ValueCell
,
3181 BLOCK_OFFSET ValueCellOffset
)
3187 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n",
3188 ValueCell
, ValueCellOffset
);
3190 VERIFY_VALUE_CELL(ValueCell
);
3192 /* Destroy the data cell */
3193 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
)
3194 && ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
3196 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, &Bin
);
3197 if (DataCell
== NULL
)
3199 DPRINT("CmiGetCell() failed\n");
3200 return STATUS_UNSUCCESSFUL
;
3203 Status
= CmiDestroyCell (RegistryHive
, DataCell
, ValueCell
->DataOffset
);
3204 if (!NT_SUCCESS(Status
))
3209 /* Update time of heap */
3210 if (!IsNoFileHive(RegistryHive
))
3211 KeQuerySystemTime(&Bin
->DateModified
);
3214 /* Destroy the value cell */
3215 Status
= CmiDestroyCell (RegistryHive
, ValueCell
, ValueCellOffset
);
3217 /* Update time of heap */
3218 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, ValueCellOffset
, &Bin
))
3220 KeQuerySystemTime(&Bin
->DateModified
);
3228 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
3231 BLOCK_OFFSET
*NewBlockOffset
)
3233 PBLOCK_LIST_ENTRY BlockList
;
3234 PCELL_HEADER tmpBlock
;
3240 DPRINT ("CmiAddBin (BlockCount %lu)\n", BlockCount
);
3242 BinSize
= BlockCount
* REG_BLOCK_SIZE
;
3243 tmpBin
= ExAllocatePool(PagedPool
, BinSize
);
3246 return STATUS_INSUFFICIENT_RESOURCES
;
3248 RtlZeroMemory (tmpBin
,
3251 tmpBin
->HeaderId
= REG_BIN_ID
;
3252 tmpBin
->BinOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
3253 RegistryHive
->FileSize
+= BinSize
;
3254 tmpBin
->BinSize
= BinSize
;
3255 tmpBin
->Unused1
= 0;
3256 KeQuerySystemTime(&tmpBin
->DateModified
);
3257 tmpBin
->Unused2
= 0;
3259 DPRINT (" BinOffset %lx BinSize %lx\n", tmpBin
->BinOffset
,tmpBin
->BinSize
);
3261 /* Allocate new block list */
3262 BlockList
= ExAllocatePool(NonPagedPool
,
3263 sizeof(BLOCK_LIST_ENTRY
) * (RegistryHive
->BlockListSize
+ BlockCount
));
3264 if (BlockList
== NULL
)
3267 return STATUS_INSUFFICIENT_RESOURCES
;
3270 if (RegistryHive
->BlockListSize
> 0)
3272 RtlCopyMemory (BlockList
,
3273 RegistryHive
->BlockList
,
3274 sizeof(BLOCK_LIST_ENTRY
) * RegistryHive
->BlockListSize
);
3275 ExFreePool(RegistryHive
->BlockList
);
3278 RegistryHive
->BlockList
= BlockList
;
3279 for (i
= 0; i
< BlockCount
; i
++)
3281 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Block
=
3282 (PVOID
)((ULONG_PTR
)tmpBin
+ (i
* REG_BLOCK_SIZE
));
3283 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Bin
= tmpBin
;
3285 RegistryHive
->BlockListSize
+= BlockCount
;
3287 /* Initialize a free block in this heap : */
3288 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
3289 tmpBlock
->CellSize
= (BinSize
- REG_HBIN_DATA_OFFSET
);
3291 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3292 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
3294 /* Grow bitmap if necessary */
3295 if (!IsNoFileHive(RegistryHive
) &&
3296 BitmapSize
> RegistryHive
->DirtyBitMap
.SizeOfBitMap
/ 8)
3298 PULONG BitmapBuffer
;
3300 DPRINT("Grow hive bitmap\n");
3302 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
3303 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
3304 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
3306 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
3307 RtlCopyMemory(BitmapBuffer
,
3308 RegistryHive
->DirtyBitMap
.Buffer
,
3309 RegistryHive
->DirtyBitMap
.SizeOfBitMap
/ 8);
3310 ExFreePool(RegistryHive
->BitmapBuffer
);
3311 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
3312 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
3313 RegistryHive
->BitmapBuffer
,
3317 *NewBlock
= (PVOID
) tmpBlock
;
3320 *NewBlockOffset
= tmpBin
->BinOffset
+ REG_HBIN_DATA_OFFSET
;
3322 /* Mark new bin dirty */
3323 CmiMarkBinDirty(RegistryHive
,
3326 return STATUS_SUCCESS
;
3331 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
3334 BLOCK_OFFSET
*CellOffset
)
3336 PCELL_HEADER NewCell
;
3342 /* Round to 16 bytes multiple */
3343 CellSize
= ROUND_UP(CellSize
, 16);
3345 /* Handle volatile hives first */
3346 if (IsPointerHive(RegistryHive
))
3348 NewCell
= ExAllocatePool(NonPagedPool
, CellSize
);
3349 if (NewCell
== NULL
)
3351 return STATUS_INSUFFICIENT_RESOURCES
;
3354 RtlZeroMemory (NewCell
,
3356 NewCell
->CellSize
= -CellSize
;
3359 if (CellOffset
!= NULL
)
3360 *CellOffset
= (BLOCK_OFFSET
) NewCell
;
3364 /* first search in free blocks */
3366 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3368 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
3370 NewCell
= RegistryHive
->FreeList
[i
];
3371 if (CellOffset
!= NULL
)
3372 *CellOffset
= RegistryHive
->FreeListOffset
[i
];
3374 /* Update time of heap */
3375 Temp
= CmiGetCell (RegistryHive
,
3376 RegistryHive
->FreeListOffset
[i
],
3380 DPRINT("CmiGetBlock() failed\n");
3381 return STATUS_UNSUCCESSFUL
;
3384 KeQuerySystemTime(&Bin
->DateModified
);
3385 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
3387 if ((i
+ 1) < RegistryHive
->FreeListSize
)
3389 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
3390 &RegistryHive
->FreeList
[i
+ 1],
3391 sizeof(RegistryHive
->FreeList
[0])
3392 * (RegistryHive
->FreeListSize
- i
- 1));
3393 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
3394 &RegistryHive
->FreeListOffset
[i
+ 1],
3395 sizeof(RegistryHive
->FreeListOffset
[0])
3396 * (RegistryHive
->FreeListSize
- i
- 1));
3398 RegistryHive
->FreeListSize
--;
3403 /* Need to extend hive file : */
3404 if (NewCell
== NULL
)
3407 Status
= CmiAddBin(RegistryHive
,
3408 ((CellSize
+ sizeof(HBIN
) - 1) / REG_BLOCK_SIZE
) + 1,
3411 if (!NT_SUCCESS(Status
))
3417 /* Split the block in two parts */
3418 if (NewCell
->CellSize
> CellSize
)
3420 NewCell
= (PCELL_HEADER
) ((ULONG_PTR
) NewCell
+ CellSize
);
3421 NewCell
->CellSize
= ((PCELL_HEADER
) (*Cell
))->CellSize
- CellSize
;
3422 CmiAddFree(RegistryHive
,
3424 *CellOffset
+ CellSize
,
3426 CmiMarkBlockDirty(RegistryHive
,
3427 *CellOffset
+ CellSize
);
3429 else if (NewCell
->CellSize
< CellSize
)
3431 return STATUS_UNSUCCESSFUL
;
3434 RtlZeroMemory(*Cell
,
3436 ((PCELL_HEADER
) (*Cell
))->CellSize
= -CellSize
;
3439 return STATUS_SUCCESS
;
3444 CmiDestroyCell (PREGISTRY_HIVE RegistryHive
,
3446 BLOCK_OFFSET CellOffset
)
3451 Status
= STATUS_SUCCESS
;
3453 if (IsPointerHive(RegistryHive
))
3459 PCELL_HEADER pFree
= Cell
;
3461 if (pFree
->CellSize
< 0)
3462 pFree
->CellSize
= -pFree
->CellSize
;
3464 /* Clear block (except the block size) */
3465 RtlZeroMemory(((char*)pFree
) + sizeof(ULONG
),
3466 pFree
->CellSize
- sizeof(ULONG
));
3468 /* Add block to the list of free blocks */
3469 CmiAddFree(RegistryHive
, Cell
, CellOffset
, TRUE
);
3471 /* Update time of heap */
3472 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, CellOffset
,&pBin
))
3473 KeQuerySystemTime(&pBin
->DateModified
);
3475 CmiMarkBlockDirty(RegistryHive
, CellOffset
);
3483 CmiGetCell (PREGISTRY_HIVE RegistryHive
,
3484 BLOCK_OFFSET CellOffset
,
3494 if (CellOffset
== (BLOCK_OFFSET
)-1)
3499 if (IsPointerHive (RegistryHive
))
3501 return (PVOID
)CellOffset
;
3504 if (CellOffset
> RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
)
3506 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3507 CellOffset
, RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
);
3511 pBin
= RegistryHive
->BlockList
[CellOffset
/ REG_BLOCK_SIZE
].Bin
;
3522 return((PVOID
)((ULONG_PTR
)pBin
+ (CellOffset
- pBin
->BinOffset
)));
3527 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3528 PCELL_HEADER FreeBlock
,
3529 BLOCK_OFFSET FreeOffset
)
3531 BLOCK_OFFSET BlockOffset
;
3532 BLOCK_OFFSET BinOffset
;
3538 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3539 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3541 CmiGetCell (RegistryHive
,
3544 DPRINT("Bin %p\n", Bin
);
3548 BinOffset
= Bin
->BinOffset
;
3549 BinSize
= Bin
->BinSize
;
3550 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3552 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3554 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3555 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3556 if (BlockOffset
> BinOffset
&&
3557 BlockOffset
< BinOffset
+ BinSize
)
3559 DPRINT("Free block: Offset %lx Size %lx\n",
3560 BlockOffset
, BlockSize
);
3562 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3563 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3564 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3566 DPRINT("Merge current block with previous and next block\n");
3568 RegistryHive
->FreeList
[i
]->CellSize
+=
3569 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3571 FreeBlock
->CellSize
= 0;
3572 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3575 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3577 RtlMoveMemory(&RegistryHive
->FreeList
[i
+ 1],
3578 &RegistryHive
->FreeList
[i
+ 2],
3579 sizeof(RegistryHive
->FreeList
[0])
3580 * (RegistryHive
->FreeListSize
- i
- 2));
3581 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3582 &RegistryHive
->FreeListOffset
[i
+ 2],
3583 sizeof(RegistryHive
->FreeListOffset
[0])
3584 * (RegistryHive
->FreeListSize
- i
- 2));
3586 RegistryHive
->FreeListSize
--;
3588 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3592 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3594 DPRINT("Merge current block with previous block\n");
3596 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3597 FreeBlock
->CellSize
= 0;
3599 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3603 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3605 DPRINT("Merge current block with next block\n");
3607 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3608 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3609 RegistryHive
->FreeList
[i
] = FreeBlock
;
3610 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3612 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3624 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3625 PCELL_HEADER FreeBlock
,
3626 BLOCK_OFFSET FreeOffset
,
3627 BOOLEAN MergeFreeBlocks
)
3629 PCELL_HEADER
*tmpList
;
3630 BLOCK_OFFSET
*tmpListOffset
;
3635 ASSERT(RegistryHive
);
3638 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3639 FreeBlock
, FreeOffset
);
3641 /* Merge free blocks */
3642 if (MergeFreeBlocks
== TRUE
)
3644 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3645 return(STATUS_SUCCESS
);
3648 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3650 tmpList
= ExAllocatePool(PagedPool
,
3651 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3652 if (tmpList
== NULL
)
3653 return STATUS_INSUFFICIENT_RESOURCES
;
3655 tmpListOffset
= ExAllocatePool(PagedPool
,
3656 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3658 if (tmpListOffset
== NULL
)
3660 ExFreePool(tmpList
);
3661 return STATUS_INSUFFICIENT_RESOURCES
;
3664 if (RegistryHive
->FreeListMax
)
3666 RtlMoveMemory(tmpList
,
3667 RegistryHive
->FreeList
,
3668 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3669 RtlMoveMemory(tmpListOffset
,
3670 RegistryHive
->FreeListOffset
,
3671 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3672 ExFreePool(RegistryHive
->FreeList
);
3673 ExFreePool(RegistryHive
->FreeListOffset
);
3675 RegistryHive
->FreeList
= tmpList
;
3676 RegistryHive
->FreeListOffset
= tmpListOffset
;
3677 RegistryHive
->FreeListMax
+= 32;
3680 /* Add new offset to free list, maintaining list in ascending order */
3681 if ((RegistryHive
->FreeListSize
== 0)
3682 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3684 /* Add to end of list */
3685 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3686 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3688 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3690 /* Add to begin of list */
3691 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3692 &RegistryHive
->FreeList
[0],
3693 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3694 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3695 &RegistryHive
->FreeListOffset
[0],
3696 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3697 RegistryHive
->FreeList
[0] = FreeBlock
;
3698 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3699 RegistryHive
->FreeListSize
++;
3703 /* Search where to insert */
3705 maxInd
= RegistryHive
->FreeListSize
- 1;
3706 while ((maxInd
- minInd
) > 1)
3708 medInd
= (minInd
+ maxInd
) / 2;
3709 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3715 /* Insert before maxInd */
3716 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3717 &RegistryHive
->FreeList
[maxInd
],
3718 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3719 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3720 &RegistryHive
->FreeListOffset
[maxInd
],
3721 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3722 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3723 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3724 RegistryHive
->FreeListSize
++;
3727 return STATUS_SUCCESS
;
3732 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3733 BLOCK_OFFSET BlockOffset
)
3740 if (IsNoFileHive(RegistryHive
))
3743 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3745 BlockNumber
= (ULONG
)BlockOffset
/ REG_BLOCK_SIZE
;
3747 Cell
= CmiGetCell (RegistryHive
,
3751 CellSize
= Cell
->CellSize
;
3753 CellSize
= -CellSize
;
3755 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, REG_BLOCK_SIZE
) -
3756 ROUND_DOWN(BlockOffset
, REG_BLOCK_SIZE
)) / REG_BLOCK_SIZE
;
3758 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3761 (Cell
->CellSize
< 0) ? "used" : "free",
3764 RegistryHive
->HiveDirty
= TRUE
;
3765 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3772 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3773 BLOCK_OFFSET BinOffset
)
3779 if (IsNoFileHive(RegistryHive
))
3782 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3784 BlockNumber
= (ULONG
)BinOffset
/ REG_BLOCK_SIZE
;
3786 Bin
= RegistryHive
->BlockList
[BlockNumber
].Bin
;
3788 BlockCount
= Bin
->BinSize
/ REG_BLOCK_SIZE
;
3790 DPRINT(" BlockNumber %lu BinSize %lu BlockCount %lu\n",
3795 RegistryHive
->HiveDirty
= TRUE
;
3796 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3803 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3804 OUT PBOOLEAN Packable
)
3808 if (Packable
!= NULL
)
3811 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3813 if (Name
->Buffer
[i
] & 0xFF00)
3815 if (Packable
!= NULL
)
3817 return Name
->Length
;
3821 return (Name
->Length
/ sizeof(WCHAR
));
3826 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3827 IN PUCHAR NameBuffer
,
3828 IN USHORT NameBufferSize
,
3829 IN BOOLEAN NamePacked
)
3834 if (NamePacked
== TRUE
)
3836 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3839 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3841 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3847 if (Name
->Length
!= NameBufferSize
)
3850 UNameBuffer
= (PWCHAR
)NameBuffer
;
3852 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3854 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3864 CmiCopyPackedName(PWCHAR NameBuffer
,
3865 PUCHAR PackedNameBuffer
,
3866 ULONG PackedNameSize
)
3870 for (i
= 0; i
< PackedNameSize
; i
++)
3871 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];
3876 CmiCompareHash(PUNICODE_STRING KeyName
,
3881 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3882 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3883 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3884 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3886 return (strncmp(Buffer
, HashString
, 4) == 0);
3891 CmiCompareHashI(PUNICODE_STRING KeyName
,
3896 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3897 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3898 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3899 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3901 return (_strnicmp(Buffer
, HashString
, 4) == 0);
3906 CmiCompareKeyNames(PUNICODE_STRING KeyName
,
3912 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3914 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3916 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3919 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3921 if (KeyName
->Buffer
[i
] != (WCHAR
)KeyCell
->Name
[i
])
3927 if (KeyName
->Length
!= KeyCell
->NameSize
)
3930 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3931 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3933 if (KeyName
->Buffer
[i
] != UnicodeName
[i
])
3943 CmiCompareKeyNamesI(PUNICODE_STRING KeyName
,
3949 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3951 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3953 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3956 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3958 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3959 RtlUpcaseUnicodeChar((WCHAR
)KeyCell
->Name
[i
]))
3965 if (KeyName
->Length
!= KeyCell
->NameSize
)
3968 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3969 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3971 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3972 RtlUpcaseUnicodeChar(UnicodeName
[i
]))
3982 CmiCopyKey (PREGISTRY_HIVE DstHive
,
3983 PKEY_CELL DstKeyCell
,
3984 PREGISTRY_HIVE SrcHive
,
3985 PKEY_CELL SrcKeyCell
)
3987 PKEY_CELL NewKeyCell
;
3988 ULONG NewKeyCellSize
;
3989 BLOCK_OFFSET NewKeyCellOffset
;
3990 PHASH_TABLE_CELL NewHashTableCell
;
3991 ULONG NewHashTableSize
;
3992 BLOCK_OFFSET NewHashTableOffset
;
3996 DPRINT ("CmiCopyKey() called\n");
3998 if (DstKeyCell
== NULL
)
4000 /* Allocate and copy key cell */
4001 NewKeyCellSize
= sizeof(KEY_CELL
) + SrcKeyCell
->NameSize
;
4002 Status
= CmiAllocateCell (DstHive
,
4004 (PVOID
) &NewKeyCell
,
4006 if (!NT_SUCCESS(Status
))
4008 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4011 if (NewKeyCell
== NULL
)
4013 DPRINT1 ("Failed to allocate a key cell\n");
4014 return STATUS_INSUFFICIENT_RESOURCES
;
4017 RtlCopyMemory (NewKeyCell
,
4021 DstHive
->HiveHeader
->RootKeyOffset
= NewKeyCellOffset
;
4023 /* Copy class name */
4024 if (SrcKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4026 PDATA_CELL SrcClassNameCell
;
4027 PDATA_CELL NewClassNameCell
;
4028 BLOCK_OFFSET NewClassNameOffset
;
4030 SrcClassNameCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ClassNameOffset
, NULL
),
4032 NewKeyCell
->ClassSize
= SrcKeyCell
->ClassSize
;
4033 Status
= CmiAllocateCell (DstHive
,
4034 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
4035 (PVOID
)&NewClassNameCell
,
4036 &NewClassNameOffset
);
4037 if (!NT_SUCCESS(Status
))
4039 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4043 RtlCopyMemory (NewClassNameCell
,
4045 NewKeyCell
->ClassSize
);
4046 NewKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4051 NewKeyCell
= DstKeyCell
;
4054 /* Allocate hash table */
4055 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4057 NewHashTableSize
= ROUND_UP(SrcKeyCell
->NumberOfSubKeys
+ 1, 4) - 1;
4058 Status
= CmiAllocateHashTableCell (DstHive
,
4060 &NewHashTableOffset
,
4062 if (!NT_SUCCESS(Status
))
4064 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status
);
4067 NewKeyCell
->HashTableOffset
= NewHashTableOffset
;
4071 NewHashTableCell
= NULL
;
4074 /* Allocate and copy value list and values */
4075 if (SrcKeyCell
->NumberOfValues
!= 0)
4077 PVALUE_LIST_CELL NewValueListCell
;
4078 PVALUE_LIST_CELL SrcValueListCell
;
4079 PVALUE_CELL NewValueCell
;
4080 PVALUE_CELL SrcValueCell
;
4081 PDATA_CELL SrcValueDataCell
;
4082 PDATA_CELL NewValueDataCell
;
4083 BLOCK_OFFSET ValueCellOffset
;
4084 BLOCK_OFFSET ValueDataCellOffset
;
4085 ULONG NewValueListCellSize
;
4086 ULONG NewValueCellSize
;
4089 NewValueListCellSize
=
4090 ROUND_UP(SrcKeyCell
->NumberOfValues
, 4) * sizeof(BLOCK_OFFSET
);
4091 Status
= CmiAllocateCell (DstHive
,
4092 NewValueListCellSize
,
4093 (PVOID
)&NewValueListCell
,
4094 &NewKeyCell
->ValueListOffset
);
4095 if (!NT_SUCCESS(Status
))
4097 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4101 RtlZeroMemory (NewValueListCell
,
4102 NewValueListCellSize
);
4105 SrcValueListCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ValueListOffset
, NULL
);
4106 for (i
= 0; i
< SrcKeyCell
->NumberOfValues
; i
++)
4108 /* Copy value cell */
4109 SrcValueCell
= CmiGetCell (SrcHive
, SrcValueListCell
->ValueOffset
[i
], NULL
);
4111 NewValueCellSize
= sizeof(VALUE_CELL
) + SrcValueCell
->NameSize
;
4112 Status
= CmiAllocateCell (DstHive
,
4114 (PVOID
*) &NewValueCell
,
4116 if (!NT_SUCCESS(Status
))
4118 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4122 NewValueListCell
->ValueOffset
[i
] = ValueCellOffset
;
4123 RtlCopyMemory (NewValueCell
,
4127 /* Copy value data cell */
4128 if (SrcValueCell
->DataSize
> (LONG
) sizeof(PVOID
))
4130 SrcValueDataCell
= CmiGetCell (SrcHive
, SrcValueCell
->DataOffset
, NULL
);
4132 Status
= CmiAllocateCell (DstHive
,
4133 sizeof(CELL_HEADER
) + SrcValueCell
->DataSize
,
4134 (PVOID
*) &NewValueDataCell
,
4135 &ValueDataCellOffset
);
4136 if (!NT_SUCCESS(Status
))
4138 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4141 RtlCopyMemory (NewValueDataCell
,
4143 SrcValueCell
->DataSize
);
4144 NewValueCell
->DataOffset
= ValueDataCellOffset
;
4150 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4152 PHASH_TABLE_CELL SrcHashTableCell
;
4153 PKEY_CELL SrcSubKeyCell
;
4154 PKEY_CELL NewSubKeyCell
;
4155 ULONG NewSubKeyCellSize
;
4156 BLOCK_OFFSET NewSubKeyCellOffset
;
4157 PHASH_RECORD SrcHashRecord
;
4159 SrcHashTableCell
= CmiGetCell (SrcHive
,
4160 SrcKeyCell
->HashTableOffset
,
4163 for (i
= 0; i
< SrcKeyCell
->NumberOfSubKeys
; i
++)
4165 SrcHashRecord
= &SrcHashTableCell
->Table
[i
];
4166 SrcSubKeyCell
= CmiGetCell (SrcHive
, SrcHashRecord
->KeyOffset
, NULL
);
4168 /* Allocate and copy key cell */
4169 NewSubKeyCellSize
= sizeof(KEY_CELL
) + SrcSubKeyCell
->NameSize
;
4170 Status
= CmiAllocateCell (DstHive
,
4172 (PVOID
)&NewSubKeyCell
,
4173 &NewSubKeyCellOffset
);
4174 if (!NT_SUCCESS(Status
))
4176 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4179 if (NewKeyCell
== NULL
)
4181 DPRINT1 ("Failed to allocate a sub key cell\n");
4182 return STATUS_INSUFFICIENT_RESOURCES
;
4185 NewHashTableCell
->Table
[i
].KeyOffset
= NewSubKeyCellOffset
;
4186 NewHashTableCell
->Table
[i
].HashValue
= SrcHashRecord
->HashValue
;
4188 RtlCopyMemory (NewSubKeyCell
,
4192 /* Copy class name */
4193 if (SrcSubKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4195 PDATA_CELL SrcClassNameCell
;
4196 PDATA_CELL NewClassNameCell
;
4197 BLOCK_OFFSET NewClassNameOffset
;
4199 SrcClassNameCell
= CmiGetCell (SrcHive
,
4200 SrcSubKeyCell
->ClassNameOffset
,
4203 NewSubKeyCell
->ClassSize
= SrcSubKeyCell
->ClassSize
;
4204 Status
= CmiAllocateCell (DstHive
,
4205 sizeof(CELL_HEADER
) + NewSubKeyCell
->ClassSize
,
4206 (PVOID
)&NewClassNameCell
,
4207 &NewClassNameOffset
);
4208 if (!NT_SUCCESS(Status
))
4210 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4214 NewSubKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4215 RtlCopyMemory (NewClassNameCell
,
4217 NewSubKeyCell
->ClassSize
);
4220 /* Copy subkey data and subkeys */
4221 Status
= CmiCopyKey (DstHive
,
4225 if (!NT_SUCCESS(Status
))
4227 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4233 return STATUS_SUCCESS
;
4238 CmiSaveTempHive (PREGISTRY_HIVE Hive
,
4241 IO_STATUS_BLOCK IoStatusBlock
;
4242 LARGE_INTEGER FileOffset
;
4247 DPRINT ("CmiSaveTempHive() called\n");
4249 Hive
->HiveHeader
->Checksum
= CmiCalcChecksum ((PULONG
)Hive
->HiveHeader
);
4251 /* Write hive block */
4252 FileOffset
.QuadPart
= (ULONGLONG
)0;
4253 Status
= ZwWriteFile (FileHandle
,
4259 sizeof(HIVE_HEADER
),
4262 if (!NT_SUCCESS(Status
))
4264 DPRINT1 ("ZwWriteFile() failed (Status %lx)\n", Status
);
4268 DPRINT ("Saving %lu blocks\n", Hive
->BlockListSize
);
4269 for (BlockIndex
= 0; BlockIndex
< Hive
->BlockListSize
; BlockIndex
++)
4271 BlockPtr
= Hive
->BlockList
[BlockIndex
].Block
;
4272 DPRINT ("BlockPtr %p\n", BlockPtr
);
4274 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
4275 DPRINT ("File offset %I64x\n", FileOffset
.QuadPart
);
4277 /* Write hive block */
4278 Status
= ZwWriteFile (FileHandle
,
4287 if (!NT_SUCCESS(Status
))
4289 DPRINT1 ("ZwWriteFile() failed (Status %lx)\n", Status
);
4294 Status
= ZwFlushBuffersFile (FileHandle
,
4296 if (!NT_SUCCESS(Status
))
4298 DPRINT1 ("ZwFlushBuffersFile() failed (Status %lx)\n", Status
);
4301 DPRINT ("CmiSaveTempHive() done\n");