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
;
1404 DPRINT("CmiStartLogUpdate() called\n");
1406 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1407 BufferSize
= sizeof(HIVE_HEADER
) +
1410 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1412 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1414 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
,
1418 DPRINT("ExAllocatePool() failed\n");
1419 return(STATUS_INSUFFICIENT_RESOURCES
);
1421 RtlZeroMemory (Buffer
,
1424 /* Open log file for writing */
1425 InitializeObjectAttributes(&ObjectAttributes
,
1426 &RegistryHive
->LogFileName
,
1427 OBJ_CASE_INSENSITIVE
,
1431 Status
= NtCreateFile(&FileHandle
,
1436 FILE_ATTRIBUTE_NORMAL
,
1439 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1442 if (!NT_SUCCESS(Status
))
1444 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1449 /* Update firt update counter and checksum */
1450 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1451 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1453 /* Copy hive header */
1454 RtlCopyMemory(Buffer
,
1455 RegistryHive
->HiveHeader
,
1456 sizeof(HIVE_HEADER
));
1457 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1464 RegistryHive
->DirtyBitMap
.Buffer
,
1467 /* Write hive block and block bitmap */
1468 FileOffset
.QuadPart
= (ULONGLONG
)0;
1469 Status
= NtWriteFile(FileHandle
,
1478 if (!NT_SUCCESS(Status
))
1480 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1481 NtClose(FileHandle
);
1487 /* Write dirty blocks */
1488 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1490 while (BlockIndex
< RegistryHive
->BlockListSize
)
1492 LastIndex
= BlockIndex
;
1493 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1496 if (BlockIndex
== (ULONG
)-1 || BlockIndex
< LastIndex
)
1498 DPRINT("No more set bits\n");
1499 Status
= STATUS_SUCCESS
;
1503 DPRINT("Block %lu is dirty\n", BlockIndex
);
1505 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1506 DPRINT("BlockPtr %p\n", BlockPtr
);
1507 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1509 /* Write hive block */
1510 Status
= NtWriteFile(FileHandle
,
1519 if (!NT_SUCCESS(Status
))
1521 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1522 NtClose(FileHandle
);
1527 FileOffset
.QuadPart
+= (ULONGLONG
)REG_BLOCK_SIZE
;
1530 /* Truncate log file */
1531 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1532 Status
= NtSetInformationFile(FileHandle
,
1535 sizeof(FILE_END_OF_FILE_INFORMATION
),
1536 FileEndOfFileInformation
);
1537 if (!NT_SUCCESS(Status
))
1539 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1540 NtClose(FileHandle
);
1544 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1545 Status
= NtSetInformationFile(FileHandle
,
1547 &FileAllocationInfo
,
1548 sizeof(FILE_ALLOCATION_INFORMATION
),
1549 FileAllocationInformation
);
1550 if (!NT_SUCCESS(Status
))
1552 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1553 NtClose(FileHandle
);
1557 /* Flush the log file */
1558 Status
= NtFlushBuffersFile(FileHandle
,
1560 if (!NT_SUCCESS(Status
))
1562 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1565 NtClose(FileHandle
);
1572 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1574 OBJECT_ATTRIBUTES ObjectAttributes
;
1575 IO_STATUS_BLOCK IoStatusBlock
;
1577 LARGE_INTEGER FileOffset
;
1584 DPRINT("CmiFinishLogUpdate() called\n");
1586 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1587 BufferSize
= sizeof(HIVE_HEADER
) +
1590 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1592 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1594 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1597 DPRINT("ExAllocatePool() failed\n");
1598 return(STATUS_INSUFFICIENT_RESOURCES
);
1601 /* Open log file for writing */
1602 InitializeObjectAttributes(&ObjectAttributes
,
1603 &RegistryHive
->LogFileName
,
1604 OBJ_CASE_INSENSITIVE
,
1608 Status
= NtCreateFile(&FileHandle
,
1613 FILE_ATTRIBUTE_NORMAL
,
1616 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1619 if (!NT_SUCCESS(Status
))
1621 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1626 /* Update first and second update counter and checksum */
1627 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1628 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1629 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1631 /* Copy hive header */
1632 RtlCopyMemory(Buffer
,
1633 RegistryHive
->HiveHeader
,
1634 sizeof(HIVE_HEADER
));
1635 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1637 /* Write empty block bitmap */
1645 /* Write hive block and block bitmap */
1646 FileOffset
.QuadPart
= (ULONGLONG
)0;
1647 Status
= NtWriteFile(FileHandle
,
1656 if (!NT_SUCCESS(Status
))
1658 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1659 NtClose(FileHandle
);
1666 /* Flush the log file */
1667 Status
= NtFlushBuffersFile(FileHandle
,
1669 if (!NT_SUCCESS(Status
))
1671 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1674 NtClose(FileHandle
);
1681 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1683 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1684 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1685 OBJECT_ATTRIBUTES ObjectAttributes
;
1686 IO_STATUS_BLOCK IoStatusBlock
;
1692 DPRINT("CmiCleanupLogUpdate() called\n");
1694 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1695 BufferSize
= sizeof(HIVE_HEADER
) +
1698 BufferSize
= ROUND_UP(BufferSize
, REG_BLOCK_SIZE
);
1700 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1702 /* Open log file for writing */
1703 InitializeObjectAttributes(&ObjectAttributes
,
1704 &RegistryHive
->LogFileName
,
1705 OBJ_CASE_INSENSITIVE
,
1709 Status
= NtCreateFile(&FileHandle
,
1714 FILE_ATTRIBUTE_NORMAL
,
1717 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1720 if (!NT_SUCCESS(Status
))
1722 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1726 /* Truncate log file */
1727 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1728 Status
= NtSetInformationFile(FileHandle
,
1731 sizeof(FILE_END_OF_FILE_INFORMATION
),
1732 FileEndOfFileInformation
);
1733 if (!NT_SUCCESS(Status
))
1735 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1736 NtClose(FileHandle
);
1740 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1741 Status
= NtSetInformationFile(FileHandle
,
1743 &FileAllocationInfo
,
1744 sizeof(FILE_ALLOCATION_INFORMATION
),
1745 FileAllocationInformation
);
1746 if (!NT_SUCCESS(Status
))
1748 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1749 NtClose(FileHandle
);
1753 /* Flush the log file */
1754 Status
= NtFlushBuffersFile(FileHandle
,
1756 if (!NT_SUCCESS(Status
))
1758 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1761 NtClose(FileHandle
);
1768 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1770 OBJECT_ATTRIBUTES ObjectAttributes
;
1771 IO_STATUS_BLOCK IoStatusBlock
;
1773 LARGE_INTEGER FileOffset
;
1779 DPRINT("CmiStartHiveUpdate() called\n");
1781 /* Open hive for writing */
1782 InitializeObjectAttributes(&ObjectAttributes
,
1783 &RegistryHive
->HiveFileName
,
1784 OBJ_CASE_INSENSITIVE
,
1788 Status
= NtCreateFile(&FileHandle
,
1793 FILE_ATTRIBUTE_NORMAL
,
1796 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1799 if (!NT_SUCCESS(Status
))
1801 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1805 /* Update firt update counter and checksum */
1806 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1807 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1809 /* Write hive block */
1810 FileOffset
.QuadPart
= (ULONGLONG
)0;
1811 Status
= NtWriteFile(FileHandle
,
1816 RegistryHive
->HiveHeader
,
1817 sizeof(HIVE_HEADER
),
1820 if (!NT_SUCCESS(Status
))
1822 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1823 NtClose(FileHandle
);
1828 while (BlockIndex
< RegistryHive
->BlockListSize
)
1830 LastIndex
= BlockIndex
;
1831 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1834 if (BlockIndex
== (ULONG
)-1 || BlockIndex
< LastIndex
)
1836 DPRINT("No more set bits\n");
1837 Status
= STATUS_SUCCESS
;
1841 DPRINT("Block %lu is dirty\n", BlockIndex
);
1843 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
].Block
;
1844 DPRINT(" BlockPtr %p\n", BlockPtr
);
1846 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
1847 DPRINT(" File offset %I64x\n", FileOffset
.QuadPart
);
1849 /* Write hive block */
1850 Status
= NtWriteFile(FileHandle
,
1859 if (!NT_SUCCESS(Status
))
1861 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1862 NtClose(FileHandle
);
1869 Status
= NtFlushBuffersFile(FileHandle
,
1871 if (!NT_SUCCESS(Status
))
1873 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1876 NtClose(FileHandle
);
1883 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1885 OBJECT_ATTRIBUTES ObjectAttributes
;
1886 IO_STATUS_BLOCK IoStatusBlock
;
1887 LARGE_INTEGER FileOffset
;
1891 DPRINT("CmiFinishHiveUpdate() called\n");
1893 InitializeObjectAttributes(&ObjectAttributes
,
1894 &RegistryHive
->HiveFileName
,
1895 OBJ_CASE_INSENSITIVE
,
1899 Status
= NtCreateFile(&FileHandle
,
1904 FILE_ATTRIBUTE_NORMAL
,
1907 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1910 if (!NT_SUCCESS(Status
))
1912 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1916 /* Update second update counter and checksum */
1917 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1918 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1919 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1921 /* Write hive block */
1922 FileOffset
.QuadPart
= (ULONGLONG
)0;
1923 Status
= NtWriteFile(FileHandle
,
1928 RegistryHive
->HiveHeader
,
1929 sizeof(HIVE_HEADER
),
1932 if (!NT_SUCCESS(Status
))
1934 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1935 NtClose(FileHandle
);
1939 Status
= NtFlushBuffersFile(FileHandle
,
1941 if (!NT_SUCCESS(Status
))
1943 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1946 NtClose(FileHandle
);
1953 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1957 DPRINT("CmiFlushRegistryHive() called\n");
1959 if (RegistryHive
->HiveDirty
== FALSE
)
1961 return(STATUS_SUCCESS
);
1964 DPRINT("Hive '%wZ' is dirty\n",
1965 &RegistryHive
->HiveFileName
);
1966 DPRINT("Log file: '%wZ'\n",
1967 &RegistryHive
->LogFileName
);
1969 /* Update hive header modification time */
1970 NtQuerySystemTime(&RegistryHive
->HiveHeader
->DateModified
);
1972 /* Start log update */
1973 Status
= CmiStartLogUpdate(RegistryHive
);
1974 if (!NT_SUCCESS(Status
))
1976 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1980 /* Finish log update */
1981 Status
= CmiFinishLogUpdate(RegistryHive
);
1982 if (!NT_SUCCESS(Status
))
1984 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1988 /* Start hive update */
1989 Status
= CmiStartHiveUpdate(RegistryHive
);
1990 if (!NT_SUCCESS(Status
))
1992 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1996 /* Finish the hive update */
1997 Status
= CmiFinishHiveUpdate(RegistryHive
);
1998 if (!NT_SUCCESS(Status
))
2000 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
2004 /* Cleanup log update */
2005 Status
= CmiCleanupLogUpdate(RegistryHive
);
2006 if (!NT_SUCCESS(Status
))
2008 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
2012 /* Increment hive update counter */
2013 RegistryHive
->UpdateCounter
++;
2015 /* Clear dirty bitmap and dirty flag */
2016 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
2017 RegistryHive
->HiveDirty
= FALSE
;
2019 DPRINT("CmiFlushRegistryHive() done\n");
2021 return(STATUS_SUCCESS
);
2026 CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject
)
2033 VERIFY_KEY_OBJECT(KeyObject
);
2035 KeyCell
= KeyObject
->KeyCell
;
2036 VERIFY_KEY_CELL(KeyCell
);
2038 SubKeyCount
= (KeyCell
== NULL
) ? 0 : KeyCell
->NumberOfSubKeys
;
2040 /* Search for volatile or 'foreign' keys */
2041 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2043 CurKey
= KeyObject
->SubKeys
[i
];
2044 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2045 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2056 CmiGetMaxNameLength(PKEY_OBJECT KeyObject
)
2058 PHASH_TABLE_CELL HashBlock
;
2060 PKEY_CELL CurSubKeyCell
;
2066 VERIFY_KEY_OBJECT(KeyObject
);
2068 KeyCell
= KeyObject
->KeyCell
;
2069 VERIFY_KEY_CELL(KeyCell
);
2072 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2073 KeyCell
->HashTableOffset
,
2075 if (HashBlock
== NULL
)
2077 DPRINT("CmiGetBlock() failed\n");
2081 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2083 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2085 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2086 HashBlock
->Table
[i
].KeyOffset
,
2088 if (CurSubKeyCell
== NULL
)
2090 DPRINT("CmiGetBlock() failed\n");
2094 NameSize
= CurSubKeyCell
->NameSize
;
2095 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2097 NameSize
*= sizeof(WCHAR
);
2100 if (NameSize
> MaxName
)
2108 DPRINT ("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2109 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2111 CurKey
= KeyObject
->SubKeys
[i
];
2112 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2113 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2115 CurSubKeyCell
= CurKey
->KeyCell
;
2116 if (CurSubKeyCell
== NULL
)
2118 DPRINT("CmiGetBlock() failed\n");
2122 if ((CurSubKeyCell
->Flags
& REG_KEY_ROOT_CELL
) == REG_KEY_ROOT_CELL
)
2124 /* Use name of the key object */
2125 NameSize
= CurKey
->Name
.Length
;
2129 /* Use name of the key cell */
2130 NameSize
= CurSubKeyCell
->NameSize
;
2131 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2133 NameSize
*= sizeof(WCHAR
);
2136 DPRINT ("NameSize %lu\n", NameSize
);
2138 if (NameSize
> MaxName
)
2145 DPRINT ("MaxName %lu\n", MaxName
);
2152 CmiGetMaxClassLength(PKEY_OBJECT KeyObject
)
2154 PHASH_TABLE_CELL HashBlock
;
2156 PKEY_CELL CurSubKeyCell
;
2161 VERIFY_KEY_OBJECT(KeyObject
);
2163 KeyCell
= KeyObject
->KeyCell
;
2164 VERIFY_KEY_CELL(KeyCell
);
2167 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2168 KeyCell
->HashTableOffset
,
2170 if (HashBlock
== NULL
)
2172 DPRINT("CmiGetBlock() failed\n");
2176 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2178 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2180 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2181 HashBlock
->Table
[i
].KeyOffset
,
2183 if (CurSubKeyCell
== NULL
)
2185 DPRINT("CmiGetBlock() failed\n");
2189 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2191 MaxClass
= CurSubKeyCell
->ClassSize
;
2197 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2198 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2200 CurKey
= KeyObject
->SubKeys
[i
];
2201 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2202 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2204 CurSubKeyCell
= CurKey
->KeyCell
;
2205 if (CurSubKeyCell
== NULL
)
2207 DPRINT("CmiGetBlock() failed\n");
2211 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2213 MaxClass
= CurSubKeyCell
->ClassSize
;
2223 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
2226 PVALUE_LIST_CELL ValueListCell
;
2227 PVALUE_CELL CurValueCell
;
2232 VERIFY_KEY_CELL(KeyCell
);
2235 ValueListCell
= CmiGetCell (RegistryHive
,
2236 KeyCell
->ValueListOffset
,
2238 if (ValueListCell
== NULL
)
2240 DPRINT("CmiGetBlock() failed\n");
2244 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2246 CurValueCell
= CmiGetCell (RegistryHive
,
2247 ValueListCell
->ValueOffset
[i
],
2249 if (CurValueCell
== NULL
)
2251 DPRINT("CmiGetBlock() failed\n");
2254 if (CurValueCell
!= NULL
)
2256 Size
= CurValueCell
->NameSize
;
2257 if (CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
2259 Size
*= sizeof(WCHAR
);
2261 if (MaxValueName
< Size
)
2263 MaxValueName
= Size
;
2268 return MaxValueName
;
2273 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
2276 PVALUE_LIST_CELL ValueListCell
;
2277 PVALUE_CELL CurValueCell
;
2281 VERIFY_KEY_CELL(KeyCell
);
2284 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2285 if (ValueListCell
== NULL
)
2290 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2292 CurValueCell
= CmiGetCell (RegistryHive
,
2293 ValueListCell
->ValueOffset
[i
],NULL
);
2294 if ((CurValueCell
!= NULL
) &&
2295 (MaxValueData
< (LONG
)(CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2297 MaxValueData
= CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2301 return MaxValueData
;
2306 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
2307 IN PKEY_CELL KeyCell
,
2308 OUT PKEY_CELL
*SubKeyCell
,
2309 OUT BLOCK_OFFSET
*BlockOffset
,
2310 IN PUNICODE_STRING KeyName
,
2311 IN ACCESS_MASK DesiredAccess
,
2312 IN ULONG Attributes
)
2314 PHASH_TABLE_CELL HashBlock
;
2315 PKEY_CELL CurSubKeyCell
;
2318 VERIFY_KEY_CELL(KeyCell
);
2320 DPRINT("Scanning for sub key %wZ\n", KeyName
);
2322 ASSERT(RegistryHive
);
2326 /* The key does not have any subkeys */
2327 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
2329 return STATUS_SUCCESS
;
2332 /* Get hash table */
2333 HashBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2334 if (HashBlock
== NULL
)
2336 DPRINT("CmiGetBlock() failed\n");
2337 return STATUS_UNSUCCESSFUL
;
2340 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
) && (i
< HashBlock
->HashTableSize
); i
++)
2342 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2344 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2345 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1 &&
2346 (HashBlock
->Table
[i
].HashValue
== 0 ||
2347 CmiCompareHashI(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2349 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2350 HashBlock
->Table
[i
].KeyOffset
,
2352 if (CurSubKeyCell
== NULL
)
2354 DPRINT("CmiGetBlock() failed\n");
2355 return STATUS_UNSUCCESSFUL
;
2358 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2360 *SubKeyCell
= CurSubKeyCell
;
2361 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2368 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2369 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2370 (HashBlock
->Table
[i
].HashValue
== 0 ||
2371 CmiCompareHash(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2373 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2374 HashBlock
->Table
[i
].KeyOffset
,
2376 if (CurSubKeyCell
== NULL
)
2378 DPRINT("CmiGetBlock() failed\n");
2379 return STATUS_UNSUCCESSFUL
;
2382 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2384 *SubKeyCell
= CurSubKeyCell
;
2385 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2392 return STATUS_SUCCESS
;
2397 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2398 PKEY_OBJECT ParentKey
,
2400 PUNICODE_STRING SubKeyName
,
2402 PUNICODE_STRING Class
,
2403 ULONG CreateOptions
)
2405 PHASH_TABLE_CELL HashBlock
;
2406 BLOCK_OFFSET NKBOffset
;
2407 PKEY_CELL NewKeyCell
;
2409 PKEY_CELL ParentKeyCell
;
2410 PDATA_CELL ClassCell
;
2417 ParentKeyCell
= ParentKey
->KeyCell
;
2419 VERIFY_KEY_CELL(ParentKeyCell
);
2421 /* Skip leading backslash */
2422 if (SubKeyName
->Buffer
[0] == L
'\\')
2424 NamePtr
= &SubKeyName
->Buffer
[1];
2425 NameSize
= SubKeyName
->Length
- sizeof(WCHAR
);
2429 NamePtr
= SubKeyName
->Buffer
;
2430 NameSize
= SubKeyName
->Length
;
2433 /* Check whether key name can be packed */
2435 for (i
= 0; i
< NameSize
/ sizeof(WCHAR
); i
++)
2437 if (NamePtr
[i
] & 0xFF00)
2444 /* Adjust name size */
2447 NameSize
= NameSize
/ sizeof(WCHAR
);
2450 DPRINT("Key %S Length %lu %s\n", NamePtr
, NameSize
, (Packable
)?"True":"False");
2452 Status
= STATUS_SUCCESS
;
2454 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2455 Status
= CmiAllocateCell (RegistryHive
,
2457 (PVOID
) &NewKeyCell
,
2459 if (NewKeyCell
== NULL
)
2461 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2465 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2466 NewKeyCell
->Flags
= 0;
2467 NtQuerySystemTime(&NewKeyCell
->LastWriteTime
);
2468 NewKeyCell
->ParentKeyOffset
= -1;
2469 NewKeyCell
->NumberOfSubKeys
= 0;
2470 NewKeyCell
->HashTableOffset
= -1;
2471 NewKeyCell
->NumberOfValues
= 0;
2472 NewKeyCell
->ValueListOffset
= -1;
2473 NewKeyCell
->SecurityKeyOffset
= -1;
2474 NewKeyCell
->ClassNameOffset
= -1;
2476 /* Pack the key name */
2477 NewKeyCell
->NameSize
= NameSize
;
2480 NewKeyCell
->Flags
|= REG_KEY_NAME_PACKED
;
2481 for (i
= 0; i
< NameSize
; i
++)
2483 NewKeyCell
->Name
[i
] = (CHAR
)(NamePtr
[i
] & 0x00FF);
2488 RtlCopyMemory(NewKeyCell
->Name
,
2493 VERIFY_KEY_CELL(NewKeyCell
);
2497 NewKeyCell
->ClassSize
= Class
->Length
;
2498 Status
= CmiAllocateCell (RegistryHive
,
2499 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
2501 &NewKeyCell
->ClassNameOffset
);
2502 RtlCopyMemory (ClassCell
->Data
,
2508 if (!NT_SUCCESS(Status
))
2513 SubKey
->KeyCell
= NewKeyCell
;
2514 SubKey
->KeyCellOffset
= NKBOffset
;
2516 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2517 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(ParentKey
->RegistryHive
)))
2522 if (ParentKeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2524 Status
= CmiAllocateHashTableCell (RegistryHive
,
2526 &ParentKeyCell
->HashTableOffset
,
2527 REG_INIT_HASH_TABLE_SIZE
);
2528 if (!NT_SUCCESS(Status
))
2535 HashBlock
= CmiGetCell (RegistryHive
,
2536 ParentKeyCell
->HashTableOffset
,
2538 if (HashBlock
== NULL
)
2540 DPRINT("CmiGetCell() failed\n");
2541 return STATUS_UNSUCCESSFUL
;
2544 if (((ParentKeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2546 PHASH_TABLE_CELL NewHashBlock
;
2547 BLOCK_OFFSET HTOffset
;
2549 /* Reallocate the hash table cell */
2550 Status
= CmiAllocateHashTableCell (RegistryHive
,
2553 HashBlock
->HashTableSize
+
2554 REG_EXTEND_HASH_TABLE_SIZE
);
2555 if (!NT_SUCCESS(Status
))
2560 RtlZeroMemory(&NewHashBlock
->Table
[0],
2561 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2562 RtlCopyMemory(&NewHashBlock
->Table
[0],
2563 &HashBlock
->Table
[0],
2564 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2565 CmiDestroyCell (RegistryHive
,
2567 ParentKeyCell
->HashTableOffset
);
2568 ParentKeyCell
->HashTableOffset
= HTOffset
;
2569 HashBlock
= NewHashBlock
;
2573 Status
= CmiAddKeyToHashTable(RegistryHive
,
2575 ParentKeyCell
->HashTableOffset
,
2578 if (NT_SUCCESS(Status
))
2580 ParentKeyCell
->NumberOfSubKeys
++;
2583 NtQuerySystemTime (&ParentKeyCell
->LastWriteTime
);
2584 CmiMarkBlockDirty (RegistryHive
, ParentKey
->KeyCellOffset
);
2591 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2592 PKEY_OBJECT ParentKey
,
2595 PHASH_TABLE_CELL HashBlock
;
2596 PVALUE_LIST_CELL ValueList
;
2597 PVALUE_CELL ValueCell
;
2598 PDATA_CELL DataCell
;
2601 DPRINT("CmiRemoveSubKey() called\n");
2603 /* Remove all values */
2604 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2606 /* Get pointer to the value list cell */
2607 ValueList
= CmiGetCell (RegistryHive
,
2608 SubKey
->KeyCell
->ValueListOffset
,
2610 if (ValueList
== NULL
)
2612 DPRINT("CmiGetCell() failed\n");
2613 return STATUS_UNSUCCESSFUL
;
2616 /* Enumerate all values */
2617 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2619 /* Get pointer to value cell */
2620 ValueCell
= CmiGetCell(RegistryHive
,
2621 ValueList
->ValueOffset
[i
],
2623 if (ValueCell
== NULL
)
2625 DPRINT("CmiGetCell() failed\n");
2626 return STATUS_UNSUCCESSFUL
;
2629 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
)
2630 && ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
2632 DataCell
= CmiGetCell (RegistryHive
,
2633 ValueCell
->DataOffset
,
2635 if (DataCell
== NULL
)
2637 DPRINT("CmiGetCell() failed\n");
2638 return STATUS_UNSUCCESSFUL
;
2641 if (DataCell
!= NULL
)
2643 /* Destroy data cell */
2644 CmiDestroyCell (RegistryHive
,
2646 ValueCell
->DataOffset
);
2650 /* Destroy value cell */
2651 CmiDestroyCell (RegistryHive
,
2653 ValueList
->ValueOffset
[i
]);
2656 /* Destroy value list cell */
2657 CmiDestroyCell (RegistryHive
,
2659 SubKey
->KeyCell
->ValueListOffset
);
2661 SubKey
->KeyCell
->NumberOfValues
= 0;
2662 SubKey
->KeyCell
->ValueListOffset
= (BLOCK_OFFSET
)-1;
2664 CmiMarkBlockDirty(RegistryHive
,
2665 SubKey
->KeyCellOffset
);
2668 /* Remove the key from the parent key's hash block */
2669 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2671 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2672 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2673 ParentKey
->KeyCell
->HashTableOffset
,
2675 if (HashBlock
== NULL
)
2677 DPRINT("CmiGetCell() failed\n");
2678 return STATUS_UNSUCCESSFUL
;
2680 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2681 if (HashBlock
!= NULL
)
2683 CmiRemoveKeyFromHashTable(ParentKey
->RegistryHive
,
2685 SubKey
->KeyCellOffset
);
2686 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2687 ParentKey
->KeyCell
->HashTableOffset
);
2691 /* Remove the key's hash block */
2692 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2694 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
);
2695 HashBlock
= CmiGetCell (RegistryHive
,
2696 SubKey
->KeyCell
->HashTableOffset
,
2698 if (HashBlock
== NULL
)
2700 DPRINT("CmiGetCell() failed\n");
2701 return STATUS_UNSUCCESSFUL
;
2703 DPRINT("SubKey HashBlock %p\n", HashBlock
);
2704 if (HashBlock
!= NULL
)
2706 CmiDestroyCell (RegistryHive
,
2708 SubKey
->KeyCell
->HashTableOffset
);
2709 SubKey
->KeyCell
->HashTableOffset
= -1;
2713 /* Decrement the number of the parent key's sub keys */
2714 if (ParentKey
!= NULL
)
2716 DPRINT("ParentKey %p\n", ParentKey
);
2717 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2719 /* Remove the parent key's hash table */
2720 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2722 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2723 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2724 ParentKey
->KeyCell
->HashTableOffset
,
2726 if (HashBlock
== NULL
)
2728 DPRINT("CmiGetCell() failed\n");
2729 return STATUS_UNSUCCESSFUL
;
2731 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2732 if (HashBlock
!= NULL
)
2734 CmiDestroyCell (ParentKey
->RegistryHive
,
2736 ParentKey
->KeyCell
->HashTableOffset
);
2737 ParentKey
->KeyCell
->HashTableOffset
= (BLOCK_OFFSET
)-1;
2741 NtQuerySystemTime(&ParentKey
->KeyCell
->LastWriteTime
);
2742 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2743 ParentKey
->KeyCellOffset
);
2746 /* Destroy key cell */
2747 CmiDestroyCell (RegistryHive
,
2749 SubKey
->KeyCellOffset
);
2750 SubKey
->KeyCell
= NULL
;
2751 SubKey
->KeyCellOffset
= (BLOCK_OFFSET
)-1;
2753 DPRINT("CmiRemoveSubKey() done\n");
2755 return STATUS_SUCCESS
;
2760 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2761 IN PKEY_CELL KeyCell
,
2762 IN PUNICODE_STRING ValueName
,
2763 OUT PVALUE_CELL
*ValueCell
,
2764 OUT BLOCK_OFFSET
*ValueCellOffset
)
2766 PVALUE_LIST_CELL ValueListCell
;
2767 PVALUE_CELL CurValueCell
;
2771 if (ValueCellOffset
!= NULL
)
2772 *ValueCellOffset
= (BLOCK_OFFSET
)-1;
2774 /* The key does not have any values */
2775 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2777 return STATUS_OBJECT_NAME_NOT_FOUND
;
2780 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2781 if (ValueListCell
== NULL
)
2783 DPRINT("ValueListCell is NULL\n");
2784 return STATUS_UNSUCCESSFUL
;
2787 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2789 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2791 CurValueCell
= CmiGetCell (RegistryHive
,
2792 ValueListCell
->ValueOffset
[i
],
2794 if (CurValueCell
== NULL
)
2796 DPRINT("CmiGetBlock() failed\n");
2797 return STATUS_UNSUCCESSFUL
;
2800 if ((CurValueCell
!= NULL
) &&
2801 CmiComparePackedNames(ValueName
,
2803 CurValueCell
->NameSize
,
2804 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2806 *ValueCell
= CurValueCell
;
2807 if (ValueCellOffset
!= NULL
)
2808 *ValueCellOffset
= ValueListCell
->ValueOffset
[i
];
2809 //DPRINT("Found value %s\n", ValueName);
2810 return STATUS_SUCCESS
;
2814 return STATUS_OBJECT_NAME_NOT_FOUND
;
2819 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2820 IN PKEY_CELL KeyCell
,
2822 OUT PVALUE_CELL
*ValueCell
)
2824 PVALUE_LIST_CELL ValueListCell
;
2825 PVALUE_CELL CurValueCell
;
2829 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2831 return STATUS_NO_MORE_ENTRIES
;
2834 if (Index
>= KeyCell
->NumberOfValues
)
2836 return STATUS_NO_MORE_ENTRIES
;
2840 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2841 if (ValueListCell
== NULL
)
2843 DPRINT("CmiGetBlock() failed\n");
2844 return STATUS_UNSUCCESSFUL
;
2847 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2850 CurValueCell
= CmiGetCell (RegistryHive
,
2851 ValueListCell
->ValueOffset
[Index
],
2853 if (CurValueCell
== NULL
)
2855 DPRINT("CmiGetBlock() failed\n");
2856 return STATUS_UNSUCCESSFUL
;
2859 *ValueCell
= CurValueCell
;
2861 return STATUS_SUCCESS
;
2866 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2867 IN PKEY_CELL KeyCell
,
2868 IN BLOCK_OFFSET KeyCellOffset
,
2869 IN PUNICODE_STRING ValueName
,
2870 OUT PVALUE_CELL
*pValueCell
,
2871 OUT BLOCK_OFFSET
*pValueCellOffset
)
2873 PVALUE_LIST_CELL NewValueListCell
;
2874 PVALUE_LIST_CELL ValueListCell
;
2875 PVALUE_CELL NewValueCell
;
2876 BLOCK_OFFSET NewValueListCellOffset
;
2877 BLOCK_OFFSET ValueListCellOffset
;
2878 BLOCK_OFFSET NewValueCellOffset
;
2882 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG
)KeyCell
->ValueListOffset
);
2884 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2885 if (ValueListCell
== NULL
)
2887 CellSize
= sizeof(VALUE_LIST_CELL
) +
2888 (3 * sizeof(BLOCK_OFFSET
));
2889 Status
= CmiAllocateCell (RegistryHive
,
2891 (PVOID
) &ValueListCell
,
2892 &ValueListCellOffset
);
2893 if (!NT_SUCCESS(Status
))
2898 KeyCell
->ValueListOffset
= ValueListCellOffset
;
2899 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2900 CmiMarkBlockDirty(RegistryHive
, ValueListCellOffset
);
2902 else if (KeyCell
->NumberOfValues
>=
2903 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
)))
2906 CellSize
= sizeof(VALUE_LIST_CELL
) +
2907 ((KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) * sizeof(BLOCK_OFFSET
));
2909 CellSize
= 2 * (ULONG
)ABS_VALUE(ValueListCell
->CellSize
);
2910 Status
= CmiAllocateCell (RegistryHive
,
2912 (PVOID
) &NewValueListCell
,
2913 &NewValueListCellOffset
);
2914 if (!NT_SUCCESS(Status
))
2919 RtlCopyMemory(&NewValueListCell
->ValueOffset
[0],
2920 &ValueListCell
->ValueOffset
[0],
2921 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2922 CmiDestroyCell (RegistryHive
, ValueListCell
, KeyCell
->ValueListOffset
);
2923 CmiMarkBlockDirty (RegistryHive
, KeyCell
->ValueListOffset
);
2925 KeyCell
->ValueListOffset
= NewValueListCellOffset
;
2926 ValueListCell
= NewValueListCell
;
2927 CmiMarkBlockDirty (RegistryHive
, KeyCellOffset
);
2928 CmiMarkBlockDirty (RegistryHive
, NewValueListCellOffset
);
2931 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2932 KeyCell
->NumberOfValues
,
2933 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2934 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
),
2935 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
));
2937 Status
= CmiAllocateValueCell(RegistryHive
,
2939 &NewValueCellOffset
,
2941 if (!NT_SUCCESS(Status
))
2946 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = NewValueCellOffset
;
2947 KeyCell
->NumberOfValues
++;
2949 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2950 CmiMarkBlockDirty(RegistryHive
, KeyCell
->ValueListOffset
);
2951 CmiMarkBlockDirty(RegistryHive
, NewValueCellOffset
);
2953 *pValueCell
= NewValueCell
;
2954 *pValueCellOffset
= NewValueCellOffset
;
2956 return STATUS_SUCCESS
;
2961 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2962 IN PKEY_CELL KeyCell
,
2963 IN BLOCK_OFFSET KeyCellOffset
,
2964 IN PUNICODE_STRING ValueName
)
2966 PVALUE_LIST_CELL ValueListCell
;
2967 PVALUE_CELL CurValueCell
;
2971 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2972 if (ValueListCell
== NULL
)
2974 DPRINT1("CmiGetBlock() failed\n");
2975 return STATUS_SUCCESS
;
2978 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2980 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2982 CurValueCell
= CmiGetCell (RegistryHive
, ValueListCell
->ValueOffset
[i
], NULL
);
2983 if (CurValueCell
== NULL
)
2985 DPRINT1("CmiGetBlock() failed\n");
2986 return STATUS_UNSUCCESSFUL
;
2989 if (CmiComparePackedNames(ValueName
,
2991 CurValueCell
->NameSize
,
2992 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2994 Status
= CmiDestroyValueCell(RegistryHive
,
2996 ValueListCell
->ValueOffset
[i
]);
2997 if (CurValueCell
== NULL
)
2999 DPRINT1("CmiDestroyValueCell() failed\n");
3003 if (i
< (KeyCell
->NumberOfValues
- 1))
3005 RtlMoveMemory(&ValueListCell
->ValueOffset
[i
],
3006 &ValueListCell
->ValueOffset
[i
+ 1],
3007 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
3009 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
- 1] = 0;
3012 KeyCell
->NumberOfValues
--;
3014 if (KeyCell
->NumberOfValues
== 0)
3016 CmiDestroyCell(RegistryHive
,
3018 KeyCell
->ValueListOffset
);
3019 KeyCell
->ValueListOffset
= -1;
3023 CmiMarkBlockDirty(RegistryHive
,
3024 KeyCell
->ValueListOffset
);
3027 CmiMarkBlockDirty(RegistryHive
,
3030 return STATUS_SUCCESS
;
3034 DPRINT("Couldn't find the desired value\n");
3036 return STATUS_OBJECT_NAME_NOT_FOUND
;
3041 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive
,
3042 OUT PHASH_TABLE_CELL
*HashBlock
,
3043 OUT BLOCK_OFFSET
*HBOffset
,
3044 IN ULONG SubKeyCount
)
3046 PHASH_TABLE_CELL NewHashBlock
;
3050 Status
= STATUS_SUCCESS
;
3052 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
3053 (SubKeyCount
* sizeof(HASH_RECORD
));
3054 Status
= CmiAllocateCell (RegistryHive
,
3056 (PVOID
*) &NewHashBlock
,
3059 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
3061 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3065 ASSERT(SubKeyCount
<= 0xffff); /* should really be USHORT_MAX or similar */
3066 NewHashBlock
->Id
= REG_HASH_TABLE_CELL_ID
;
3067 NewHashBlock
->HashTableSize
= (USHORT
)SubKeyCount
;
3068 *HashBlock
= NewHashBlock
;
3076 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
3077 PHASH_TABLE_CELL HashBlock
,
3080 BLOCK_OFFSET KeyOffset
;
3083 if (HashBlock
== NULL
)
3086 if (IsPointerHive(RegistryHive
))
3088 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
3092 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
3093 KeyCell
= CmiGetCell (RegistryHive
, KeyOffset
, NULL
);
3101 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
3102 PHASH_TABLE_CELL HashCell
,
3103 BLOCK_OFFSET HashCellOffset
,
3104 PKEY_CELL NewKeyCell
,
3105 BLOCK_OFFSET NKBOffset
)
3109 for (i
= 0; i
< HashCell
->HashTableSize
; i
++)
3111 if (HashCell
->Table
[i
].KeyOffset
== 0)
3113 HashCell
->Table
[i
].KeyOffset
= NKBOffset
;
3114 HashCell
->Table
[i
].HashValue
= 0;
3115 if (NewKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3117 RtlCopyMemory(&HashCell
->Table
[i
].HashValue
,
3119 min(NewKeyCell
->NameSize
, sizeof(ULONG
)));
3121 CmiMarkBlockDirty(RegistryHive
, HashCellOffset
);
3122 return STATUS_SUCCESS
;
3126 return STATUS_UNSUCCESSFUL
;
3131 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
3132 PHASH_TABLE_CELL HashBlock
,
3133 BLOCK_OFFSET NKBOffset
)
3137 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3139 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
3141 HashBlock
->Table
[i
].KeyOffset
= 0;
3142 HashBlock
->Table
[i
].HashValue
= 0;
3143 return STATUS_SUCCESS
;
3147 return STATUS_UNSUCCESSFUL
;
3152 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
3153 PVALUE_CELL
*ValueCell
,
3154 BLOCK_OFFSET
*VBOffset
,
3155 IN PUNICODE_STRING ValueName
)
3157 PVALUE_CELL NewValueCell
;
3163 Status
= STATUS_SUCCESS
;
3165 NameSize
= CmiGetPackedNameLength(ValueName
,
3168 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
3170 Status
= CmiAllocateCell (RegistryHive
,
3171 sizeof(VALUE_CELL
) + NameSize
,
3172 (PVOID
*) &NewValueCell
,
3174 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
3176 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3180 ASSERT(NameSize
<= 0xffff); /* should really be USHORT_MAX or similar */
3181 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
3182 NewValueCell
->NameSize
= (USHORT
)NameSize
;
3185 /* Pack the value name */
3186 for (i
= 0; i
< NameSize
; i
++)
3187 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
3188 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
3192 /* Copy the value name */
3193 RtlCopyMemory(NewValueCell
->Name
,
3196 NewValueCell
->Flags
= 0;
3198 NewValueCell
->DataType
= 0;
3199 NewValueCell
->DataSize
= 0;
3200 NewValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
3201 *ValueCell
= NewValueCell
;
3209 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
3210 PVALUE_CELL ValueCell
,
3211 BLOCK_OFFSET ValueCellOffset
)
3217 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n",
3218 ValueCell
, ValueCellOffset
);
3220 VERIFY_VALUE_CELL(ValueCell
);
3222 /* Destroy the data cell */
3223 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
)
3224 && ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
3226 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, &Bin
);
3227 if (DataCell
== NULL
)
3229 DPRINT("CmiGetCell() failed\n");
3230 return STATUS_UNSUCCESSFUL
;
3233 Status
= CmiDestroyCell (RegistryHive
, DataCell
, ValueCell
->DataOffset
);
3234 if (!NT_SUCCESS(Status
))
3239 /* Update time of heap */
3240 if (!IsNoFileHive(RegistryHive
))
3241 NtQuerySystemTime(&Bin
->DateModified
);
3244 /* Destroy the value cell */
3245 Status
= CmiDestroyCell (RegistryHive
, ValueCell
, ValueCellOffset
);
3247 /* Update time of heap */
3248 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, ValueCellOffset
, &Bin
))
3250 NtQuerySystemTime(&Bin
->DateModified
);
3258 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
3261 BLOCK_OFFSET
*NewBlockOffset
)
3263 PBLOCK_LIST_ENTRY BlockList
;
3264 PCELL_HEADER tmpBlock
;
3269 DPRINT ("CmiAddBin (BlockCount %lu)\n", BlockCount
);
3271 BinSize
= BlockCount
* REG_BLOCK_SIZE
;
3272 tmpBin
= ExAllocatePool(PagedPool
, BinSize
);
3275 return STATUS_INSUFFICIENT_RESOURCES
;
3277 RtlZeroMemory (tmpBin
,
3280 tmpBin
->HeaderId
= REG_BIN_ID
;
3281 tmpBin
->BinOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
3282 RegistryHive
->FileSize
+= BinSize
;
3283 tmpBin
->BinSize
= BinSize
;
3284 tmpBin
->Unused1
= 0;
3285 NtQuerySystemTime(&tmpBin
->DateModified
);
3286 tmpBin
->Unused2
= 0;
3288 DPRINT (" BinOffset %lx BinSize %lx\n", tmpBin
->BinOffset
,tmpBin
->BinSize
);
3290 /* Allocate new block list */
3291 BlockList
= ExAllocatePool(NonPagedPool
,
3292 sizeof(BLOCK_LIST_ENTRY
) * (RegistryHive
->BlockListSize
+ BlockCount
));
3293 if (BlockList
== NULL
)
3296 return STATUS_INSUFFICIENT_RESOURCES
;
3299 if (RegistryHive
->BlockListSize
> 0)
3301 RtlCopyMemory (BlockList
,
3302 RegistryHive
->BlockList
,
3303 sizeof(BLOCK_LIST_ENTRY
) * RegistryHive
->BlockListSize
);
3304 ExFreePool(RegistryHive
->BlockList
);
3307 RegistryHive
->BlockList
= BlockList
;
3308 for (i
= 0; i
< BlockCount
; i
++)
3310 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Block
=
3311 (PVOID
)((ULONG_PTR
)tmpBin
+ (i
* REG_BLOCK_SIZE
));
3312 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
].Bin
= tmpBin
;
3314 RegistryHive
->BlockListSize
+= BlockCount
;
3316 /* Initialize a free block in this heap : */
3317 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
3318 tmpBlock
->CellSize
= (BinSize
- REG_HBIN_DATA_OFFSET
);
3320 /* Grow bitmap if necessary */
3321 if (IsNoFileHive(RegistryHive
) &&
3322 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
3324 PULONG BitmapBuffer
;
3327 DPRINT("Grow hive bitmap\n");
3329 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3330 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
3331 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
3332 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
3333 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
3335 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
3336 RtlCopyMemory(BitmapBuffer
,
3337 RegistryHive
->DirtyBitMap
.Buffer
,
3338 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
3339 ExFreePool(RegistryHive
->BitmapBuffer
);
3340 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
3341 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
3342 RegistryHive
->BitmapBuffer
,
3346 *NewBlock
= (PVOID
) tmpBlock
;
3349 *NewBlockOffset
= tmpBin
->BinOffset
+ REG_HBIN_DATA_OFFSET
;
3351 /* Mark new bin dirty */
3352 CmiMarkBinDirty(RegistryHive
,
3355 return STATUS_SUCCESS
;
3360 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
3363 BLOCK_OFFSET
*CellOffset
)
3365 PCELL_HEADER NewCell
;
3371 /* Round to 16 bytes multiple */
3372 CellSize
= ROUND_UP(CellSize
, 16);
3374 /* Handle volatile hives first */
3375 if (IsPointerHive(RegistryHive
))
3377 NewCell
= ExAllocatePool(NonPagedPool
, CellSize
);
3378 if (NewCell
== NULL
)
3380 return STATUS_INSUFFICIENT_RESOURCES
;
3383 RtlZeroMemory (NewCell
,
3385 NewCell
->CellSize
= -CellSize
;
3388 if (CellOffset
!= NULL
)
3389 *CellOffset
= (BLOCK_OFFSET
) NewCell
;
3393 /* first search in free blocks */
3395 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3397 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
3399 NewCell
= RegistryHive
->FreeList
[i
];
3400 if (CellOffset
!= NULL
)
3401 *CellOffset
= RegistryHive
->FreeListOffset
[i
];
3403 /* Update time of heap */
3404 Temp
= CmiGetCell (RegistryHive
,
3405 RegistryHive
->FreeListOffset
[i
],
3409 DPRINT("CmiGetBlock() failed\n");
3410 return STATUS_UNSUCCESSFUL
;
3413 NtQuerySystemTime(&Bin
->DateModified
);
3414 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
3416 if ((i
+ 1) < RegistryHive
->FreeListSize
)
3418 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
3419 &RegistryHive
->FreeList
[i
+ 1],
3420 sizeof(RegistryHive
->FreeList
[0])
3421 * (RegistryHive
->FreeListSize
- i
- 1));
3422 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
3423 &RegistryHive
->FreeListOffset
[i
+ 1],
3424 sizeof(RegistryHive
->FreeListOffset
[0])
3425 * (RegistryHive
->FreeListSize
- i
- 1));
3427 RegistryHive
->FreeListSize
--;
3432 /* Need to extend hive file : */
3433 if (NewCell
== NULL
)
3436 Status
= CmiAddBin(RegistryHive
,
3437 ((CellSize
+ sizeof(HBIN
) - 1) / REG_BLOCK_SIZE
) + 1,
3440 if (!NT_SUCCESS(Status
))
3446 /* Split the block in two parts */
3447 if (NewCell
->CellSize
> CellSize
)
3449 NewCell
= (PCELL_HEADER
) ((ULONG_PTR
) NewCell
+ CellSize
);
3450 NewCell
->CellSize
= ((PCELL_HEADER
) (*Cell
))->CellSize
- CellSize
;
3451 CmiAddFree(RegistryHive
,
3453 *CellOffset
+ CellSize
,
3455 CmiMarkBlockDirty(RegistryHive
,
3456 *CellOffset
+ CellSize
);
3458 else if (NewCell
->CellSize
< CellSize
)
3460 return STATUS_UNSUCCESSFUL
;
3463 RtlZeroMemory(*Cell
,
3465 ((PCELL_HEADER
) (*Cell
))->CellSize
= -CellSize
;
3468 return STATUS_SUCCESS
;
3473 CmiDestroyCell (PREGISTRY_HIVE RegistryHive
,
3475 BLOCK_OFFSET CellOffset
)
3480 Status
= STATUS_SUCCESS
;
3482 if (IsPointerHive(RegistryHive
))
3488 PCELL_HEADER pFree
= Cell
;
3490 if (pFree
->CellSize
< 0)
3491 pFree
->CellSize
= -pFree
->CellSize
;
3493 /* Clear block (except the block size) */
3494 RtlZeroMemory(((char*)pFree
) + sizeof(ULONG
),
3495 pFree
->CellSize
- sizeof(ULONG
));
3497 /* Add block to the list of free blocks */
3498 CmiAddFree(RegistryHive
, Cell
, CellOffset
, TRUE
);
3500 /* Update time of heap */
3501 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, CellOffset
,&pBin
))
3502 NtQuerySystemTime(&pBin
->DateModified
);
3504 CmiMarkBlockDirty(RegistryHive
, CellOffset
);
3512 CmiGetCell (PREGISTRY_HIVE RegistryHive
,
3513 BLOCK_OFFSET CellOffset
,
3523 if (CellOffset
== (BLOCK_OFFSET
)-1)
3528 if (IsPointerHive (RegistryHive
))
3530 return (PVOID
)CellOffset
;
3533 if (CellOffset
> RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
)
3535 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3536 CellOffset
, RegistryHive
->BlockListSize
* REG_BLOCK_SIZE
);
3540 pBin
= RegistryHive
->BlockList
[CellOffset
/ REG_BLOCK_SIZE
].Bin
;
3551 return((PVOID
)((ULONG_PTR
)pBin
+ (CellOffset
- pBin
->BinOffset
)));
3556 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3557 PCELL_HEADER FreeBlock
,
3558 BLOCK_OFFSET FreeOffset
)
3560 BLOCK_OFFSET BlockOffset
;
3561 BLOCK_OFFSET BinOffset
;
3567 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3568 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3570 CmiGetCell (RegistryHive
,
3573 DPRINT("Bin %p\n", Bin
);
3577 BinOffset
= Bin
->BinOffset
;
3578 BinSize
= Bin
->BinSize
;
3579 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3581 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3583 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3584 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3585 if (BlockOffset
> BinOffset
&&
3586 BlockOffset
< BinOffset
+ BinSize
)
3588 DPRINT("Free block: Offset %lx Size %lx\n",
3589 BlockOffset
, BlockSize
);
3591 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3592 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3593 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3595 DPRINT("Merge current block with previous and next block\n");
3597 RegistryHive
->FreeList
[i
]->CellSize
+=
3598 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3600 FreeBlock
->CellSize
= 0;
3601 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3604 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3606 RtlMoveMemory(&RegistryHive
->FreeList
[i
+ 1],
3607 &RegistryHive
->FreeList
[i
+ 2],
3608 sizeof(RegistryHive
->FreeList
[0])
3609 * (RegistryHive
->FreeListSize
- i
- 2));
3610 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3611 &RegistryHive
->FreeListOffset
[i
+ 2],
3612 sizeof(RegistryHive
->FreeListOffset
[0])
3613 * (RegistryHive
->FreeListSize
- i
- 2));
3615 RegistryHive
->FreeListSize
--;
3617 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3621 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3623 DPRINT("Merge current block with previous block\n");
3625 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3626 FreeBlock
->CellSize
= 0;
3628 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3632 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3634 DPRINT("Merge current block with next block\n");
3636 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3637 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3638 RegistryHive
->FreeList
[i
] = FreeBlock
;
3639 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3641 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3653 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3654 PCELL_HEADER FreeBlock
,
3655 BLOCK_OFFSET FreeOffset
,
3656 BOOLEAN MergeFreeBlocks
)
3658 PCELL_HEADER
*tmpList
;
3659 BLOCK_OFFSET
*tmpListOffset
;
3664 ASSERT(RegistryHive
);
3667 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3668 FreeBlock
, FreeOffset
);
3670 /* Merge free blocks */
3671 if (MergeFreeBlocks
== TRUE
)
3673 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3674 return(STATUS_SUCCESS
);
3677 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3679 tmpList
= ExAllocatePool(PagedPool
,
3680 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3681 if (tmpList
== NULL
)
3682 return STATUS_INSUFFICIENT_RESOURCES
;
3684 tmpListOffset
= ExAllocatePool(PagedPool
,
3685 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3687 if (tmpListOffset
== NULL
)
3689 ExFreePool(tmpList
);
3690 return STATUS_INSUFFICIENT_RESOURCES
;
3693 if (RegistryHive
->FreeListMax
)
3695 RtlMoveMemory(tmpList
,
3696 RegistryHive
->FreeList
,
3697 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3698 RtlMoveMemory(tmpListOffset
,
3699 RegistryHive
->FreeListOffset
,
3700 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3701 ExFreePool(RegistryHive
->FreeList
);
3702 ExFreePool(RegistryHive
->FreeListOffset
);
3704 RegistryHive
->FreeList
= tmpList
;
3705 RegistryHive
->FreeListOffset
= tmpListOffset
;
3706 RegistryHive
->FreeListMax
+= 32;
3709 /* Add new offset to free list, maintaining list in ascending order */
3710 if ((RegistryHive
->FreeListSize
== 0)
3711 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3713 /* Add to end of list */
3714 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3715 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3717 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3719 /* Add to begin of list */
3720 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3721 &RegistryHive
->FreeList
[0],
3722 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3723 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3724 &RegistryHive
->FreeListOffset
[0],
3725 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3726 RegistryHive
->FreeList
[0] = FreeBlock
;
3727 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3728 RegistryHive
->FreeListSize
++;
3732 /* Search where to insert */
3734 maxInd
= RegistryHive
->FreeListSize
- 1;
3735 while ((maxInd
- minInd
) > 1)
3737 medInd
= (minInd
+ maxInd
) / 2;
3738 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3744 /* Insert before maxInd */
3745 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3746 &RegistryHive
->FreeList
[maxInd
],
3747 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3748 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3749 &RegistryHive
->FreeListOffset
[maxInd
],
3750 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3751 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3752 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3753 RegistryHive
->FreeListSize
++;
3756 return STATUS_SUCCESS
;
3761 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3762 BLOCK_OFFSET BlockOffset
)
3769 if (IsNoFileHive(RegistryHive
))
3772 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3774 BlockNumber
= (ULONG
)BlockOffset
/ REG_BLOCK_SIZE
;
3776 Cell
= CmiGetCell (RegistryHive
,
3780 CellSize
= Cell
->CellSize
;
3782 CellSize
= -CellSize
;
3784 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, REG_BLOCK_SIZE
) -
3785 ROUND_DOWN(BlockOffset
, REG_BLOCK_SIZE
)) / REG_BLOCK_SIZE
;
3787 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3790 (Cell
->CellSize
< 0) ? "used" : "free",
3793 RegistryHive
->HiveDirty
= TRUE
;
3794 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3801 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3802 BLOCK_OFFSET BinOffset
)
3808 if (IsNoFileHive(RegistryHive
))
3811 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3813 BlockNumber
= (ULONG
)BinOffset
/ REG_BLOCK_SIZE
;
3815 Bin
= RegistryHive
->BlockList
[BlockNumber
].Bin
;
3817 BlockCount
= Bin
->BinSize
/ REG_BLOCK_SIZE
;
3819 DPRINT(" BlockNumber %lu BinSize %lu BlockCount %lu\n",
3824 RegistryHive
->HiveDirty
= TRUE
;
3825 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3832 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3833 OUT PBOOLEAN Packable
)
3837 if (Packable
!= NULL
)
3840 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3842 if (Name
->Buffer
[i
] & 0xFF00)
3844 if (Packable
!= NULL
)
3846 return Name
->Length
;
3850 return (Name
->Length
/ sizeof(WCHAR
));
3855 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3856 IN PCHAR NameBuffer
,
3857 IN USHORT NameBufferSize
,
3858 IN BOOLEAN NamePacked
)
3863 if (NamePacked
== TRUE
)
3865 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3868 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3870 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3876 if (Name
->Length
!= NameBufferSize
)
3879 UNameBuffer
= (PWCHAR
)NameBuffer
;
3881 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3883 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3893 CmiCopyPackedName(PWCHAR NameBuffer
,
3894 PCHAR PackedNameBuffer
,
3895 ULONG PackedNameSize
)
3899 for (i
= 0; i
< PackedNameSize
; i
++)
3900 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];
3905 CmiCompareHash(PUNICODE_STRING KeyName
,
3910 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3911 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3912 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3913 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3915 return (strncmp(Buffer
, HashString
, 4) == 0);
3920 CmiCompareHashI(PUNICODE_STRING KeyName
,
3925 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3926 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3927 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3928 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3930 return (_strnicmp(Buffer
, HashString
, 4) == 0);
3935 CmiCompareKeyNames(PUNICODE_STRING KeyName
,
3941 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3943 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3945 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3948 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3950 if (KeyName
->Buffer
[i
] != (WCHAR
)KeyCell
->Name
[i
])
3956 if (KeyName
->Length
!= KeyCell
->NameSize
)
3959 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3960 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3962 if (KeyName
->Buffer
[i
] != UnicodeName
[i
])
3972 CmiCompareKeyNamesI(PUNICODE_STRING KeyName
,
3978 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3980 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3982 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3985 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3987 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3988 RtlUpcaseUnicodeChar((WCHAR
)KeyCell
->Name
[i
]))
3994 if (KeyName
->Length
!= KeyCell
->NameSize
)
3997 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3998 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
4000 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
4001 RtlUpcaseUnicodeChar(UnicodeName
[i
]))
4011 CmiCopyKey (PREGISTRY_HIVE DstHive
,
4012 PKEY_CELL DstKeyCell
,
4013 PREGISTRY_HIVE SrcHive
,
4014 PKEY_CELL SrcKeyCell
)
4016 PKEY_CELL NewKeyCell
;
4017 ULONG NewKeyCellSize
;
4018 BLOCK_OFFSET NewKeyCellOffset
;
4019 PHASH_TABLE_CELL NewHashTableCell
;
4020 ULONG NewHashTableSize
;
4021 BLOCK_OFFSET NewHashTableOffset
;
4025 DPRINT ("CmiCopyKey() called\n");
4027 if (DstKeyCell
== NULL
)
4029 /* Allocate and copy key cell */
4030 NewKeyCellSize
= sizeof(KEY_CELL
) + SrcKeyCell
->NameSize
;
4031 Status
= CmiAllocateCell (DstHive
,
4033 (PVOID
) &NewKeyCell
,
4035 if (!NT_SUCCESS(Status
))
4037 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4040 if (NewKeyCell
== NULL
)
4042 DPRINT1 ("Failed to allocate a key cell\n");
4043 return STATUS_INSUFFICIENT_RESOURCES
;
4046 RtlCopyMemory (NewKeyCell
,
4050 DstHive
->HiveHeader
->RootKeyOffset
= NewKeyCellOffset
;
4052 /* Copy class name */
4053 if (SrcKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4055 PDATA_CELL SrcClassNameCell
;
4056 PDATA_CELL NewClassNameCell
;
4057 BLOCK_OFFSET NewClassNameOffset
;
4059 SrcClassNameCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ClassNameOffset
, NULL
),
4061 NewKeyCell
->ClassSize
= SrcKeyCell
->ClassSize
;
4062 Status
= CmiAllocateCell (DstHive
,
4063 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
4064 (PVOID
)&NewClassNameCell
,
4065 &NewClassNameOffset
);
4066 if (!NT_SUCCESS(Status
))
4068 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4072 RtlCopyMemory (NewClassNameCell
,
4074 NewKeyCell
->ClassSize
);
4075 NewKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4080 NewKeyCell
= DstKeyCell
;
4083 /* Allocate hash table */
4084 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4086 NewHashTableSize
= ROUND_UP(SrcKeyCell
->NumberOfSubKeys
+ 1, 4) - 1;
4087 Status
= CmiAllocateHashTableCell (DstHive
,
4089 &NewHashTableOffset
,
4091 if (!NT_SUCCESS(Status
))
4093 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status
);
4096 NewKeyCell
->HashTableOffset
= NewHashTableOffset
;
4099 /* Allocate and copy value list and values */
4100 if (SrcKeyCell
->NumberOfValues
!= 0)
4102 PVALUE_LIST_CELL NewValueListCell
;
4103 PVALUE_LIST_CELL SrcValueListCell
;
4104 PVALUE_CELL NewValueCell
;
4105 PVALUE_CELL SrcValueCell
;
4106 PDATA_CELL SrcValueDataCell
;
4107 PDATA_CELL NewValueDataCell
;
4108 BLOCK_OFFSET ValueCellOffset
;
4109 BLOCK_OFFSET ValueDataCellOffset
;
4110 ULONG NewValueListCellSize
;
4111 ULONG NewValueCellSize
;
4114 NewValueListCellSize
=
4115 ROUND_UP(SrcKeyCell
->NumberOfValues
, 4) * sizeof(BLOCK_OFFSET
);
4116 Status
= CmiAllocateCell (DstHive
,
4117 NewValueListCellSize
,
4118 (PVOID
)&NewValueListCell
,
4119 &NewKeyCell
->ValueListOffset
);
4120 if (!NT_SUCCESS(Status
))
4122 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4126 RtlZeroMemory (NewValueListCell
,
4127 NewValueListCellSize
);
4130 SrcValueListCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ValueListOffset
, NULL
);
4131 for (i
= 0; i
< SrcKeyCell
->NumberOfValues
; i
++)
4133 /* Copy value cell */
4134 SrcValueCell
= CmiGetCell (SrcHive
, SrcValueListCell
->ValueOffset
[i
], NULL
);
4136 NewValueCellSize
= sizeof(VALUE_CELL
) + SrcValueCell
->NameSize
;
4137 Status
= CmiAllocateCell (DstHive
,
4139 (PVOID
*) &NewValueCell
,
4141 if (!NT_SUCCESS(Status
))
4143 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4147 NewValueListCell
->ValueOffset
[i
] = ValueCellOffset
;
4148 RtlCopyMemory (NewValueCell
,
4152 /* Copy value data cell */
4153 if (SrcValueCell
->DataSize
> (LONG
) sizeof(PVOID
))
4155 SrcValueDataCell
= CmiGetCell (SrcHive
, SrcValueCell
->DataOffset
, NULL
);
4157 Status
= CmiAllocateCell (DstHive
,
4158 sizeof(CELL_HEADER
) + SrcValueCell
->DataSize
,
4159 (PVOID
*) &NewValueDataCell
,
4160 &ValueDataCellOffset
);
4161 if (!NT_SUCCESS(Status
))
4163 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4166 RtlCopyMemory (NewValueDataCell
,
4168 SrcValueCell
->DataSize
);
4169 NewValueCell
->DataOffset
= ValueDataCellOffset
;
4175 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4177 PHASH_TABLE_CELL SrcHashTableCell
;
4178 PKEY_CELL SrcSubKeyCell
;
4179 PKEY_CELL NewSubKeyCell
;
4180 ULONG NewSubKeyCellSize
;
4181 BLOCK_OFFSET NewSubKeyCellOffset
;
4182 PHASH_RECORD SrcHashRecord
;
4184 SrcHashTableCell
= CmiGetCell (SrcHive
,
4185 SrcKeyCell
->HashTableOffset
,
4188 for (i
= 0; i
< SrcKeyCell
->NumberOfSubKeys
; i
++)
4190 SrcHashRecord
= &SrcHashTableCell
->Table
[i
];
4191 SrcSubKeyCell
= CmiGetCell (SrcHive
, SrcHashRecord
->KeyOffset
, NULL
);
4193 /* Allocate and copy key cell */
4194 NewSubKeyCellSize
= sizeof(KEY_CELL
) + SrcSubKeyCell
->NameSize
;
4195 Status
= CmiAllocateCell (DstHive
,
4197 (PVOID
)&NewSubKeyCell
,
4198 &NewSubKeyCellOffset
);
4199 if (!NT_SUCCESS(Status
))
4201 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4204 if (NewKeyCell
== NULL
)
4206 DPRINT1 ("Failed to allocate a sub key cell\n");
4207 return STATUS_INSUFFICIENT_RESOURCES
;
4210 NewHashTableCell
->Table
[i
].KeyOffset
= NewSubKeyCellOffset
;
4211 NewHashTableCell
->Table
[i
].HashValue
= SrcHashRecord
->HashValue
;
4213 RtlCopyMemory (NewSubKeyCell
,
4217 /* Copy class name */
4218 if (SrcSubKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4220 PDATA_CELL SrcClassNameCell
;
4221 PDATA_CELL NewClassNameCell
;
4222 BLOCK_OFFSET NewClassNameOffset
;
4224 SrcClassNameCell
= CmiGetCell (SrcHive
,
4225 SrcSubKeyCell
->ClassNameOffset
,
4228 NewSubKeyCell
->ClassSize
= SrcSubKeyCell
->ClassSize
;
4229 Status
= CmiAllocateCell (DstHive
,
4230 sizeof(CELL_HEADER
) + NewSubKeyCell
->ClassSize
,
4231 (PVOID
)&NewClassNameCell
,
4232 &NewClassNameOffset
);
4233 if (!NT_SUCCESS(Status
))
4235 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4239 NewSubKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4240 RtlCopyMemory (NewClassNameCell
,
4242 NewSubKeyCell
->ClassSize
);
4245 /* Copy subkey data and subkeys */
4246 Status
= CmiCopyKey (DstHive
,
4250 if (!NT_SUCCESS(Status
))
4252 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4258 return STATUS_SUCCESS
;
4263 CmiSaveTempHive (PREGISTRY_HIVE Hive
,
4266 IO_STATUS_BLOCK IoStatusBlock
;
4267 LARGE_INTEGER FileOffset
;
4272 DPRINT ("CmiSaveTempHive() called\n");
4274 Hive
->HiveHeader
->Checksum
= CmiCalcChecksum ((PULONG
)Hive
->HiveHeader
);
4276 /* Write hive block */
4277 FileOffset
.QuadPart
= (ULONGLONG
)0;
4278 Status
= NtWriteFile (FileHandle
,
4284 sizeof(HIVE_HEADER
),
4287 if (!NT_SUCCESS(Status
))
4289 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4293 DPRINT ("Saving %lu blocks\n", Hive
->BlockListSize
);
4294 for (BlockIndex
= 0; BlockIndex
< Hive
->BlockListSize
; BlockIndex
++)
4296 BlockPtr
= Hive
->BlockList
[BlockIndex
].Block
;
4297 DPRINT ("BlockPtr %p\n", BlockPtr
);
4299 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * (ULONGLONG
)REG_BLOCK_SIZE
;
4300 DPRINT ("File offset %I64x\n", FileOffset
.QuadPart
);
4302 /* Write hive block */
4303 Status
= NtWriteFile (FileHandle
,
4312 if (!NT_SUCCESS(Status
))
4314 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4319 Status
= NtFlushBuffersFile (FileHandle
,
4321 if (!NT_SUCCESS(Status
))
4323 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
4326 DPRINT ("CmiSaveTempHive() done\n");