2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/regfile.c
5 * PURPOSE: Registry file manipulation routines
11 #include <internal/debug.h>
16 /* uncomment to enable hive checks (incomplete and probably buggy) */
19 /* LOCAL MACROS *************************************************************/
21 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
23 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
25 BOOLEAN CmiDoVerify
= FALSE
;
28 CmiCalcChecksum(PULONG Buffer
);
30 /* FUNCTIONS ****************************************************************/
33 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header
)
36 RtlZeroMemory(Header
, sizeof(HIVE_HEADER
));
37 Header
->BlockId
= REG_HIVE_ID
;
38 Header
->UpdateCounter1
= 0;
39 Header
->UpdateCounter2
= 0;
40 Header
->DateModified
.u
.LowPart
= 0;
41 Header
->DateModified
.u
.HighPart
= 0;
47 Header
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
48 Header
->BlockSize
= REG_BLOCK_SIZE
;
55 CmiCreateDefaultBinHeader(PHBIN BinHeader
)
58 RtlZeroMemory(BinHeader
, sizeof(HBIN
));
59 BinHeader
->HeaderId
= REG_BIN_ID
;
60 BinHeader
->DateModified
.u
.LowPart
= 0;
61 BinHeader
->DateModified
.u
.HighPart
= 0;
62 BinHeader
->BinSize
= REG_BLOCK_SIZE
;
67 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
)
70 RtlZeroMemory(RootKeyCell
, sizeof(KEY_CELL
));
71 RootKeyCell
->CellSize
= -sizeof(KEY_CELL
);
72 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
73 RootKeyCell
->Flags
= REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
;
74 NtQuerySystemTime(&RootKeyCell
->LastWriteTime
);
75 RootKeyCell
->ParentKeyOffset
= 0;
76 RootKeyCell
->NumberOfSubKeys
= 0;
77 RootKeyCell
->HashTableOffset
= -1;
78 RootKeyCell
->NumberOfValues
= 0;
79 RootKeyCell
->ValueListOffset
= -1;
80 RootKeyCell
->SecurityKeyOffset
= 0;
81 RootKeyCell
->ClassNameOffset
= -1;
82 RootKeyCell
->NameSize
= 0;
83 RootKeyCell
->ClassSize
= 0;
88 CmiVerifyBinHeader(PHBIN BinHeader
)
95 if (BinHeader
->HeaderId
!= REG_BIN_ID
)
97 DbgPrint("Bin header ID is %.08x (should be %.08x)\n",
98 BinHeader
->HeaderId
, REG_BIN_ID
);
99 assert(BinHeader
->HeaderId
== REG_BIN_ID
);
102 //BinHeader->DateModified.dwLowDateTime
104 //BinHeader->DateModified.dwHighDateTime
107 if (BinHeader
->BinSize
!= REG_BLOCK_SIZE
)
109 DbgPrint("BinSize is %.08x (should be a multiple of %.08x)\n",
110 BinHeader
->BinSize
, REG_BLOCK_SIZE
);
111 assert(BinHeader
->BinSize
% REG_BLOCK_SIZE
== 0);
119 CmiVerifyKeyCell(PKEY_CELL KeyCell
)
126 if (KeyCell
->CellSize
== 0)
128 DbgPrint("CellSize is %d (must not be 0)\n",
130 assert(KeyCell
->CellSize
!= 0);
133 if (KeyCell
->Id
!= REG_KEY_CELL_ID
)
135 DbgPrint("Id is %.08x (should be %.08x)\n",
136 KeyCell
->Id
, REG_KEY_CELL_ID
);
137 assert(KeyCell
->Id
== REG_KEY_CELL_ID
);
142 //KeyCell->LastWriteTime;
144 if (KeyCell
->ParentKeyOffset
< 0)
146 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
147 KeyCell
->ParentKeyOffset
);
148 assert(KeyCell
->ParentKeyOffset
>= 0);
151 if (KeyCell
->NumberOfSubKeys
< 0)
153 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
154 KeyCell
->NumberOfSubKeys
);
155 assert(KeyCell
->NumberOfSubKeys
>= 0);
158 //KeyCell->HashTableOffset;
160 if (KeyCell
->NumberOfValues
< 0)
162 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
163 KeyCell
->NumberOfValues
);
164 assert(KeyCell
->NumberOfValues
>= 0);
167 //KeyCell->ValuesOffset = -1;
169 if (KeyCell
->SecurityKeyOffset
< 0)
171 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
172 KeyCell
->SecurityKeyOffset
);
173 assert(KeyCell
->SecurityKeyOffset
>= 0);
176 //KeyCell->ClassNameOffset = -1;
187 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell
)
192 CmiVerifyKeyCell(RootKeyCell
);
194 if (!(RootKeyCell
->Flags
& REG_KEY_ROOT_CELL
))
196 DbgPrint("Flags is %.08x (should be %.08x)\n",
197 RootKeyCell
->Flags
, REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
);
198 assert(!(RootKeyCell
->Flags
& (REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
)));
206 CmiVerifyValueCell(PVALUE_CELL ValueCell
)
213 if (ValueCell
->CellSize
== 0)
215 DbgPrint("CellSize is %d (must not be 0)\n",
216 ValueCell
->CellSize
);
217 assert(ValueCell
->CellSize
!= 0);
220 if (ValueCell
->Id
!= REG_VALUE_CELL_ID
)
222 DbgPrint("Id is %.08x (should be %.08x)\n",
223 ValueCell
->Id
, REG_VALUE_CELL_ID
);
224 assert(ValueCell
->Id
== REG_VALUE_CELL_ID
);
227 //ValueCell->NameSize;
228 //ValueCell->LONG DataSize;
229 //ValueCell->DataOffset;
230 //ValueCell->ULONG DataType;
231 //ValueCell->USHORT Flags;
232 //ValueCell->USHORT Unused1;
233 //ValueCell->UCHAR Name[0];
239 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell
)
244 if (ValueListCell
->CellSize
== 0)
246 DbgPrint("CellSize is %d (must not be 0)\n",
247 ValueListCell
->CellSize
);
248 assert(ValueListCell
->CellSize
!= 0);
256 CmiVerifyKeyObject(PKEY_OBJECT KeyObject
)
261 if (KeyObject
->RegistryHive
== NULL
)
263 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
264 KeyObject
->RegistryHive
);
265 assert(KeyObject
->RegistryHive
!= NULL
);
268 if (KeyObject
->KeyCell
== NULL
)
270 DbgPrint("KeyCell is NULL (must not be NULL)\n",
272 assert(KeyObject
->KeyCell
!= NULL
);
275 if (KeyObject
->ParentKey
== NULL
)
277 DbgPrint("ParentKey is NULL (must not be NULL)\n",
278 KeyObject
->ParentKey
);
279 assert(KeyObject
->ParentKey
!= NULL
);
287 CmiVerifyHiveHeader(PHIVE_HEADER Header
)
292 if (Header
->BlockId
!= REG_HIVE_ID
)
294 DbgPrint("BlockId is %.08x (must be %.08x)\n",
297 assert(Header
->BlockId
== REG_HIVE_ID
);
300 if (Header
->Unused3
!= 1)
302 DbgPrint("Unused3 is %.08x (must be 1)\n",
304 assert(Header
->Unused3
== 1);
307 if (Header
->Unused4
!= 3)
309 DbgPrint("Unused4 is %.08x (must be 3)\n",
311 assert(Header
->Unused4
== 3);
314 if (Header
->Unused5
!= 0)
316 DbgPrint("Unused5 is %.08x (must be 0)\n",
318 assert(Header
->Unused5
== 0);
321 if (Header
->Unused6
!= 1)
323 DbgPrint("Unused6 is %.08x (must be 1)\n",
325 assert(Header
->Unused6
== 1);
328 if (Header
->Unused7
!= 1)
330 DbgPrint("Unused7 is %.08x (must be 1)\n",
332 assert(Header
->Unused7
== 1);
340 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive
)
345 CmiVerifyHiveHeader(RegistryHive
->HiveHeader
);
352 CmiCreateNewRegFile(HANDLE FileHandle
)
354 IO_STATUS_BLOCK IoStatusBlock
;
355 PCELL_HEADER FreeCell
;
356 PHIVE_HEADER HiveHeader
;
357 PKEY_CELL RootKeyCell
;
362 Buffer
= (PCHAR
) ExAllocatePool(NonPagedPool
, 2 * REG_BLOCK_SIZE
);
364 return STATUS_INSUFFICIENT_RESOURCES
;
366 RtlZeroMemory (Buffer
,
369 HiveHeader
= (PHIVE_HEADER
)Buffer
;
370 BinHeader
= (PHBIN
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
);
371 RootKeyCell
= (PKEY_CELL
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
);
372 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
374 CmiCreateDefaultHiveHeader(HiveHeader
);
375 CmiCreateDefaultBinHeader(BinHeader
);
376 CmiCreateDefaultRootKeyCell(RootKeyCell
);
379 BinHeader
->BinOffset
= 0;
381 /* Offset to root key block */
382 HiveHeader
->RootKeyOffset
= REG_HBIN_DATA_OFFSET
;
384 /* The rest of the block is free */
385 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
387 Status
= NtWriteFile(FileHandle
,
399 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
401 if (!NT_SUCCESS(Status
))
406 Status
= NtFlushBuffersFile(FileHandle
,
415 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive
)
417 OBJECT_ATTRIBUTES ObjectAttributes
;
418 FILE_STANDARD_INFORMATION fsi
;
419 IO_STATUS_BLOCK IoStatusBlock
;
420 HANDLE HiveHandle
= INVALID_HANDLE_VALUE
;
421 HANDLE LogHandle
= INVALID_HANDLE_VALUE
;
422 PHIVE_HEADER HiveHeader
= NULL
;
423 PHIVE_HEADER LogHeader
= NULL
;
424 LARGE_INTEGER FileOffset
;
428 RTL_BITMAP BlockBitMap
;
431 DPRINT("CmiCheckAndFixHive() called\n");
433 /* Try to open the hive file */
434 InitializeObjectAttributes(&ObjectAttributes
,
435 &RegistryHive
->HiveFileName
,
436 OBJ_CASE_INSENSITIVE
,
440 Status
= NtCreateFile(&HiveHandle
,
441 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
445 FILE_ATTRIBUTE_NORMAL
,
448 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
451 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
453 return(STATUS_SUCCESS
);
455 if (!NT_SUCCESS(Status
))
457 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
461 /* Try to open the log file */
462 InitializeObjectAttributes(&ObjectAttributes
,
463 &RegistryHive
->LogFileName
,
464 OBJ_CASE_INSENSITIVE
,
468 Status
= NtCreateFile(&LogHandle
,
469 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
473 FILE_ATTRIBUTE_NORMAL
,
476 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
479 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
481 LogHandle
= INVALID_HANDLE_VALUE
;
483 else if (!NT_SUCCESS(Status
))
485 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
490 /* Allocate hive header */
491 HiveHeader
= ExAllocatePool(PagedPool
,
492 sizeof(HIVE_HEADER
));
493 if (HiveHeader
== NULL
)
495 DPRINT("ExAllocatePool() failed\n");
496 Status
= STATUS_INSUFFICIENT_RESOURCES
;
500 /* Read hive base block */
501 FileOffset
.QuadPart
= 0ULL;
502 Status
= NtReadFile(HiveHandle
,
511 if (!NT_SUCCESS(Status
))
513 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
517 if (LogHandle
== INVALID_HANDLE_VALUE
)
519 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
520 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
522 /* There is no way to fix the hive without log file - BSOD! */
523 DPRINT("Hive header inconsistent and no log file available!\n");
524 KEBUGCHECK(CONFIG_LIST_FAILED
);
527 Status
= STATUS_SUCCESS
;
532 /* Allocate hive header */
533 LogHeader
= ExAllocatePool(PagedPool
,
534 sizeof(HIVE_HEADER
));
535 if (LogHeader
== NULL
)
537 DPRINT("ExAllocatePool() failed\n");
538 Status
= STATUS_INSUFFICIENT_RESOURCES
;
542 /* Read log file header */
543 FileOffset
.QuadPart
= 0ULL;
544 Status
= NtReadFile(LogHandle
,
553 if (!NT_SUCCESS(Status
))
555 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
559 /* Check log file header integrity */
560 if (LogHeader
->Checksum
!= CmiCalcChecksum((PULONG
)LogHeader
) ||
561 LogHeader
->UpdateCounter1
!= LogHeader
->UpdateCounter2
)
563 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
564 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
566 DPRINT("Hive file and log file are inconsistent!\n");
567 KEBUGCHECK(CONFIG_LIST_FAILED
);
570 /* Log file damaged but hive is okay */
571 Status
= STATUS_SUCCESS
;
575 if (HiveHeader
->UpdateCounter1
== HiveHeader
->UpdateCounter2
&&
576 HiveHeader
->UpdateCounter1
== LogHeader
->UpdateCounter1
)
578 /* Hive and log file are up-to-date */
579 Status
= STATUS_SUCCESS
;
584 * Hive needs an update!
588 Status
= NtQueryInformationFile(LogHandle
,
592 FileStandardInformation
);
593 if (!NT_SUCCESS(Status
))
595 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
598 FileSize
= fsi
.EndOfFile
.u
.LowPart
;
600 /* Calculate bitmap and block size */
601 BitmapSize
= ROUND_UP((FileSize
/ REG_BLOCK_SIZE
) - 1, sizeof(ULONG
) * 8) / 8;
602 BufferSize
= sizeof(HIVE_HEADER
) +
605 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
607 /* Reallocate log header block */
608 ExFreePool(LogHeader
);
609 LogHeader
= ExAllocatePool(PagedPool
,
611 if (LogHeader
== NULL
)
613 DPRINT("ExAllocatePool() failed\n");
614 Status
= STATUS_INSUFFICIENT_RESOURCES
;
618 /* Read log file header */
619 FileOffset
.QuadPart
= 0ULL;
620 Status
= NtReadFile(LogHandle
,
629 if (!NT_SUCCESS(Status
))
631 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
635 /* Initialize bitmap */
636 RtlInitializeBitMap(&BlockBitMap
,
637 (PVOID
)((ULONG_PTR
)LogHeader
+ REG_BLOCK_SIZE
+ sizeof(ULONG
)),
640 /* FIXME: Update dirty blocks */
643 /* FIXME: Update hive header */
646 Status
= STATUS_SUCCESS
;
650 /* Clean up the mess */
652 if (HiveHeader
!= NULL
)
653 ExFreePool(HiveHeader
);
655 if (LogHeader
!= NULL
)
656 ExFreePool(LogHeader
);
658 if (LogHandle
!= INVALID_HANDLE_VALUE
)
669 CmiImportHiveBins(PREGISTRY_HIVE Hive
,
672 BLOCK_OFFSET BlockOffset
;
679 while (BlockIndex
< Hive
->BlockListSize
)
681 Bin
= (PHBIN
)((ULONG_PTR
)ChunkPtr
+ BlockOffset
);
683 if (Bin
->HeaderId
!= REG_BIN_ID
)
685 DPRINT1 ("Bad bin header id %x, offset %x\n", Bin
->HeaderId
, BlockOffset
);
686 return STATUS_REGISTRY_CORRUPT
;
689 assertmsg((Bin
->BinSize
% REG_BLOCK_SIZE
) == 0,
690 ("Bin size (0x%.08x) must be multiple of 4K\n",
693 /* Allocate the hive block */
694 Hive
->BlockList
[BlockIndex
].Bin
= ExAllocatePool (PagedPool
,
696 if (Hive
->BlockList
[BlockIndex
].Bin
== NULL
)
698 DPRINT1 ("ExAllocatePool() failed\n");
699 return STATUS_INSUFFICIENT_RESOURCES
;
701 Hive
->BlockList
[BlockIndex
].Block
= (PVOID
)Hive
->BlockList
[BlockIndex
].Bin
;
704 RtlCopyMemory (Hive
->BlockList
[BlockIndex
].Bin
,
708 if (Bin
->BinSize
> REG_BLOCK_SIZE
)
710 for (j
= 1; j
< Bin
->BinSize
/ REG_BLOCK_SIZE
; j
++)
712 Hive
->BlockList
[BlockIndex
+ j
].Bin
= Hive
->BlockList
[BlockIndex
].Bin
;
713 Hive
->BlockList
[BlockIndex
+ j
].Block
=
714 (PVOID
)((ULONG_PTR
)Hive
->BlockList
[BlockIndex
].Bin
+ (j
* REG_BLOCK_SIZE
));
718 BlockIndex
+= Bin
->BinSize
/ REG_BLOCK_SIZE
;
719 BlockOffset
+= Bin
->BinSize
;
722 return STATUS_SUCCESS
;
727 CmiFreeHiveBins (PREGISTRY_HIVE Hive
)
733 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
735 if (Hive
->BlockList
[i
].Bin
== NULL
)
738 if (Hive
->BlockList
[i
].Bin
!= Bin
)
740 Bin
= Hive
->BlockList
[i
].Bin
;
741 ExFreePool (Hive
->BlockList
[i
].Bin
);
743 Hive
->BlockList
[i
].Bin
= NULL
;
744 Hive
->BlockList
[i
].Block
= NULL
;
750 CmiCreateHiveFreeCellList(PREGISTRY_HIVE Hive
)
752 BLOCK_OFFSET BlockOffset
;
753 PCELL_HEADER FreeBlock
;
759 /* Initialize the free cell list */
760 Hive
->FreeListSize
= 0;
761 Hive
->FreeListMax
= 0;
762 Hive
->FreeList
= NULL
;
763 Hive
->FreeListOffset
= NULL
;
767 while (BlockIndex
< Hive
->BlockListSize
)
769 Bin
= Hive
->BlockList
[BlockIndex
].Bin
;
771 /* Search free blocks and add to list */
772 FreeOffset
= REG_HBIN_DATA_OFFSET
;
773 while (FreeOffset
< Bin
->BinSize
)
775 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) Bin
+ FreeOffset
);
776 if (FreeBlock
->CellSize
> 0)
778 Status
= CmiAddFree(Hive
,
780 Bin
->BinOffset
+ FreeOffset
,
783 if (!NT_SUCCESS(Status
))
788 FreeOffset
+= FreeBlock
->CellSize
;
792 FreeOffset
-= FreeBlock
->CellSize
;
796 BlockIndex
+= Bin
->BinSize
/ REG_BLOCK_SIZE
;
797 BlockOffset
+= Bin
->BinSize
;
800 return STATUS_SUCCESS
;
805 CmiFreeHiveFreeCellList(PREGISTRY_HIVE Hive
)
807 ExFreePool (Hive
->FreeList
);
808 ExFreePool (Hive
->FreeListOffset
);
810 Hive
->FreeListSize
= 0;
811 Hive
->FreeListMax
= 0;
812 Hive
->FreeList
= NULL
;
813 Hive
->FreeListOffset
= NULL
;
818 CmiCreateHiveBitmap(PREGISTRY_HIVE Hive
)
822 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
823 BitmapSize
= ROUND_UP(Hive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
824 DPRINT("Hive->BlockListSize: %lu\n", Hive
->BlockListSize
);
825 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
827 /* Allocate bitmap */
828 Hive
->BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
830 if (Hive
->BitmapBuffer
== NULL
)
832 return STATUS_INSUFFICIENT_RESOURCES
;
835 RtlInitializeBitMap(&Hive
->DirtyBitMap
,
839 /* Initialize bitmap */
840 RtlClearAllBits(&Hive
->DirtyBitMap
);
841 Hive
->HiveDirty
= FALSE
;
843 return STATUS_SUCCESS
;
848 CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive
,
851 OBJECT_ATTRIBUTES ObjectAttributes
;
852 ULONG CreateDisposition
;
853 IO_STATUS_BLOCK IoSB
;
855 PSECTION_OBJECT SectionObject
;
860 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) called\n",
861 RegistryHive
, Filename
);
863 /* Duplicate Filename */
864 Status
= RtlCreateUnicodeString(&RegistryHive
->HiveFileName
,
866 if (!NT_SUCCESS(Status
))
868 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status
);
872 /* Create log file name */
873 RegistryHive
->LogFileName
.Length
= (wcslen(Filename
) + 4) * sizeof(WCHAR
);
874 RegistryHive
->LogFileName
.MaximumLength
= RegistryHive
->LogFileName
.Length
+ sizeof(WCHAR
);
875 RegistryHive
->LogFileName
.Buffer
= ExAllocatePool(NonPagedPool
,
876 RegistryHive
->LogFileName
.MaximumLength
);
877 if (RegistryHive
->LogFileName
.Buffer
== NULL
)
879 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
880 DPRINT("ExAllocatePool() failed\n");
881 return(STATUS_INSUFFICIENT_RESOURCES
);
883 wcscpy(RegistryHive
->LogFileName
.Buffer
,
885 wcscat(RegistryHive
->LogFileName
.Buffer
,
889 /* Check and eventually fix a hive */
890 Status
= CmiCheckAndFixHive(RegistryHive
);
891 if (!NT_SUCCESS(Status
))
893 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
894 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
895 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status
);
900 InitializeObjectAttributes(&ObjectAttributes
,
901 &RegistryHive
->HiveFileName
,
902 OBJ_CASE_INSENSITIVE
,
906 CreateDisposition
= FILE_OPEN_IF
;
907 Status
= NtCreateFile(&FileHandle
,
912 FILE_ATTRIBUTE_NORMAL
,
915 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
918 if (!NT_SUCCESS(Status
))
920 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
921 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
922 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
926 if (IoSB
.Information
!= FILE_OPENED
)
928 Status
= CmiCreateNewRegFile(FileHandle
);
929 if (!NT_SUCCESS(Status
))
931 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status
);
933 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
934 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
939 /* Create the hive section */
940 Status
= MmCreateSection(&SectionObject
,
948 if (!NT_SUCCESS(Status
))
950 DPRINT1("MmCreateSection() failed (Status %lx)\n", Status
);
951 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
952 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
956 /* Map the hive file */
959 Status
= MmMapViewOfSection(SectionObject
,
960 PsGetCurrentProcess(),
969 if (!NT_SUCCESS(Status
))
971 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status
);
972 ObDereferenceObject(SectionObject
);
973 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
974 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
978 DPRINT("ViewBase %p ViewSize %lx\n", ViewBase
, ViewSize
);
980 /* Copy hive header and initalize hive */
981 RtlCopyMemory (RegistryHive
->HiveHeader
,
983 sizeof(HIVE_HEADER
));
984 RegistryHive
->FileSize
= ViewSize
;
985 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ REG_BLOCK_SIZE
) - 1;
986 RegistryHive
->UpdateCounter
= RegistryHive
->HiveHeader
->UpdateCounter1
;
988 /* Allocate hive block list */
989 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
990 RegistryHive
->BlockListSize
* sizeof(BLOCK_LIST_ENTRY
));
991 if (RegistryHive
->BlockList
== NULL
)
993 DPRINT1("Failed to allocate the hive block list\n");
994 MmUnmapViewOfSection(PsGetCurrentProcess(),
996 ObDereferenceObject(SectionObject
);
997 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
998 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1000 return STATUS_INSUFFICIENT_RESOURCES
;
1002 RtlZeroMemory (RegistryHive
->BlockList
,
1003 RegistryHive
->BlockListSize
* sizeof(BLOCK_LIST_ENTRY
));
1005 /* Import the hive bins */
1006 Status
= CmiImportHiveBins (RegistryHive
,
1007 ViewBase
+ REG_BLOCK_SIZE
);
1008 if (!NT_SUCCESS(Status
))
1010 ExFreePool(RegistryHive
->BlockList
);
1011 MmUnmapViewOfSection(PsGetCurrentProcess(),
1013 ObDereferenceObject(SectionObject
);
1014 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1015 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1016 NtClose(FileHandle
);
1020 /* Unmap and dereference the hive section */
1021 MmUnmapViewOfSection(PsGetCurrentProcess(),
1023 ObDereferenceObject(SectionObject
);
1025 /* Close the hive file */
1026 NtClose(FileHandle
);
1028 /* Initialize the free cell list */
1029 Status
= CmiCreateHiveFreeCellList (RegistryHive
);
1030 if (!NT_SUCCESS(Status
))
1032 CmiFreeHiveBins(RegistryHive
);
1033 ExFreePool(RegistryHive
->BlockList
);
1034 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1035 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1039 /* Create the block bitmap */
1040 Status
= CmiCreateHiveBitmap (RegistryHive
);
1041 if (!NT_SUCCESS(Status
))
1043 CmiFreeHiveFreeCellList(RegistryHive
);
1044 CmiFreeHiveBins(RegistryHive
);
1045 ExFreePool(RegistryHive
->BlockList
);
1046 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1047 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1051 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n",
1052 RegistryHive
, Filename
);
1054 return STATUS_SUCCESS
;
1059 CmiCreateVolatileHive(PREGISTRY_HIVE
*RegistryHive
)
1061 PKEY_CELL RootKeyCell
;
1062 PREGISTRY_HIVE Hive
;
1064 *RegistryHive
= NULL
;
1066 Hive
= ExAllocatePool (NonPagedPool
,
1067 sizeof(REGISTRY_HIVE
));
1069 return STATUS_INSUFFICIENT_RESOURCES
;
1071 RtlZeroMemory (Hive
,
1072 sizeof(REGISTRY_HIVE
));
1074 DPRINT("Hive %x\n", Hive
);
1076 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1077 sizeof(HIVE_HEADER
));
1078 if (Hive
->HiveHeader
== NULL
)
1081 return STATUS_INSUFFICIENT_RESOURCES
;
1083 RtlZeroMemory (Hive
->HiveHeader
,
1084 sizeof(HIVE_HEADER
));
1086 Hive
->Flags
= (HIVE_NO_FILE
| HIVE_POINTER
);
1088 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1090 RootKeyCell
= (PKEY_CELL
)ExAllocatePool (NonPagedPool
,
1092 if (RootKeyCell
== NULL
)
1094 ExFreePool(Hive
->HiveHeader
);
1096 return STATUS_INSUFFICIENT_RESOURCES
;
1099 CmiCreateDefaultRootKeyCell (RootKeyCell
);
1100 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)RootKeyCell
;
1102 ExInitializeResourceLite (&Hive
->HiveResource
);
1104 /* Acquire hive list lock exclusively */
1105 KeEnterCriticalRegion();
1106 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1109 /* Add the new hive to the hive list */
1110 InsertTailList (&CmiHiveListHead
,
1113 /* Release hive list lock */
1114 ExReleaseResourceLite (&CmiHiveListLock
);
1115 KeLeaveCriticalRegion();
1117 VERIFY_REGISTRY_HIVE (Hive
);
1119 *RegistryHive
= Hive
;
1121 return STATUS_SUCCESS
;
1126 CmiCreateTempHive(PREGISTRY_HIVE
*RegistryHive
)
1129 PCELL_HEADER FreeCell
;
1130 PREGISTRY_HIVE Hive
;
1133 DPRINT ("CmiCreateTempHive() called\n");
1135 *RegistryHive
= NULL
;
1137 Hive
= ExAllocatePool (NonPagedPool
,
1138 sizeof(REGISTRY_HIVE
));
1141 DPRINT1 ("Failed to allocate registry hive block\n");
1142 return STATUS_INSUFFICIENT_RESOURCES
;
1144 RtlZeroMemory (Hive
,
1145 sizeof(REGISTRY_HIVE
));
1147 DPRINT ("Hive %x\n", Hive
);
1149 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1151 if (Hive
->HiveHeader
== NULL
)
1153 DPRINT1 ("Failed to allocate hive header block\n");
1155 return STATUS_INSUFFICIENT_RESOURCES
;
1157 RtlZeroMemory (Hive
->HiveHeader
,
1160 DPRINT ("HiveHeader %x\n", Hive
->HiveHeader
);
1162 Hive
->Flags
= HIVE_NO_FILE
;
1164 RtlInitUnicodeString (&Hive
->HiveFileName
,
1166 RtlInitUnicodeString (&Hive
->LogFileName
,
1169 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1171 /* Allocate hive block list */
1172 Hive
->BlockList
= ExAllocatePool (NonPagedPool
,
1173 sizeof(PBLOCK_LIST_ENTRY
));
1174 if (Hive
->BlockList
== NULL
)
1176 DPRINT1 ("Failed to allocate hive block list\n");
1177 ExFreePool(Hive
->HiveHeader
);
1179 return STATUS_INSUFFICIENT_RESOURCES
;
1182 /* Allocate first Bin */
1183 Hive
->BlockList
[0].Bin
= ExAllocatePool (NonPagedPool
,
1185 if (Hive
->BlockList
[0].Bin
== NULL
)
1187 DPRINT1 ("Failed to allocate first bin\n");
1188 ExFreePool(Hive
->BlockList
);
1189 ExFreePool(Hive
->HiveHeader
);
1191 return STATUS_INSUFFICIENT_RESOURCES
;
1193 Hive
->BlockList
[0].Block
= (PVOID
)Hive
->BlockList
[0].Bin
;
1195 Hive
->FileSize
= 2* REG_BLOCK_SIZE
;
1196 Hive
->BlockListSize
= 1;
1197 Hive
->UpdateCounter
= Hive
->HiveHeader
->UpdateCounter1
;
1200 BinHeader
= Hive
->BlockList
[0].Bin
;
1201 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)BinHeader
+ REG_HBIN_DATA_OFFSET
);
1203 CmiCreateDefaultBinHeader (BinHeader
);
1206 BinHeader
->BinOffset
= 0;
1208 /* Offset to root key block */
1209 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
1211 /* The rest of the block is free */
1212 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
1214 /* Create the free cell list */
1215 Status
= CmiCreateHiveFreeCellList (Hive
);
1216 if (Hive
->BlockList
[0].Bin
== NULL
)
1218 DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status
);
1219 ExFreePool(Hive
->BlockList
[0].Bin
);
1220 ExFreePool(Hive
->BlockList
);
1221 ExFreePool(Hive
->HiveHeader
);
1227 ExInitializeResourceLite (&Hive
->HiveResource
);
1229 /* Acquire hive list lock exclusively */
1230 KeEnterCriticalRegion();
1231 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1234 /* Add the new hive to the hive list */
1235 InsertTailList (&CmiHiveListHead
,
1238 /* Release hive list lock */
1239 ExReleaseResourceLite (&CmiHiveListLock
);
1240 KeLeaveCriticalRegion();
1242 VERIFY_REGISTRY_HIVE (Hive
);
1244 *RegistryHive
= Hive
;
1246 return STATUS_SUCCESS
;
1251 CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1252 IN PUNICODE_STRING FileName
,
1255 PREGISTRY_HIVE Hive
;
1258 DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName
);
1260 if (Flags
& ~REG_NO_LAZY_FLUSH
)
1261 return STATUS_INVALID_PARAMETER
;
1263 Hive
= ExAllocatePool (NonPagedPool
,
1264 sizeof(REGISTRY_HIVE
));
1267 DPRINT1 ("Failed to allocate hive header.\n");
1268 return STATUS_INSUFFICIENT_RESOURCES
;
1270 RtlZeroMemory (Hive
,
1271 sizeof(REGISTRY_HIVE
));
1273 DPRINT ("Hive %x\n", Hive
);
1274 Hive
->Flags
= (Flags
& REG_NO_LAZY_FLUSH
) ? HIVE_NO_SYNCH
: 0;
1276 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool(NonPagedPool
,
1277 sizeof(HIVE_HEADER
));
1278 if (Hive
->HiveHeader
== NULL
)
1280 DPRINT1 ("Failed to allocate hive header.\n");
1282 return STATUS_INSUFFICIENT_RESOURCES
;
1285 RtlZeroMemory (Hive
->HiveHeader
,
1286 sizeof(HIVE_HEADER
));
1288 Status
= CmiInitNonVolatileRegistryHive (Hive
,
1290 if (!NT_SUCCESS (Status
))
1292 DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status
);
1293 ExFreePool (Hive
->HiveHeader
);
1298 ExInitializeResourceLite (&Hive
->HiveResource
);
1300 /* Add the new hive to the hive list */
1301 KeEnterCriticalRegion();
1302 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1304 InsertTailList (&CmiHiveListHead
,
1306 ExReleaseResourceLite (&CmiHiveListLock
);
1307 KeLeaveCriticalRegion();
1310 VERIFY_REGISTRY_HIVE(Hive
);
1313 Status
= CmiConnectHive (KeyObjectAttributes
,
1315 if (!NT_SUCCESS(Status
))
1317 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status
);
1318 // CmiRemoveRegistryHive (Hive);
1321 DPRINT ("CmiLoadHive() done\n");
1328 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
1330 if (RegistryHive
->Flags
& HIVE_POINTER
)
1331 return STATUS_UNSUCCESSFUL
;
1333 /* Acquire hive list lock exclusively */
1334 KeEnterCriticalRegion();
1335 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1338 /* Remove hive from hive list */
1339 RemoveEntryList (&RegistryHive
->HiveList
);
1341 /* Release hive list lock */
1342 ExReleaseResourceLite (&CmiHiveListLock
);
1343 KeLeaveCriticalRegion();
1345 /* Release file names */
1346 RtlFreeUnicodeString (&RegistryHive
->HiveFileName
);
1347 RtlFreeUnicodeString (&RegistryHive
->LogFileName
);
1349 /* Release hive bitmap */
1350 ExFreePool (RegistryHive
->BitmapBuffer
);
1352 /* Release free cell list */
1353 ExFreePool (RegistryHive
->FreeList
);
1354 ExFreePool (RegistryHive
->FreeListOffset
);
1356 /* Release hive resource */
1357 ExDeleteResource (&RegistryHive
->HiveResource
);
1359 /* Release bins and bin list */
1360 CmiFreeHiveBins (RegistryHive
);
1361 ExFreePool (RegistryHive
->BlockList
);
1363 /* Release hive header */
1364 ExFreePool (RegistryHive
->HiveHeader
);
1367 ExFreePool (RegistryHive
);
1369 return STATUS_SUCCESS
;
1374 CmiCalcChecksum(PULONG Buffer
)
1379 for (i
= 0; i
< 127; i
++)
1387 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
1389 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1390 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1391 OBJECT_ATTRIBUTES ObjectAttributes
;
1392 IO_STATUS_BLOCK IoStatusBlock
;
1394 LARGE_INTEGER FileOffset
;
1403 DPRINT("CmiStartLogUpdate() called\n");
1405 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1406 BufferSize
= sizeof(HIVE_HEADER
) +
1409 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1411 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1413 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
,
1417 DPRINT("ExAllocatePool() failed\n");
1418 return(STATUS_INSUFFICIENT_RESOURCES
);
1420 RtlZeroMemory (Buffer
,
1423 /* Open log file for writing */
1424 InitializeObjectAttributes(&ObjectAttributes
,
1425 &RegistryHive
->LogFileName
,
1426 OBJ_CASE_INSENSITIVE
,
1430 Status
= NtCreateFile(&FileHandle
,
1435 FILE_ATTRIBUTE_NORMAL
,
1438 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1441 if (!NT_SUCCESS(Status
))
1443 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1448 /* Update firt update counter and checksum */
1449 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1450 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1452 /* Copy hive header */
1453 RtlCopyMemory(Buffer
,
1454 RegistryHive
->HiveHeader
,
1455 sizeof(HIVE_HEADER
));
1456 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1463 RegistryHive
->DirtyBitMap
.Buffer
,
1466 /* Write hive block and block bitmap */
1467 FileOffset
.QuadPart
= (ULONGLONG
)0;
1468 Status
= NtWriteFile(FileHandle
,
1477 if (!NT_SUCCESS(Status
))
1479 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1480 NtClose(FileHandle
);
1486 /* Write dirty blocks */
1487 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1491 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1494 if ((BlockIndex
== (ULONG
)-1) ||
1495 (BlockIndex
>= RegistryHive
->BlockListSize
))
1497 DPRINT("No more set bits\n");
1498 Status
= STATUS_SUCCESS
;
1502 DPRINT("Block %lu is dirty\n", BlockIndex
);
1504 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1505 DPRINT("BlockPtr %p\n", BlockPtr
);
1506 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1508 /* Write hive block */
1509 Status
= NtWriteFile(FileHandle
,
1518 if (!NT_SUCCESS(Status
))
1520 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1521 NtClose(FileHandle
);
1526 FileOffset
.QuadPart
+= (ULONGLONG
)REG_BLOCK_SIZE
;
1529 /* Truncate log file */
1530 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1531 Status
= NtSetInformationFile(FileHandle
,
1534 sizeof(FILE_END_OF_FILE_INFORMATION
),
1535 FileEndOfFileInformation
);
1536 if (!NT_SUCCESS(Status
))
1538 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1539 NtClose(FileHandle
);
1543 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1544 Status
= NtSetInformationFile(FileHandle
,
1546 &FileAllocationInfo
,
1547 sizeof(FILE_ALLOCATION_INFORMATION
),
1548 FileAllocationInformation
);
1549 if (!NT_SUCCESS(Status
))
1551 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1552 NtClose(FileHandle
);
1556 /* Flush the log file */
1557 Status
= NtFlushBuffersFile(FileHandle
,
1559 if (!NT_SUCCESS(Status
))
1561 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1564 NtClose(FileHandle
);
1571 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1573 OBJECT_ATTRIBUTES ObjectAttributes
;
1574 IO_STATUS_BLOCK IoStatusBlock
;
1576 LARGE_INTEGER FileOffset
;
1583 DPRINT("CmiFinishLogUpdate() called\n");
1585 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1586 BufferSize
= sizeof(HIVE_HEADER
) +
1589 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1591 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1593 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1596 DPRINT("ExAllocatePool() failed\n");
1597 return(STATUS_INSUFFICIENT_RESOURCES
);
1600 /* Open log file for writing */
1601 InitializeObjectAttributes(&ObjectAttributes
,
1602 &RegistryHive
->LogFileName
,
1603 OBJ_CASE_INSENSITIVE
,
1607 Status
= NtCreateFile(&FileHandle
,
1612 FILE_ATTRIBUTE_NORMAL
,
1615 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1618 if (!NT_SUCCESS(Status
))
1620 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1625 /* Update first and second update counter and checksum */
1626 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1627 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1628 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1630 /* Copy hive header */
1631 RtlCopyMemory(Buffer
,
1632 RegistryHive
->HiveHeader
,
1633 sizeof(HIVE_HEADER
));
1634 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1636 /* Write empty block bitmap */
1644 /* Write hive block and block bitmap */
1645 FileOffset
.QuadPart
= (ULONGLONG
)0;
1646 Status
= NtWriteFile(FileHandle
,
1655 if (!NT_SUCCESS(Status
))
1657 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1658 NtClose(FileHandle
);
1665 /* Flush the log file */
1666 Status
= NtFlushBuffersFile(FileHandle
,
1668 if (!NT_SUCCESS(Status
))
1670 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1673 NtClose(FileHandle
);
1680 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1682 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1683 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1684 OBJECT_ATTRIBUTES ObjectAttributes
;
1685 IO_STATUS_BLOCK IoStatusBlock
;
1691 DPRINT("CmiCleanupLogUpdate() called\n");
1693 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1694 BufferSize
= sizeof(HIVE_HEADER
) +
1697 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1699 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1701 /* Open log file for writing */
1702 InitializeObjectAttributes(&ObjectAttributes
,
1703 &RegistryHive
->LogFileName
,
1704 OBJ_CASE_INSENSITIVE
,
1708 Status
= NtCreateFile(&FileHandle
,
1713 FILE_ATTRIBUTE_NORMAL
,
1716 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1719 if (!NT_SUCCESS(Status
))
1721 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1725 /* Truncate log file */
1726 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1727 Status
= NtSetInformationFile(FileHandle
,
1730 sizeof(FILE_END_OF_FILE_INFORMATION
),
1731 FileEndOfFileInformation
);
1732 if (!NT_SUCCESS(Status
))
1734 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1735 NtClose(FileHandle
);
1739 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1740 Status
= NtSetInformationFile(FileHandle
,
1742 &FileAllocationInfo
,
1743 sizeof(FILE_ALLOCATION_INFORMATION
),
1744 FileAllocationInformation
);
1745 if (!NT_SUCCESS(Status
))
1747 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1748 NtClose(FileHandle
);
1752 /* Flush the log file */
1753 Status
= NtFlushBuffersFile(FileHandle
,
1755 if (!NT_SUCCESS(Status
))
1757 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1760 NtClose(FileHandle
);
1767 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1769 OBJECT_ATTRIBUTES ObjectAttributes
;
1770 IO_STATUS_BLOCK IoStatusBlock
;
1772 LARGE_INTEGER FileOffset
;
1777 DPRINT("CmiStartHiveUpdate() called\n");
1779 /* Open hive for writing */
1780 InitializeObjectAttributes(&ObjectAttributes
,
1781 &RegistryHive
->HiveFileName
,
1782 OBJ_CASE_INSENSITIVE
,
1786 Status
= NtCreateFile(&FileHandle
,
1791 FILE_ATTRIBUTE_NORMAL
,
1794 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1797 if (!NT_SUCCESS(Status
))
1799 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1803 /* Update firt update counter and checksum */
1804 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1805 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1807 /* Write hive block */
1808 FileOffset
.QuadPart
= (ULONGLONG
)0;
1809 Status
= NtWriteFile(FileHandle
,
1814 RegistryHive
->HiveHeader
,
1815 sizeof(HIVE_HEADER
),
1818 if (!NT_SUCCESS(Status
))
1820 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1821 NtClose(FileHandle
);
1828 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1831 if ((BlockIndex
== (ULONG
)-1) ||
1832 (BlockIndex
>= RegistryHive
->BlockListSize
))
1834 DPRINT("No more set bits\n");
1835 Status
= STATUS_SUCCESS
;
1839 DPRINT("Block %lu is dirty\n", BlockIndex
);
1841 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1842 DPRINT(" BlockPtr %p\n", BlockPtr
);
1844 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
1845 DPRINT(" File offset %I64x\n", FileOffset
.QuadPart
);
1847 /* Write hive block */
1848 Status
= NtWriteFile(FileHandle
,
1857 if (!NT_SUCCESS(Status
))
1859 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1860 NtClose(FileHandle
);
1867 Status
= NtFlushBuffersFile(FileHandle
,
1869 if (!NT_SUCCESS(Status
))
1871 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1874 NtClose(FileHandle
);
1881 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1883 OBJECT_ATTRIBUTES ObjectAttributes
;
1884 IO_STATUS_BLOCK IoStatusBlock
;
1885 LARGE_INTEGER FileOffset
;
1889 DPRINT("CmiFinishHiveUpdate() called\n");
1891 InitializeObjectAttributes(&ObjectAttributes
,
1892 &RegistryHive
->HiveFileName
,
1893 OBJ_CASE_INSENSITIVE
,
1897 Status
= NtCreateFile(&FileHandle
,
1902 FILE_ATTRIBUTE_NORMAL
,
1905 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1908 if (!NT_SUCCESS(Status
))
1910 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1914 /* Update second update counter and checksum */
1915 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1916 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1917 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1919 /* Write hive block */
1920 FileOffset
.QuadPart
= (ULONGLONG
)0;
1921 Status
= NtWriteFile(FileHandle
,
1926 RegistryHive
->HiveHeader
,
1927 sizeof(HIVE_HEADER
),
1930 if (!NT_SUCCESS(Status
))
1932 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1933 NtClose(FileHandle
);
1937 Status
= NtFlushBuffersFile(FileHandle
,
1939 if (!NT_SUCCESS(Status
))
1941 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1944 NtClose(FileHandle
);
1951 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1955 DPRINT("CmiFlushRegistryHive() called\n");
1957 if (RegistryHive
->HiveDirty
== FALSE
)
1959 return(STATUS_SUCCESS
);
1962 DPRINT("Hive '%wZ' is dirty\n",
1963 &RegistryHive
->HiveFileName
);
1964 DPRINT("Log file: '%wZ'\n",
1965 &RegistryHive
->LogFileName
);
1967 /* Update hive header modification time */
1968 NtQuerySystemTime(&RegistryHive
->HiveHeader
->DateModified
);
1970 /* Start log update */
1971 Status
= CmiStartLogUpdate(RegistryHive
);
1972 if (!NT_SUCCESS(Status
))
1974 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1978 /* Finish log update */
1979 Status
= CmiFinishLogUpdate(RegistryHive
);
1980 if (!NT_SUCCESS(Status
))
1982 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1986 /* Start hive update */
1987 Status
= CmiStartHiveUpdate(RegistryHive
);
1988 if (!NT_SUCCESS(Status
))
1990 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1994 /* Finish the hive update */
1995 Status
= CmiFinishHiveUpdate(RegistryHive
);
1996 if (!NT_SUCCESS(Status
))
1998 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
2002 /* Cleanup log update */
2003 Status
= CmiCleanupLogUpdate(RegistryHive
);
2004 if (!NT_SUCCESS(Status
))
2006 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
2010 /* Increment hive update counter */
2011 RegistryHive
->UpdateCounter
++;
2013 /* Clear dirty bitmap and dirty flag */
2014 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
2015 RegistryHive
->HiveDirty
= FALSE
;
2017 DPRINT("CmiFlushRegistryHive() done\n");
2019 return(STATUS_SUCCESS
);
2024 CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject
)
2031 VERIFY_KEY_OBJECT(KeyObject
);
2033 KeyCell
= KeyObject
->KeyCell
;
2034 VERIFY_KEY_CELL(KeyCell
);
2036 SubKeyCount
= (KeyCell
== NULL
) ? 0 : KeyCell
->NumberOfSubKeys
;
2038 /* Search for volatile or 'foreign' keys */
2039 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2041 CurKey
= KeyObject
->SubKeys
[i
];
2042 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2043 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2054 CmiGetMaxNameLength(PKEY_OBJECT KeyObject
)
2056 PHASH_TABLE_CELL HashBlock
;
2058 PKEY_CELL CurSubKeyCell
;
2064 VERIFY_KEY_OBJECT(KeyObject
);
2066 KeyCell
= KeyObject
->KeyCell
;
2067 VERIFY_KEY_CELL(KeyCell
);
2070 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2071 KeyCell
->HashTableOffset
,
2073 if (HashBlock
== NULL
)
2075 DPRINT("CmiGetBlock() failed\n");
2079 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2081 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2083 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2084 HashBlock
->Table
[i
].KeyOffset
,
2086 if (CurSubKeyCell
== NULL
)
2088 DPRINT("CmiGetBlock() failed\n");
2092 NameSize
= CurSubKeyCell
->NameSize
;
2093 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2095 NameSize
*= sizeof(WCHAR
);
2098 if (NameSize
> MaxName
)
2106 DPRINT ("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2107 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2109 CurKey
= KeyObject
->SubKeys
[i
];
2110 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2111 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2113 CurSubKeyCell
= CurKey
->KeyCell
;
2114 if (CurSubKeyCell
== NULL
)
2116 DPRINT("CmiGetBlock() failed\n");
2120 if ((CurSubKeyCell
->Flags
& REG_KEY_ROOT_CELL
) == REG_KEY_ROOT_CELL
)
2122 /* Use name of the key object */
2123 NameSize
= CurKey
->Name
.Length
;
2127 /* Use name of the key cell */
2128 NameSize
= CurSubKeyCell
->NameSize
;
2129 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2131 NameSize
*= sizeof(WCHAR
);
2134 DPRINT ("NameSize %lu\n", NameSize
);
2136 if (NameSize
> MaxName
)
2143 DPRINT ("MaxName %lu\n", MaxName
);
2150 CmiGetMaxClassLength(PKEY_OBJECT KeyObject
)
2152 PHASH_TABLE_CELL HashBlock
;
2154 PKEY_CELL CurSubKeyCell
;
2159 VERIFY_KEY_OBJECT(KeyObject
);
2161 KeyCell
= KeyObject
->KeyCell
;
2162 VERIFY_KEY_CELL(KeyCell
);
2165 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2166 KeyCell
->HashTableOffset
,
2168 if (HashBlock
== NULL
)
2170 DPRINT("CmiGetBlock() failed\n");
2174 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2176 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2178 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2179 HashBlock
->Table
[i
].KeyOffset
,
2181 if (CurSubKeyCell
== NULL
)
2183 DPRINT("CmiGetBlock() failed\n");
2187 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2189 MaxClass
= CurSubKeyCell
->ClassSize
;
2195 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2196 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2198 CurKey
= KeyObject
->SubKeys
[i
];
2199 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2200 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2202 CurSubKeyCell
= CurKey
->KeyCell
;
2203 if (CurSubKeyCell
== NULL
)
2205 DPRINT("CmiGetBlock() failed\n");
2209 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2211 MaxClass
= CurSubKeyCell
->ClassSize
;
2221 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
2224 PVALUE_LIST_CELL ValueListCell
;
2225 PVALUE_CELL CurValueCell
;
2230 VERIFY_KEY_CELL(KeyCell
);
2233 ValueListCell
= CmiGetCell (RegistryHive
,
2234 KeyCell
->ValueListOffset
,
2236 if (ValueListCell
== NULL
)
2238 DPRINT("CmiGetBlock() failed\n");
2242 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2244 CurValueCell
= CmiGetCell (RegistryHive
,
2245 ValueListCell
->ValueOffset
[i
],
2247 if (CurValueCell
== NULL
)
2249 DPRINT("CmiGetBlock() failed\n");
2252 if (CurValueCell
!= NULL
)
2254 Size
= CurValueCell
->NameSize
;
2255 if (CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
2257 Size
*= sizeof(WCHAR
);
2259 if (MaxValueName
< Size
)
2261 MaxValueName
= Size
;
2266 return MaxValueName
;
2271 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
2274 PVALUE_LIST_CELL ValueListCell
;
2275 PVALUE_CELL CurValueCell
;
2279 VERIFY_KEY_CELL(KeyCell
);
2282 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2283 if (ValueListCell
== NULL
)
2288 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2290 CurValueCell
= CmiGetCell (RegistryHive
,
2291 ValueListCell
->ValueOffset
[i
],NULL
);
2292 if ((CurValueCell
!= NULL
) &&
2293 (MaxValueData
< (LONG
)(CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2295 MaxValueData
= CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2299 return MaxValueData
;
2304 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
2305 IN PKEY_CELL KeyCell
,
2306 OUT PKEY_CELL
*SubKeyCell
,
2307 OUT BLOCK_OFFSET
*BlockOffset
,
2308 IN PUNICODE_STRING KeyName
,
2309 IN ACCESS_MASK DesiredAccess
,
2310 IN ULONG Attributes
)
2312 PHASH_TABLE_CELL HashBlock
;
2313 PKEY_CELL CurSubKeyCell
;
2316 VERIFY_KEY_CELL(KeyCell
);
2318 DPRINT("Scanning for sub key %wZ\n", KeyName
);
2320 assert(RegistryHive
);
2324 /* The key does not have any subkeys */
2325 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
2327 return STATUS_SUCCESS
;
2330 /* Get hash table */
2331 HashBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2332 if (HashBlock
== NULL
)
2334 DPRINT("CmiGetBlock() failed\n");
2335 return STATUS_UNSUCCESSFUL
;
2338 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
) && (i
< HashBlock
->HashTableSize
); i
++)
2340 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2342 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2343 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1 &&
2344 (HashBlock
->Table
[i
].HashValue
== 0 ||
2345 CmiCompareHashI(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2347 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2348 HashBlock
->Table
[i
].KeyOffset
,
2350 if (CurSubKeyCell
== NULL
)
2352 DPRINT("CmiGetBlock() failed\n");
2353 return STATUS_UNSUCCESSFUL
;
2356 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2358 *SubKeyCell
= CurSubKeyCell
;
2359 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2366 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2367 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2368 (HashBlock
->Table
[i
].HashValue
== 0 ||
2369 CmiCompareHash(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2371 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2372 HashBlock
->Table
[i
].KeyOffset
,
2374 if (CurSubKeyCell
== NULL
)
2376 DPRINT("CmiGetBlock() failed\n");
2377 return STATUS_UNSUCCESSFUL
;
2380 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2382 *SubKeyCell
= CurSubKeyCell
;
2383 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2390 return STATUS_SUCCESS
;
2395 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2396 PKEY_OBJECT ParentKey
,
2398 PUNICODE_STRING SubKeyName
,
2400 PUNICODE_STRING Class
,
2401 ULONG CreateOptions
)
2403 PHASH_TABLE_CELL HashBlock
;
2404 BLOCK_OFFSET NKBOffset
;
2405 PKEY_CELL NewKeyCell
;
2407 PKEY_CELL ParentKeyCell
;
2408 PDATA_CELL ClassCell
;
2415 ParentKeyCell
= ParentKey
->KeyCell
;
2417 VERIFY_KEY_CELL(ParentKeyCell
);
2419 /* Skip leading backslash */
2420 if (SubKeyName
->Buffer
[0] == L
'\\')
2422 NamePtr
= &SubKeyName
->Buffer
[1];
2423 NameSize
= SubKeyName
->Length
- sizeof(WCHAR
);
2427 NamePtr
= SubKeyName
->Buffer
;
2428 NameSize
= SubKeyName
->Length
;
2431 /* Check whether key name can be packed */
2433 for (i
= 0; i
< NameSize
/ sizeof(WCHAR
); i
++)
2435 if (NamePtr
[i
] & 0xFF00)
2442 /* Adjust name size */
2445 NameSize
= NameSize
/ sizeof(WCHAR
);
2448 DPRINT("Key %S Length %lu %s\n", NamePtr
, NameSize
, (Packable
)?"True":"False");
2450 Status
= STATUS_SUCCESS
;
2452 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2453 Status
= CmiAllocateCell (RegistryHive
,
2455 (PVOID
) &NewKeyCell
,
2457 if (NewKeyCell
== NULL
)
2459 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2463 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2464 NewKeyCell
->Flags
= 0;
2465 NtQuerySystemTime(&NewKeyCell
->LastWriteTime
);
2466 NewKeyCell
->ParentKeyOffset
= -1;
2467 NewKeyCell
->NumberOfSubKeys
= 0;
2468 NewKeyCell
->HashTableOffset
= -1;
2469 NewKeyCell
->NumberOfValues
= 0;
2470 NewKeyCell
->ValueListOffset
= -1;
2471 NewKeyCell
->SecurityKeyOffset
= -1;
2472 NewKeyCell
->ClassNameOffset
= -1;
2474 /* Pack the key name */
2475 NewKeyCell
->NameSize
= NameSize
;
2478 NewKeyCell
->Flags
|= REG_KEY_NAME_PACKED
;
2479 for (i
= 0; i
< NameSize
; i
++)
2481 NewKeyCell
->Name
[i
] = (CHAR
)(NamePtr
[i
] & 0x00FF);
2486 RtlCopyMemory(NewKeyCell
->Name
,
2491 VERIFY_KEY_CELL(NewKeyCell
);
2495 NewKeyCell
->ClassSize
= Class
->Length
;
2496 Status
= CmiAllocateCell (RegistryHive
,
2497 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
2499 &NewKeyCell
->ClassNameOffset
);
2500 RtlCopyMemory (ClassCell
->Data
,
2506 if (!NT_SUCCESS(Status
))
2511 SubKey
->KeyCell
= NewKeyCell
;
2512 SubKey
->KeyCellOffset
= NKBOffset
;
2514 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2515 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(ParentKey
->RegistryHive
)))
2520 if (ParentKeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2522 Status
= CmiAllocateHashTableCell (RegistryHive
,
2524 &ParentKeyCell
->HashTableOffset
,
2525 REG_INIT_HASH_TABLE_SIZE
);
2526 if (!NT_SUCCESS(Status
))
2533 HashBlock
= CmiGetCell (RegistryHive
,
2534 ParentKeyCell
->HashTableOffset
,
2536 if (HashBlock
== NULL
)
2538 DPRINT("CmiGetCell() failed\n");
2539 return STATUS_UNSUCCESSFUL
;
2542 if (((ParentKeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2544 PHASH_TABLE_CELL NewHashBlock
;
2545 BLOCK_OFFSET HTOffset
;
2547 /* Reallocate the hash table cell */
2548 Status
= CmiAllocateHashTableCell (RegistryHive
,
2551 HashBlock
->HashTableSize
+
2552 REG_EXTEND_HASH_TABLE_SIZE
);
2553 if (!NT_SUCCESS(Status
))
2558 RtlZeroMemory(&NewHashBlock
->Table
[0],
2559 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2560 RtlCopyMemory(&NewHashBlock
->Table
[0],
2561 &HashBlock
->Table
[0],
2562 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2563 CmiDestroyCell (RegistryHive
,
2565 ParentKeyCell
->HashTableOffset
);
2566 ParentKeyCell
->HashTableOffset
= HTOffset
;
2567 HashBlock
= NewHashBlock
;
2571 Status
= CmiAddKeyToHashTable(RegistryHive
,
2573 ParentKeyCell
->HashTableOffset
,
2576 if (NT_SUCCESS(Status
))
2578 ParentKeyCell
->NumberOfSubKeys
++;
2581 NtQuerySystemTime (&ParentKeyCell
->LastWriteTime
);
2582 CmiMarkBlockDirty (RegistryHive
, ParentKey
->KeyCellOffset
);
2589 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2590 PKEY_OBJECT ParentKey
,
2593 PHASH_TABLE_CELL HashBlock
;
2594 PVALUE_LIST_CELL ValueList
;
2595 PVALUE_CELL ValueCell
;
2596 PDATA_CELL DataCell
;
2599 DPRINT("CmiRemoveSubKey() called\n");
2601 /* Remove all values */
2602 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2604 /* Get pointer to the value list cell */
2605 ValueList
= CmiGetCell (RegistryHive
,
2606 SubKey
->KeyCell
->ValueListOffset
,
2608 if (ValueList
== NULL
)
2610 DPRINT("CmiGetCell() failed\n");
2611 return STATUS_UNSUCCESSFUL
;
2614 /* Enumerate all values */
2615 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2617 /* Get pointer to value cell */
2618 ValueCell
= CmiGetCell(RegistryHive
,
2619 ValueList
->ValueOffset
[i
],
2621 if (ValueCell
== NULL
)
2623 DPRINT("CmiGetCell() failed\n");
2624 return STATUS_UNSUCCESSFUL
;
2627 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
2629 DataCell
= CmiGetCell (RegistryHive
,
2630 ValueCell
->DataOffset
,
2632 if (DataCell
== NULL
)
2634 DPRINT("CmiGetCell() failed\n");
2635 return STATUS_UNSUCCESSFUL
;
2638 if (DataCell
!= NULL
)
2640 /* Destroy data cell */
2641 CmiDestroyCell (RegistryHive
,
2643 ValueCell
->DataOffset
);
2647 /* Destroy value cell */
2648 CmiDestroyCell (RegistryHive
,
2650 ValueList
->ValueOffset
[i
]);
2653 /* Destroy value list cell */
2654 CmiDestroyCell (RegistryHive
,
2656 SubKey
->KeyCell
->ValueListOffset
);
2658 SubKey
->KeyCell
->NumberOfValues
= 0;
2659 SubKey
->KeyCell
->ValueListOffset
= (BLOCK_OFFSET
)-1;
2661 CmiMarkBlockDirty(RegistryHive
,
2662 SubKey
->KeyCellOffset
);
2665 /* Remove the key from the parent key's hash block */
2666 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2668 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2669 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2670 ParentKey
->KeyCell
->HashTableOffset
,
2672 if (HashBlock
== NULL
)
2674 DPRINT("CmiGetCell() failed\n");
2675 return STATUS_UNSUCCESSFUL
;
2677 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2678 if (HashBlock
!= NULL
)
2680 CmiRemoveKeyFromHashTable(ParentKey
->RegistryHive
,
2682 SubKey
->KeyCellOffset
);
2683 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2684 ParentKey
->KeyCell
->HashTableOffset
);
2688 /* Remove the key's hash block */
2689 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2691 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
);
2692 HashBlock
= CmiGetCell (RegistryHive
,
2693 SubKey
->KeyCell
->HashTableOffset
,
2695 if (HashBlock
== NULL
)
2697 DPRINT("CmiGetCell() failed\n");
2698 return STATUS_UNSUCCESSFUL
;
2700 DPRINT("SubKey HashBlock %p\n", HashBlock
);
2701 if (HashBlock
!= NULL
)
2703 CmiDestroyCell (RegistryHive
,
2705 SubKey
->KeyCell
->HashTableOffset
);
2706 SubKey
->KeyCell
->HashTableOffset
= -1;
2710 /* Decrement the number of the parent key's sub keys */
2711 if (ParentKey
!= NULL
)
2713 DPRINT("ParentKey %p\n", ParentKey
);
2714 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2716 /* Remove the parent key's hash table */
2717 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2719 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2720 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2721 ParentKey
->KeyCell
->HashTableOffset
,
2723 if (HashBlock
== NULL
)
2725 DPRINT("CmiGetCell() failed\n");
2726 return STATUS_UNSUCCESSFUL
;
2728 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2729 if (HashBlock
!= NULL
)
2731 CmiDestroyCell (ParentKey
->RegistryHive
,
2733 ParentKey
->KeyCell
->HashTableOffset
);
2734 ParentKey
->KeyCell
->HashTableOffset
= (BLOCK_OFFSET
)-1;
2738 NtQuerySystemTime(&ParentKey
->KeyCell
->LastWriteTime
);
2739 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2740 ParentKey
->KeyCellOffset
);
2743 /* Destroy key cell */
2744 CmiDestroyCell (RegistryHive
,
2746 SubKey
->KeyCellOffset
);
2747 SubKey
->KeyCell
= NULL
;
2748 SubKey
->KeyCellOffset
= (BLOCK_OFFSET
)-1;
2750 DPRINT("CmiRemoveSubKey() done\n");
2752 return STATUS_SUCCESS
;
2757 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2758 IN PKEY_CELL KeyCell
,
2759 IN PUNICODE_STRING ValueName
,
2760 OUT PVALUE_CELL
*ValueCell
,
2761 OUT BLOCK_OFFSET
*ValueCellOffset
)
2763 PVALUE_LIST_CELL ValueListCell
;
2764 PVALUE_CELL CurValueCell
;
2768 if (ValueCellOffset
!= NULL
)
2769 *ValueCellOffset
= (BLOCK_OFFSET
)-1;
2771 /* The key does not have any values */
2772 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2774 return STATUS_OBJECT_NAME_NOT_FOUND
;
2777 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2778 if (ValueListCell
== NULL
)
2780 DPRINT("ValueListCell is NULL\n");
2781 return STATUS_UNSUCCESSFUL
;
2784 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2786 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2788 CurValueCell
= CmiGetCell (RegistryHive
,
2789 ValueListCell
->ValueOffset
[i
],
2791 if (CurValueCell
== NULL
)
2793 DPRINT("CmiGetBlock() failed\n");
2794 return STATUS_UNSUCCESSFUL
;
2797 if ((CurValueCell
!= NULL
) &&
2798 CmiComparePackedNames(ValueName
,
2800 CurValueCell
->NameSize
,
2801 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2803 *ValueCell
= CurValueCell
;
2804 if (ValueCellOffset
!= NULL
)
2805 *ValueCellOffset
= ValueListCell
->ValueOffset
[i
];
2806 //DPRINT("Found value %s\n", ValueName);
2807 return STATUS_SUCCESS
;
2811 return STATUS_OBJECT_NAME_NOT_FOUND
;
2816 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2817 IN PKEY_CELL KeyCell
,
2819 OUT PVALUE_CELL
*ValueCell
)
2821 PVALUE_LIST_CELL ValueListCell
;
2822 PVALUE_CELL CurValueCell
;
2826 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2828 return STATUS_NO_MORE_ENTRIES
;
2831 if (Index
>= KeyCell
->NumberOfValues
)
2833 return STATUS_NO_MORE_ENTRIES
;
2837 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2838 if (ValueListCell
== NULL
)
2840 DPRINT("CmiGetBlock() failed\n");
2841 return STATUS_UNSUCCESSFUL
;
2844 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2847 CurValueCell
= CmiGetCell (RegistryHive
,
2848 ValueListCell
->ValueOffset
[Index
],
2850 if (CurValueCell
== NULL
)
2852 DPRINT("CmiGetBlock() failed\n");
2853 return STATUS_UNSUCCESSFUL
;
2856 *ValueCell
= CurValueCell
;
2858 return STATUS_SUCCESS
;
2863 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2864 IN PKEY_CELL KeyCell
,
2865 IN BLOCK_OFFSET KeyCellOffset
,
2866 IN PUNICODE_STRING ValueName
,
2867 OUT PVALUE_CELL
*pValueCell
,
2868 OUT BLOCK_OFFSET
*pValueCellOffset
)
2870 PVALUE_LIST_CELL NewValueListCell
;
2871 PVALUE_LIST_CELL ValueListCell
;
2872 PVALUE_CELL NewValueCell
;
2873 BLOCK_OFFSET NewValueListCellOffset
;
2874 BLOCK_OFFSET ValueListCellOffset
;
2875 BLOCK_OFFSET NewValueCellOffset
;
2879 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG
)KeyCell
->ValueListOffset
);
2881 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2882 if (ValueListCell
== NULL
)
2884 CellSize
= sizeof(VALUE_LIST_CELL
) +
2885 (3 * sizeof(BLOCK_OFFSET
));
2886 Status
= CmiAllocateCell (RegistryHive
,
2888 (PVOID
) &ValueListCell
,
2889 &ValueListCellOffset
);
2890 if (!NT_SUCCESS(Status
))
2895 KeyCell
->ValueListOffset
= ValueListCellOffset
;
2896 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2897 CmiMarkBlockDirty(RegistryHive
, ValueListCellOffset
);
2899 else if (KeyCell
->NumberOfValues
>=
2900 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
)))
2903 CellSize
= sizeof(VALUE_LIST_CELL
) +
2904 ((KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) * sizeof(BLOCK_OFFSET
));
2906 CellSize
= 2 * (ULONG
)ABS_VALUE(ValueListCell
->CellSize
);
2907 Status
= CmiAllocateCell (RegistryHive
,
2909 (PVOID
) &NewValueListCell
,
2910 &NewValueListCellOffset
);
2911 if (!NT_SUCCESS(Status
))
2916 RtlCopyMemory(&NewValueListCell
->ValueOffset
[0],
2917 &ValueListCell
->ValueOffset
[0],
2918 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2919 CmiDestroyCell (RegistryHive
, ValueListCell
, KeyCell
->ValueListOffset
);
2920 CmiMarkBlockDirty (RegistryHive
, KeyCell
->ValueListOffset
);
2922 KeyCell
->ValueListOffset
= NewValueListCellOffset
;
2923 ValueListCell
= NewValueListCell
;
2924 CmiMarkBlockDirty (RegistryHive
, KeyCellOffset
);
2925 CmiMarkBlockDirty (RegistryHive
, NewValueListCellOffset
);
2928 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2929 KeyCell
->NumberOfValues
,
2930 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2931 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
),
2932 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
));
2934 Status
= CmiAllocateValueCell(RegistryHive
,
2936 &NewValueCellOffset
,
2938 if (!NT_SUCCESS(Status
))
2943 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = NewValueCellOffset
;
2944 KeyCell
->NumberOfValues
++;
2946 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2947 CmiMarkBlockDirty(RegistryHive
, KeyCell
->ValueListOffset
);
2948 CmiMarkBlockDirty(RegistryHive
, NewValueCellOffset
);
2950 *pValueCell
= NewValueCell
;
2951 *pValueCellOffset
= NewValueCellOffset
;
2953 return STATUS_SUCCESS
;
2958 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2959 IN PKEY_CELL KeyCell
,
2960 IN BLOCK_OFFSET KeyCellOffset
,
2961 IN PUNICODE_STRING ValueName
)
2963 PVALUE_LIST_CELL ValueListCell
;
2964 PVALUE_CELL CurValueCell
;
2968 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2969 if (ValueListCell
== NULL
)
2971 DPRINT1("CmiGetBlock() failed\n");
2972 return STATUS_SUCCESS
;
2975 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2977 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2979 CurValueCell
= CmiGetCell (RegistryHive
, ValueListCell
->ValueOffset
[i
], NULL
);
2980 if (CurValueCell
== NULL
)
2982 DPRINT1("CmiGetBlock() failed\n");
2983 return STATUS_UNSUCCESSFUL
;
2986 if (CmiComparePackedNames(ValueName
,
2988 CurValueCell
->NameSize
,
2989 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2991 Status
= CmiDestroyValueCell(RegistryHive
,
2993 ValueListCell
->ValueOffset
[i
]);
2994 if (CurValueCell
== NULL
)
2996 DPRINT1("CmiDestroyValueCell() failed\n");
3000 if (i
< (KeyCell
->NumberOfValues
- 1))
3002 RtlMoveMemory(&ValueListCell
->ValueOffset
[i
],
3003 &ValueListCell
->ValueOffset
[i
+ 1],
3004 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
3006 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
- 1] = 0;
3009 KeyCell
->NumberOfValues
--;
3011 if (KeyCell
->NumberOfValues
== 0)
3013 CmiDestroyCell(RegistryHive
,
3015 KeyCell
->ValueListOffset
);
3016 KeyCell
->ValueListOffset
= -1;
3020 CmiMarkBlockDirty(RegistryHive
,
3021 KeyCell
->ValueListOffset
);
3024 CmiMarkBlockDirty(RegistryHive
,
3027 return STATUS_SUCCESS
;
3031 DPRINT("Couldn't find the desired value\n");
3033 return STATUS_OBJECT_NAME_NOT_FOUND
;
3038 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive
,
3039 OUT PHASH_TABLE_CELL
*HashBlock
,
3040 OUT BLOCK_OFFSET
*HBOffset
,
3041 IN ULONG SubKeyCount
)
3043 PHASH_TABLE_CELL NewHashBlock
;
3047 Status
= STATUS_SUCCESS
;
3049 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
3050 (SubKeyCount
* sizeof(HASH_RECORD
));
3051 Status
= CmiAllocateCell (RegistryHive
,
3053 (PVOID
*) &NewHashBlock
,
3056 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
3058 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3062 assert(SubKeyCount
<= 0xffff); /* should really be USHORT_MAX or similar */
3063 NewHashBlock
->Id
= REG_HASH_TABLE_CELL_ID
;
3064 NewHashBlock
->HashTableSize
= (USHORT
)SubKeyCount
;
3065 *HashBlock
= NewHashBlock
;
3073 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
3074 PHASH_TABLE_CELL HashBlock
,
3077 BLOCK_OFFSET KeyOffset
;
3080 if (HashBlock
== NULL
)
3083 if (IsPointerHive(RegistryHive
))
3085 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
3089 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
3090 KeyCell
= CmiGetCell (RegistryHive
, KeyOffset
, NULL
);
3098 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
3099 PHASH_TABLE_CELL HashCell
,
3100 BLOCK_OFFSET HashCellOffset
,
3101 PKEY_CELL NewKeyCell
,
3102 BLOCK_OFFSET NKBOffset
)
3106 for (i
= 0; i
< HashCell
->HashTableSize
; i
++)
3108 if (HashCell
->Table
[i
].KeyOffset
== 0)
3110 HashCell
->Table
[i
].KeyOffset
= NKBOffset
;
3111 HashCell
->Table
[i
].HashValue
= 0;
3112 if (NewKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3114 RtlCopyMemory(&HashCell
->Table
[i
].HashValue
,
3116 min(NewKeyCell
->NameSize
, sizeof(ULONG
)));
3118 CmiMarkBlockDirty(RegistryHive
, HashCellOffset
);
3119 return STATUS_SUCCESS
;
3123 return STATUS_UNSUCCESSFUL
;
3128 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
3129 PHASH_TABLE_CELL HashBlock
,
3130 BLOCK_OFFSET NKBOffset
)
3134 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3136 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
3138 HashBlock
->Table
[i
].KeyOffset
= 0;
3139 HashBlock
->Table
[i
].HashValue
= 0;
3140 return STATUS_SUCCESS
;
3144 return STATUS_UNSUCCESSFUL
;
3149 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
3150 PVALUE_CELL
*ValueCell
,
3151 BLOCK_OFFSET
*VBOffset
,
3152 IN PUNICODE_STRING ValueName
)
3154 PVALUE_CELL NewValueCell
;
3160 Status
= STATUS_SUCCESS
;
3162 NameSize
= CmiGetPackedNameLength(ValueName
,
3165 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
3167 Status
= CmiAllocateCell (RegistryHive
,
3168 sizeof(VALUE_CELL
) + NameSize
,
3169 (PVOID
*) &NewValueCell
,
3171 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
3173 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3177 assert(NameSize
<= 0xffff); /* should really be USHORT_MAX or similar */
3178 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
3179 NewValueCell
->NameSize
= (USHORT
)NameSize
;
3182 /* Pack the value name */
3183 for (i
= 0; i
< NameSize
; i
++)
3184 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
3185 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
3189 /* Copy the value name */
3190 RtlCopyMemory(NewValueCell
->Name
,
3193 NewValueCell
->Flags
= 0;
3195 NewValueCell
->DataType
= 0;
3196 NewValueCell
->DataSize
= 0;
3197 NewValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
3198 *ValueCell
= NewValueCell
;
3206 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
3207 PVALUE_CELL ValueCell
,
3208 BLOCK_OFFSET ValueCellOffset
)
3214 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n",
3215 ValueCell
, ValueCellOffset
);
3217 VERIFY_VALUE_CELL(ValueCell
);
3219 /* Destroy the data cell */
3220 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
3222 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, &Bin
);
3223 if (DataCell
== NULL
)
3225 DPRINT("CmiGetCell() failed\n");
3226 return STATUS_UNSUCCESSFUL
;
3229 Status
= CmiDestroyCell (RegistryHive
, DataCell
, ValueCell
->DataOffset
);
3230 if (!NT_SUCCESS(Status
))
3235 /* Update time of heap */
3236 if (!IsNoFileHive(RegistryHive
))
3237 NtQuerySystemTime(&Bin
->DateModified
);
3240 /* Destroy the value cell */
3241 Status
= CmiDestroyCell (RegistryHive
, ValueCell
, ValueCellOffset
);
3243 /* Update time of heap */
3244 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, ValueCellOffset
, &Bin
))
3246 NtQuerySystemTime(&Bin
->DateModified
);
3254 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
3257 BLOCK_OFFSET
*NewBlockOffset
)
3259 PBLOCK_LIST_ENTRY BlockList
;
3260 PCELL_HEADER tmpBlock
;
3265 DPRINT ("CmiAddBin (BlockCount %lu)\n", BlockCount
);
3267 BinSize
= BlockCount
* REG_BLOCK_SIZE
;
3268 tmpBin
= ExAllocatePool(PagedPool
, BinSize
);
3271 return STATUS_INSUFFICIENT_RESOURCES
;
3273 RtlZeroMemory (tmpBin
,
3276 tmpBin
->HeaderId
= REG_BIN_ID
;
3277 tmpBin
->BinOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
3278 RegistryHive
->FileSize
+= BinSize
;
3279 tmpBin
->BinSize
= BinSize
;
3280 tmpBin
->Unused1
= 0;
3281 NtQuerySystemTime(&tmpBin
->DateModified
);
3282 tmpBin
->Unused2
= 0;
3284 DPRINT (" BinOffset %lx BinSize %lx\n", tmpBin
->BinOffset
,tmpBin
->BinSize
);
3286 /* Allocate new block list */
3287 BlockList
= ExAllocatePool(NonPagedPool
,
3288 sizeof(BLOCK_LIST_ENTRY
) * (RegistryHive
->BlockListSize
+ BlockCount
));
3289 if (BlockList
== NULL
)
3292 return STATUS_INSUFFICIENT_RESOURCES
;
3295 if (RegistryHive
->BlockListSize
> 0)
3297 RtlCopyMemory (BlockList
,
3298 RegistryHive
->BlockList
,
3299 sizeof(BLOCK_LIST_ENTRY
) * RegistryHive
->BlockListSize
);
3300 ExFreePool(RegistryHive
->BlockList
);
3303 RegistryHive
->BlockList
= BlockList
;
3304 for (i
= 0; i
< BlockCount
; i
++)
3306 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Block
=
3307 (PVOID
)((ULONG_PTR
)tmpBin
+ (i
* REG_BLOCK_SIZE
));
3308 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Bin
= tmpBin
;
3310 RegistryHive
->BlockListSize
+= BlockCount
;
3312 /* Initialize a free block in this heap : */
3313 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
3314 tmpBlock
->CellSize
= (BinSize
- REG_HBIN_DATA_OFFSET
);
3316 /* Grow bitmap if necessary */
3317 if (IsNoFileHive(RegistryHive
) &&
3318 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
3320 PULONG BitmapBuffer
;
3323 DPRINT("Grow hive bitmap\n");
3325 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3326 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
3327 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
3328 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
3329 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
3331 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
3332 RtlCopyMemory(BitmapBuffer
,
3333 RegistryHive
->DirtyBitMap
.Buffer
,
3334 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
3335 ExFreePool(RegistryHive
->BitmapBuffer
);
3336 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
3337 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
3338 RegistryHive
->BitmapBuffer
,
3342 *NewBlock
= (PVOID
) tmpBlock
;
3345 *NewBlockOffset
= tmpBin
->BinOffset
+ REG_HBIN_DATA_OFFSET
;
3347 /* Mark new bin dirty */
3348 CmiMarkBinDirty(RegistryHive
,
3351 return STATUS_SUCCESS
;
3356 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
3359 BLOCK_OFFSET
*CellOffset
)
3361 PCELL_HEADER NewCell
;
3367 /* Round to 16 bytes multiple */
3368 CellSize
= ROUND_UP(CellSize
, 16);
3370 /* Handle volatile hives first */
3371 if (IsPointerHive(RegistryHive
))
3373 NewCell
= ExAllocatePool(NonPagedPool
, CellSize
);
3374 if (NewCell
== NULL
)
3376 return STATUS_INSUFFICIENT_RESOURCES
;
3379 RtlZeroMemory (NewCell
,
3381 NewCell
->CellSize
= -CellSize
;
3384 if (CellOffset
!= NULL
)
3385 *CellOffset
= (BLOCK_OFFSET
) NewCell
;
3389 /* first search in free blocks */
3391 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3393 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
3395 NewCell
= RegistryHive
->FreeList
[i
];
3396 if (CellOffset
!= NULL
)
3397 *CellOffset
= RegistryHive
->FreeListOffset
[i
];
3399 /* Update time of heap */
3400 Temp
= CmiGetCell (RegistryHive
,
3401 RegistryHive
->FreeListOffset
[i
],
3405 DPRINT("CmiGetBlock() failed\n");
3406 return STATUS_UNSUCCESSFUL
;
3409 NtQuerySystemTime(&Bin
->DateModified
);
3410 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
3412 if ((i
+ 1) < RegistryHive
->FreeListSize
)
3414 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
3415 &RegistryHive
->FreeList
[i
+ 1],
3416 sizeof(RegistryHive
->FreeList
[0])
3417 * (RegistryHive
->FreeListSize
- i
- 1));
3418 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
3419 &RegistryHive
->FreeListOffset
[i
+ 1],
3420 sizeof(RegistryHive
->FreeListOffset
[0])
3421 * (RegistryHive
->FreeListSize
- i
- 1));
3423 RegistryHive
->FreeListSize
--;
3428 /* Need to extend hive file : */
3429 if (NewCell
== NULL
)
3432 Status
= CmiAddBin(RegistryHive
,
3433 ((CellSize
+ sizeof(HBIN
) - 1) / REG_BLOCK_SIZE
) + 1,
3436 if (!NT_SUCCESS(Status
))
3442 /* Split the block in two parts */
3443 if (NewCell
->CellSize
> CellSize
)
3445 NewCell
= (PCELL_HEADER
) ((ULONG_PTR
) NewCell
+ CellSize
);
3446 NewCell
->CellSize
= ((PCELL_HEADER
) (*Cell
))->CellSize
- CellSize
;
3447 CmiAddFree(RegistryHive
,
3449 *CellOffset
+ CellSize
,
3451 CmiMarkBlockDirty(RegistryHive
,
3452 *CellOffset
+ CellSize
);
3454 else if (NewCell
->CellSize
< CellSize
)
3456 return STATUS_UNSUCCESSFUL
;
3459 RtlZeroMemory(*Cell
,
3461 ((PCELL_HEADER
) (*Cell
))->CellSize
= -CellSize
;
3464 return STATUS_SUCCESS
;
3469 CmiDestroyCell (PREGISTRY_HIVE RegistryHive
,
3471 BLOCK_OFFSET CellOffset
)
3476 Status
= STATUS_SUCCESS
;
3478 if (IsPointerHive(RegistryHive
))
3484 PCELL_HEADER pFree
= Cell
;
3486 if (pFree
->CellSize
< 0)
3487 pFree
->CellSize
= -pFree
->CellSize
;
3489 /* Clear block (except the block size) */
3490 RtlZeroMemory(((char*)pFree
) + sizeof(ULONG
),
3491 pFree
->CellSize
- sizeof(ULONG
));
3493 /* Add block to the list of free blocks */
3494 CmiAddFree(RegistryHive
, Cell
, CellOffset
, TRUE
);
3496 /* Update time of heap */
3497 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, CellOffset
,&pBin
))
3498 NtQuerySystemTime(&pBin
->DateModified
);
3500 CmiMarkBlockDirty(RegistryHive
, CellOffset
);
3508 CmiGetCell (PREGISTRY_HIVE RegistryHive
,
3509 BLOCK_OFFSET CellOffset
,
3519 if (CellOffset
== (BLOCK_OFFSET
)-1)
3524 if (IsPointerHive (RegistryHive
))
3526 return (PVOID
)CellOffset
;
3529 if (CellOffset
> RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
)
3531 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3532 CellOffset
, RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
);
3536 pBin
= RegistryHive
->BlockList
[CellOffset
/ REG_BLOCK_SIZE
].Bin
;
3547 return((PVOID
)((ULONG_PTR
)pBin
+ (CellOffset
- pBin
->BinOffset
)));
3552 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3553 PCELL_HEADER FreeBlock
,
3554 BLOCK_OFFSET FreeOffset
)
3556 BLOCK_OFFSET BlockOffset
;
3557 BLOCK_OFFSET BinOffset
;
3563 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3564 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3566 CmiGetCell (RegistryHive
,
3569 DPRINT("Bin %p\n", Bin
);
3573 BinOffset
= Bin
->BinOffset
;
3574 BinSize
= Bin
->BinSize
;
3575 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3577 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3579 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3580 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3581 if (BlockOffset
> BinOffset
&&
3582 BlockOffset
< BinOffset
+ BinSize
)
3584 DPRINT("Free block: Offset %lx Size %lx\n",
3585 BlockOffset
, BlockSize
);
3587 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3588 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3589 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3591 DPRINT("Merge current block with previous and next block\n");
3593 RegistryHive
->FreeList
[i
]->CellSize
+=
3594 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3596 FreeBlock
->CellSize
= 0;
3597 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3600 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3602 RtlMoveMemory(&RegistryHive
->FreeList
[i
+ 1],
3603 &RegistryHive
->FreeList
[i
+ 2],
3604 sizeof(RegistryHive
->FreeList
[0])
3605 * (RegistryHive
->FreeListSize
- i
- 2));
3606 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3607 &RegistryHive
->FreeListOffset
[i
+ 2],
3608 sizeof(RegistryHive
->FreeListOffset
[0])
3609 * (RegistryHive
->FreeListSize
- i
- 2));
3611 RegistryHive
->FreeListSize
--;
3613 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3617 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3619 DPRINT("Merge current block with previous block\n");
3621 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3622 FreeBlock
->CellSize
= 0;
3624 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3628 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3630 DPRINT("Merge current block with next block\n");
3632 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3633 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3634 RegistryHive
->FreeList
[i
] = FreeBlock
;
3635 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3637 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3649 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3650 PCELL_HEADER FreeBlock
,
3651 BLOCK_OFFSET FreeOffset
,
3652 BOOLEAN MergeFreeBlocks
)
3654 PCELL_HEADER
*tmpList
;
3655 BLOCK_OFFSET
*tmpListOffset
;
3660 assert(RegistryHive
);
3663 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3664 FreeBlock
, FreeOffset
);
3666 /* Merge free blocks */
3667 if (MergeFreeBlocks
== TRUE
)
3669 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3670 return(STATUS_SUCCESS
);
3673 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3675 tmpList
= ExAllocatePool(PagedPool
,
3676 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3677 if (tmpList
== NULL
)
3678 return STATUS_INSUFFICIENT_RESOURCES
;
3680 tmpListOffset
= ExAllocatePool(PagedPool
,
3681 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3683 if (tmpListOffset
== NULL
)
3685 ExFreePool(tmpList
);
3686 return STATUS_INSUFFICIENT_RESOURCES
;
3689 if (RegistryHive
->FreeListMax
)
3691 RtlMoveMemory(tmpList
,
3692 RegistryHive
->FreeList
,
3693 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3694 RtlMoveMemory(tmpListOffset
,
3695 RegistryHive
->FreeListOffset
,
3696 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3697 ExFreePool(RegistryHive
->FreeList
);
3698 ExFreePool(RegistryHive
->FreeListOffset
);
3700 RegistryHive
->FreeList
= tmpList
;
3701 RegistryHive
->FreeListOffset
= tmpListOffset
;
3702 RegistryHive
->FreeListMax
+= 32;
3705 /* Add new offset to free list, maintaining list in ascending order */
3706 if ((RegistryHive
->FreeListSize
== 0)
3707 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3709 /* Add to end of list */
3710 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3711 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3713 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3715 /* Add to begin of list */
3716 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3717 &RegistryHive
->FreeList
[0],
3718 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3719 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3720 &RegistryHive
->FreeListOffset
[0],
3721 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3722 RegistryHive
->FreeList
[0] = FreeBlock
;
3723 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3724 RegistryHive
->FreeListSize
++;
3728 /* Search where to insert */
3730 maxInd
= RegistryHive
->FreeListSize
- 1;
3731 while ((maxInd
- minInd
) > 1)
3733 medInd
= (minInd
+ maxInd
) / 2;
3734 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3740 /* Insert before maxInd */
3741 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3742 &RegistryHive
->FreeList
[maxInd
],
3743 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3744 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3745 &RegistryHive
->FreeListOffset
[maxInd
],
3746 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3747 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3748 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3749 RegistryHive
->FreeListSize
++;
3752 return STATUS_SUCCESS
;
3757 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3758 BLOCK_OFFSET BlockOffset
)
3765 if (IsNoFileHive(RegistryHive
))
3768 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3770 BlockNumber
= (ULONG
)BlockOffset
/ REG_BLOCK_SIZE
;
3772 Cell
= CmiGetCell (RegistryHive
,
3776 CellSize
= Cell
->CellSize
;
3778 CellSize
= -CellSize
;
3780 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, REG_BLOCK_SIZE
) -
3781 ROUND_DOWN(BlockOffset
, REG_BLOCK_SIZE
)) / REG_BLOCK_SIZE
;
3783 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3786 (Cell
->CellSize
< 0) ? "used" : "free",
3789 RegistryHive
->HiveDirty
= TRUE
;
3790 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3797 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3798 BLOCK_OFFSET BinOffset
)
3804 if (IsNoFileHive(RegistryHive
))
3807 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3809 BlockNumber
= (ULONG
)BinOffset
/ REG_BLOCK_SIZE
;
3811 Bin
= RegistryHive
->BlockList
[BlockNumber
].Bin
;
3813 BlockCount
= Bin
->BinSize
/ REG_BLOCK_SIZE
;
3815 DPRINT(" BlockNumber %lu BinSize %lu BlockCount %lu\n",
3820 RegistryHive
->HiveDirty
= TRUE
;
3821 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3828 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3829 OUT PBOOLEAN Packable
)
3833 if (Packable
!= NULL
)
3836 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3838 if (Name
->Buffer
[i
] & 0xFF00)
3840 if (Packable
!= NULL
)
3842 return Name
->Length
;
3846 return (Name
->Length
/ sizeof(WCHAR
));
3851 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3852 IN PCHAR NameBuffer
,
3853 IN USHORT NameBufferSize
,
3854 IN BOOLEAN NamePacked
)
3859 if (NamePacked
== TRUE
)
3861 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3864 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3866 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3872 if (Name
->Length
!= NameBufferSize
)
3875 UNameBuffer
= (PWCHAR
)NameBuffer
;
3877 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3879 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3889 CmiCopyPackedName(PWCHAR NameBuffer
,
3890 PCHAR PackedNameBuffer
,
3891 ULONG PackedNameSize
)
3895 for (i
= 0; i
< PackedNameSize
; i
++)
3896 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];
3901 CmiCompareHash(PUNICODE_STRING KeyName
,
3906 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3907 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3908 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3909 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3911 return (strncmp(Buffer
, HashString
, 4) == 0);
3916 CmiCompareHashI(PUNICODE_STRING KeyName
,
3921 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3922 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3923 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3924 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3926 return (_strnicmp(Buffer
, HashString
, 4) == 0);
3931 CmiCompareKeyNames(PUNICODE_STRING KeyName
,
3937 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3939 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3941 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3944 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3946 if (KeyName
->Buffer
[i
] != (WCHAR
)KeyCell
->Name
[i
])
3952 if (KeyName
->Length
!= KeyCell
->NameSize
)
3955 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3956 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3958 if (KeyName
->Buffer
[i
] != UnicodeName
[i
])
3968 CmiCompareKeyNamesI(PUNICODE_STRING KeyName
,
3974 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3976 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3978 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3981 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3983 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3984 RtlUpcaseUnicodeChar((WCHAR
)KeyCell
->Name
[i
]))
3990 if (KeyName
->Length
!= KeyCell
->NameSize
)
3993 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3994 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3996 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3997 RtlUpcaseUnicodeChar(UnicodeName
[i
]))
4007 CmiCopyKey (PREGISTRY_HIVE DstHive
,
4008 PKEY_CELL DstKeyCell
,
4009 PREGISTRY_HIVE SrcHive
,
4010 PKEY_CELL SrcKeyCell
)
4012 PKEY_CELL NewKeyCell
;
4013 ULONG NewKeyCellSize
;
4014 BLOCK_OFFSET NewKeyCellOffset
;
4015 PHASH_TABLE_CELL NewHashTableCell
;
4016 ULONG NewHashTableSize
;
4017 BLOCK_OFFSET NewHashTableOffset
;
4021 DPRINT ("CmiCopyKey() called\n");
4023 if (DstKeyCell
== NULL
)
4025 /* Allocate and copy key cell */
4026 NewKeyCellSize
= sizeof(KEY_CELL
) + SrcKeyCell
->NameSize
;
4027 Status
= CmiAllocateCell (DstHive
,
4029 (PVOID
) &NewKeyCell
,
4031 if (!NT_SUCCESS(Status
))
4033 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4036 if (NewKeyCell
== NULL
)
4038 DPRINT1 ("Failed to allocate a key cell\n");
4039 return STATUS_INSUFFICIENT_RESOURCES
;
4042 RtlCopyMemory (NewKeyCell
,
4046 DstHive
->HiveHeader
->RootKeyOffset
= NewKeyCellOffset
;
4048 /* Copy class name */
4049 if (SrcKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4051 PDATA_CELL SrcClassNameCell
;
4052 PDATA_CELL NewClassNameCell
;
4053 BLOCK_OFFSET NewClassNameOffset
;
4055 SrcClassNameCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ClassNameOffset
, NULL
),
4057 NewKeyCell
->ClassSize
= SrcKeyCell
->ClassSize
;
4058 Status
= CmiAllocateCell (DstHive
,
4059 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
4060 (PVOID
)&NewClassNameCell
,
4061 &NewClassNameOffset
);
4062 if (!NT_SUCCESS(Status
))
4064 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4068 RtlCopyMemory (NewClassNameCell
,
4070 NewKeyCell
->ClassSize
);
4071 NewKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4076 NewKeyCell
= DstKeyCell
;
4079 /* Allocate hash table */
4080 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4082 NewHashTableSize
= ROUND_UP(SrcKeyCell
->NumberOfSubKeys
+ 1, 4) - 1;
4083 Status
= CmiAllocateHashTableCell (DstHive
,
4085 &NewHashTableOffset
,
4087 if (!NT_SUCCESS(Status
))
4089 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status
);
4092 NewKeyCell
->HashTableOffset
= NewHashTableOffset
;
4095 /* Allocate and copy value list and values */
4096 if (SrcKeyCell
->NumberOfValues
!= 0)
4098 PVALUE_LIST_CELL NewValueListCell
;
4099 PVALUE_LIST_CELL SrcValueListCell
;
4100 PVALUE_CELL NewValueCell
;
4101 PVALUE_CELL SrcValueCell
;
4102 PDATA_CELL SrcValueDataCell
;
4103 PDATA_CELL NewValueDataCell
;
4104 BLOCK_OFFSET ValueCellOffset
;
4105 BLOCK_OFFSET ValueDataCellOffset
;
4106 ULONG NewValueListCellSize
;
4107 ULONG NewValueCellSize
;
4110 NewValueListCellSize
=
4111 ROUND_UP(SrcKeyCell
->NumberOfValues
, 4) * sizeof(BLOCK_OFFSET
);
4112 Status
= CmiAllocateCell (DstHive
,
4113 NewValueListCellSize
,
4114 (PVOID
)&NewValueListCell
,
4115 &NewKeyCell
->ValueListOffset
);
4116 if (!NT_SUCCESS(Status
))
4118 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4122 RtlZeroMemory (NewValueListCell
,
4123 NewValueListCellSize
);
4126 SrcValueListCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ValueListOffset
, NULL
);
4127 for (i
= 0; i
< SrcKeyCell
->NumberOfValues
; i
++)
4129 /* Copy value cell */
4130 SrcValueCell
= CmiGetCell (SrcHive
, SrcValueListCell
->ValueOffset
[i
], NULL
);
4132 NewValueCellSize
= sizeof(VALUE_CELL
) + SrcValueCell
->NameSize
;
4133 Status
= CmiAllocateCell (DstHive
,
4135 (PVOID
*) &NewValueCell
,
4137 if (!NT_SUCCESS(Status
))
4139 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4143 NewValueListCell
->ValueOffset
[i
] = ValueCellOffset
;
4144 RtlCopyMemory (NewValueCell
,
4148 /* Copy value data cell */
4149 if (SrcValueCell
->DataSize
> (LONG
) sizeof(PVOID
))
4151 SrcValueDataCell
= CmiGetCell (SrcHive
, SrcValueCell
->DataOffset
, NULL
);
4153 Status
= CmiAllocateCell (DstHive
,
4154 sizeof(CELL_HEADER
) + SrcValueCell
->DataSize
,
4155 (PVOID
*) &NewValueDataCell
,
4156 &ValueDataCellOffset
);
4157 if (!NT_SUCCESS(Status
))
4159 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4162 RtlCopyMemory (NewValueDataCell
,
4164 SrcValueCell
->DataSize
);
4165 NewValueCell
->DataOffset
= ValueDataCellOffset
;
4171 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4173 PHASH_TABLE_CELL SrcHashTableCell
;
4174 PKEY_CELL SrcSubKeyCell
;
4175 PKEY_CELL NewSubKeyCell
;
4176 ULONG NewSubKeyCellSize
;
4177 BLOCK_OFFSET NewSubKeyCellOffset
;
4178 PHASH_RECORD SrcHashRecord
;
4180 SrcHashTableCell
= CmiGetCell (SrcHive
,
4181 SrcKeyCell
->HashTableOffset
,
4184 for (i
= 0; i
< SrcKeyCell
->NumberOfSubKeys
; i
++)
4186 SrcHashRecord
= &SrcHashTableCell
->Table
[i
];
4187 SrcSubKeyCell
= CmiGetCell (SrcHive
, SrcHashRecord
->KeyOffset
, NULL
);
4189 /* Allocate and copy key cell */
4190 NewSubKeyCellSize
= sizeof(KEY_CELL
) + SrcSubKeyCell
->NameSize
;
4191 Status
= CmiAllocateCell (DstHive
,
4193 (PVOID
)&NewSubKeyCell
,
4194 &NewSubKeyCellOffset
);
4195 if (!NT_SUCCESS(Status
))
4197 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4200 if (NewKeyCell
== NULL
)
4202 DPRINT1 ("Failed to allocate a sub key cell\n");
4203 return STATUS_INSUFFICIENT_RESOURCES
;
4206 NewHashTableCell
->Table
[i
].KeyOffset
= NewSubKeyCellOffset
;
4207 NewHashTableCell
->Table
[i
].HashValue
= SrcHashRecord
->HashValue
;
4209 RtlCopyMemory (NewSubKeyCell
,
4213 /* Copy class name */
4214 if (SrcSubKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4216 PDATA_CELL SrcClassNameCell
;
4217 PDATA_CELL NewClassNameCell
;
4218 BLOCK_OFFSET NewClassNameOffset
;
4220 SrcClassNameCell
= CmiGetCell (SrcHive
,
4221 SrcSubKeyCell
->ClassNameOffset
,
4224 NewSubKeyCell
->ClassSize
= SrcSubKeyCell
->ClassSize
;
4225 Status
= CmiAllocateCell (DstHive
,
4226 sizeof(CELL_HEADER
) + NewSubKeyCell
->ClassSize
,
4227 (PVOID
)&NewClassNameCell
,
4228 &NewClassNameOffset
);
4229 if (!NT_SUCCESS(Status
))
4231 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4235 NewSubKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4236 RtlCopyMemory (NewClassNameCell
,
4238 NewSubKeyCell
->ClassSize
);
4241 /* Copy subkey data and subkeys */
4242 Status
= CmiCopyKey (DstHive
,
4246 if (!NT_SUCCESS(Status
))
4248 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4254 return STATUS_SUCCESS
;
4259 CmiSaveTempHive (PREGISTRY_HIVE Hive
,
4262 IO_STATUS_BLOCK IoStatusBlock
;
4263 LARGE_INTEGER FileOffset
;
4268 DPRINT ("CmiSaveTempHive() called\n");
4270 Hive
->HiveHeader
->Checksum
= CmiCalcChecksum ((PULONG
)Hive
->HiveHeader
);
4272 /* Write hive block */
4273 FileOffset
.QuadPart
= (ULONGLONG
)0;
4274 Status
= NtWriteFile (FileHandle
,
4280 sizeof(HIVE_HEADER
),
4283 if (!NT_SUCCESS(Status
))
4285 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4289 DPRINT ("Saving %lu blocks\n", Hive
->BlockListSize
);
4290 for (BlockIndex
= 0; BlockIndex
< Hive
->BlockListSize
; BlockIndex
++)
4292 BlockPtr
= Hive
->BlockList
[BlockIndex
].Block
;
4293 DPRINT ("BlockPtr %p\n", BlockPtr
);
4295 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
4296 DPRINT ("File offset %I64x\n", FileOffset
.QuadPart
);
4298 /* Write hive block */
4299 Status
= NtWriteFile (FileHandle
,
4308 if (!NT_SUCCESS(Status
))
4310 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4315 Status
= NtFlushBuffersFile (FileHandle
,
4317 if (!NT_SUCCESS(Status
))
4319 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
4322 DPRINT ("CmiSaveTempHive() done\n");