2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/regfile.c
5 * PURPOSE: Registry file manipulation routines
12 #include <internal/ob.h>
13 #include <ntos/minmax.h>
14 #include <reactos/bugcodes.h>
17 #include <internal/debug.h>
22 /* uncomment to enable hive checks (incomplete and probably buggy) */
25 /* LOCAL MACROS *************************************************************/
27 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
29 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
31 BOOLEAN CmiDoVerify
= FALSE
;
34 CmiCalcChecksum(PULONG Buffer
);
36 /* FUNCTIONS ****************************************************************/
39 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header
)
42 RtlZeroMemory(Header
, sizeof(HIVE_HEADER
));
43 Header
->BlockId
= REG_HIVE_ID
;
44 Header
->UpdateCounter1
= 0;
45 Header
->UpdateCounter2
= 0;
46 Header
->DateModified
.u
.LowPart
= 0;
47 Header
->DateModified
.u
.HighPart
= 0;
53 Header
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
54 Header
->BlockSize
= REG_BLOCK_SIZE
;
61 CmiCreateDefaultBinCell(PHBIN BinCell
)
64 RtlZeroMemory(BinCell
, sizeof(HBIN
));
65 BinCell
->BlockId
= REG_BIN_ID
;
66 BinCell
->DateModified
.u
.LowPart
= 0;
67 BinCell
->DateModified
.u
.HighPart
= 0;
68 BinCell
->BlockSize
= REG_BLOCK_SIZE
;
73 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
)
76 RtlZeroMemory(RootKeyCell
, sizeof(KEY_CELL
));
77 RootKeyCell
->CellSize
= -sizeof(KEY_CELL
);
78 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
79 RootKeyCell
->Flags
= REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
;
80 NtQuerySystemTime(&RootKeyCell
->LastWriteTime
);
81 RootKeyCell
->ParentKeyOffset
= 0;
82 RootKeyCell
->NumberOfSubKeys
= 0;
83 RootKeyCell
->HashTableOffset
= -1;
84 RootKeyCell
->NumberOfValues
= 0;
85 RootKeyCell
->ValueListOffset
= -1;
86 RootKeyCell
->SecurityKeyOffset
= 0;
87 RootKeyCell
->ClassNameOffset
= -1;
88 RootKeyCell
->NameSize
= 0;
89 RootKeyCell
->ClassSize
= 0;
94 CmiVerifyBinCell(PHBIN BinCell
)
101 if (BinCell
->BlockId
!= REG_BIN_ID
)
103 DbgPrint("BlockId is %.08x (should be %.08x)\n",
104 BinCell
->BlockId
, REG_BIN_ID
);
105 assert(BinCell
->BlockId
== REG_BIN_ID
);
108 //BinCell->DateModified.dwLowDateTime
110 //BinCell->DateModified.dwHighDateTime
113 if (BinCell
->BlockSize
!= REG_BLOCK_SIZE
)
115 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
116 BinCell
->BlockSize
, REG_BLOCK_SIZE
);
117 assert(BinCell
->BlockSize
== REG_BLOCK_SIZE
);
125 CmiVerifyKeyCell(PKEY_CELL KeyCell
)
132 if (KeyCell
->CellSize
== 0)
134 DbgPrint("CellSize is %d (must not be 0)\n",
136 assert(KeyCell
->CellSize
!= 0);
139 if (KeyCell
->Id
!= REG_KEY_CELL_ID
)
141 DbgPrint("Id is %.08x (should be %.08x)\n",
142 KeyCell
->Id
, REG_KEY_CELL_ID
);
143 assert(KeyCell
->Id
== REG_KEY_CELL_ID
);
148 //KeyCell->LastWriteTime;
150 if (KeyCell
->ParentKeyOffset
< 0)
152 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
153 KeyCell
->ParentKeyOffset
);
154 assert(KeyCell
->ParentKeyOffset
>= 0);
157 if (KeyCell
->NumberOfSubKeys
< 0)
159 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
160 KeyCell
->NumberOfSubKeys
);
161 assert(KeyCell
->NumberOfSubKeys
>= 0);
164 //KeyCell->HashTableOffset;
166 if (KeyCell
->NumberOfValues
< 0)
168 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
169 KeyCell
->NumberOfValues
);
170 assert(KeyCell
->NumberOfValues
>= 0);
173 //KeyCell->ValuesOffset = -1;
175 if (KeyCell
->SecurityKeyOffset
< 0)
177 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
178 KeyCell
->SecurityKeyOffset
);
179 assert(KeyCell
->SecurityKeyOffset
>= 0);
182 //KeyCell->ClassNameOffset = -1;
193 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell
)
198 CmiVerifyKeyCell(RootKeyCell
);
200 if (!(RootKeyCell
->Flags
& REG_KEY_ROOT_CELL
))
202 DbgPrint("Flags is %.08x (should be %.08x)\n",
203 RootKeyCell
->Flags
, REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
);
204 assert(!(RootKeyCell
->Flags
& (REG_KEY_ROOT_CELL
| REG_KEY_NAME_PACKED
)));
212 CmiVerifyValueCell(PVALUE_CELL ValueCell
)
219 if (ValueCell
->CellSize
== 0)
221 DbgPrint("CellSize is %d (must not be 0)\n",
222 ValueCell
->CellSize
);
223 assert(ValueCell
->CellSize
!= 0);
226 if (ValueCell
->Id
!= REG_VALUE_CELL_ID
)
228 DbgPrint("Id is %.08x (should be %.08x)\n",
229 ValueCell
->Id
, REG_VALUE_CELL_ID
);
230 assert(ValueCell
->Id
== REG_VALUE_CELL_ID
);
233 //ValueCell->NameSize;
234 //ValueCell->LONG DataSize;
235 //ValueCell->DataOffset;
236 //ValueCell->ULONG DataType;
237 //ValueCell->USHORT Flags;
238 //ValueCell->USHORT Unused1;
239 //ValueCell->UCHAR Name[0];
245 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell
)
250 if (ValueListCell
->CellSize
== 0)
252 DbgPrint("CellSize is %d (must not be 0)\n",
253 ValueListCell
->CellSize
);
254 assert(ValueListCell
->CellSize
!= 0);
262 CmiVerifyKeyObject(PKEY_OBJECT KeyObject
)
267 if (KeyObject
->RegistryHive
== NULL
)
269 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
270 KeyObject
->RegistryHive
);
271 assert(KeyObject
->RegistryHive
!= NULL
);
274 if (KeyObject
->KeyCell
== NULL
)
276 DbgPrint("KeyCell is NULL (must not be NULL)\n",
278 assert(KeyObject
->KeyCell
!= NULL
);
281 if (KeyObject
->ParentKey
== NULL
)
283 DbgPrint("ParentKey is NULL (must not be NULL)\n",
284 KeyObject
->ParentKey
);
285 assert(KeyObject
->ParentKey
!= NULL
);
293 CmiVerifyHiveHeader(PHIVE_HEADER Header
)
298 if (Header
->BlockId
!= REG_HIVE_ID
)
300 DbgPrint("BlockId is %.08x (must be %.08x)\n",
303 assert(Header
->BlockId
== REG_HIVE_ID
);
306 if (Header
->Unused3
!= 1)
308 DbgPrint("Unused3 is %.08x (must be 1)\n",
310 assert(Header
->Unused3
== 1);
313 if (Header
->Unused4
!= 3)
315 DbgPrint("Unused4 is %.08x (must be 3)\n",
317 assert(Header
->Unused4
== 3);
320 if (Header
->Unused5
!= 0)
322 DbgPrint("Unused5 is %.08x (must be 0)\n",
324 assert(Header
->Unused5
== 0);
327 if (Header
->Unused6
!= 1)
329 DbgPrint("Unused6 is %.08x (must be 1)\n",
331 assert(Header
->Unused6
== 1);
334 if (Header
->Unused7
!= 1)
336 DbgPrint("Unused7 is %.08x (must be 1)\n",
338 assert(Header
->Unused7
== 1);
346 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive
)
351 CmiVerifyHiveHeader(RegistryHive
->HiveHeader
);
358 CmiCreateNewRegFile(HANDLE FileHandle
)
360 IO_STATUS_BLOCK IoStatusBlock
;
361 PCELL_HEADER FreeCell
;
362 PHIVE_HEADER HiveHeader
;
363 PKEY_CELL RootKeyCell
;
368 Buffer
= (PCHAR
) ExAllocatePool(NonPagedPool
, 2 * REG_BLOCK_SIZE
);
370 return STATUS_INSUFFICIENT_RESOURCES
;
372 HiveHeader
= (PHIVE_HEADER
)Buffer
;
373 BinCell
= (PHBIN
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
);
374 RootKeyCell
= (PKEY_CELL
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
);
375 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
377 CmiCreateDefaultHiveHeader(HiveHeader
);
378 CmiCreateDefaultBinCell(BinCell
);
379 CmiCreateDefaultRootKeyCell(RootKeyCell
);
382 BinCell
->BlockOffset
= 0;
384 /* Offset to root key block */
385 HiveHeader
->RootKeyOffset
= REG_HBIN_DATA_OFFSET
;
387 /* The rest of the block is free */
388 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
390 Status
= NtWriteFile(FileHandle
,
402 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
404 if (!NT_SUCCESS(Status
))
409 Status
= NtFlushBuffersFile(FileHandle
,
418 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive
)
420 OBJECT_ATTRIBUTES ObjectAttributes
;
421 FILE_STANDARD_INFORMATION fsi
;
422 IO_STATUS_BLOCK IoStatusBlock
;
423 HANDLE HiveHandle
= INVALID_HANDLE_VALUE
;
424 HANDLE LogHandle
= INVALID_HANDLE_VALUE
;
425 PHIVE_HEADER HiveHeader
= NULL
;
426 PHIVE_HEADER LogHeader
= NULL
;
427 LARGE_INTEGER FileOffset
;
431 RTL_BITMAP BlockBitMap
;
434 DPRINT("CmiCheckAndFixHive() called\n");
436 /* Try to open the hive file */
437 InitializeObjectAttributes(&ObjectAttributes
,
438 &RegistryHive
->HiveFileName
,
443 Status
= NtCreateFile(&HiveHandle
,
444 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
448 FILE_ATTRIBUTE_NORMAL
,
451 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
454 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
456 return(STATUS_SUCCESS
);
458 if (!NT_SUCCESS(Status
))
460 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
464 /* Try to open the log file */
465 InitializeObjectAttributes(&ObjectAttributes
,
466 &RegistryHive
->LogFileName
,
471 Status
= NtCreateFile(&LogHandle
,
472 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
476 FILE_ATTRIBUTE_NORMAL
,
479 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
482 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
484 LogHandle
= INVALID_HANDLE_VALUE
;
486 else if (!NT_SUCCESS(Status
))
488 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
493 /* Allocate hive header */
494 HiveHeader
= ExAllocatePool(PagedPool
,
495 sizeof(HIVE_HEADER
));
496 if (HiveHeader
== NULL
)
498 DPRINT("ExAllocatePool() failed\n");
499 Status
= STATUS_INSUFFICIENT_RESOURCES
;
503 /* Read hive base block */
504 FileOffset
.QuadPart
= 0ULL;
505 Status
= NtReadFile(HiveHandle
,
514 if (!NT_SUCCESS(Status
))
516 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
520 if (LogHandle
== INVALID_HANDLE_VALUE
)
522 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
523 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
525 /* There is no way to fix the hive without log file - BSOD! */
526 DPRINT("Hive header inconsistent and no log file available!\n");
527 KEBUGCHECK(CONFIG_LIST_FAILED
);
530 Status
= STATUS_SUCCESS
;
535 /* Allocate hive header */
536 LogHeader
= ExAllocatePool(PagedPool
,
537 sizeof(HIVE_HEADER
));
538 if (LogHeader
== NULL
)
540 DPRINT("ExAllocatePool() failed\n");
541 Status
= STATUS_INSUFFICIENT_RESOURCES
;
545 /* Read log file header */
546 FileOffset
.QuadPart
= 0ULL;
547 Status
= NtReadFile(LogHandle
,
556 if (!NT_SUCCESS(Status
))
558 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
562 /* Check log file header integrity */
563 if (LogHeader
->Checksum
!= CmiCalcChecksum((PULONG
)LogHeader
) ||
564 LogHeader
->UpdateCounter1
!= LogHeader
->UpdateCounter2
)
566 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
567 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
569 DPRINT("Hive file and log file are inconsistent!\n");
570 KEBUGCHECK(CONFIG_LIST_FAILED
);
573 /* Log file damaged but hive is okay */
574 Status
= STATUS_SUCCESS
;
578 if (HiveHeader
->UpdateCounter1
== HiveHeader
->UpdateCounter2
&&
579 HiveHeader
->UpdateCounter1
== LogHeader
->UpdateCounter1
)
581 /* Hive and log file are up-to-date */
582 Status
= STATUS_SUCCESS
;
587 * Hive needs an update!
591 Status
= NtQueryInformationFile(LogHandle
,
595 FileStandardInformation
);
596 if (!NT_SUCCESS(Status
))
598 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
601 FileSize
= fsi
.EndOfFile
.u
.LowPart
;
603 /* Calculate bitmap and block size */
604 BitmapSize
= ROUND_UP((FileSize
/ 4096) - 1, sizeof(ULONG
) * 8) / 8;
605 BufferSize
= sizeof(HIVE_HEADER
) +
608 BufferSize
= ROUND_UP(BufferSize
, 4096);
610 /* Reallocate log header block */
611 ExFreePool(LogHeader
);
612 LogHeader
= ExAllocatePool(PagedPool
,
614 if (LogHeader
== NULL
)
616 DPRINT("ExAllocatePool() failed\n");
617 Status
= STATUS_INSUFFICIENT_RESOURCES
;
621 /* Read log file header */
622 FileOffset
.QuadPart
= 0ULL;
623 Status
= NtReadFile(LogHandle
,
632 if (!NT_SUCCESS(Status
))
634 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
638 /* Initialize bitmap */
639 RtlInitializeBitMap(&BlockBitMap
,
640 (PVOID
)((ULONG
)LogHeader
+ 4096 + sizeof(ULONG
)),
643 /* FIXME: Update dirty blocks */
646 /* FIXME: Update hive header */
649 Status
= STATUS_SUCCESS
;
653 /* Clean up the mess */
655 if (HiveHeader
!= NULL
)
656 ExFreePool(HiveHeader
);
658 if (LogHeader
!= NULL
)
659 ExFreePool(LogHeader
);
661 if (LogHandle
!= INVALID_HANDLE_VALUE
)
672 CmiImportHiveBins(PREGISTRY_HIVE Hive
,
675 BLOCK_OFFSET BlockOffset
;
682 while (BlockIndex
< Hive
->BlockListSize
)
684 Bin
= (PHBIN
)((ULONG_PTR
)ChunkPtr
+ BlockOffset
);
686 if (Bin
->BlockId
!= REG_BIN_ID
)
688 DPRINT1 ("Bad BlockId %x, offset %x\n", Bin
->BlockId
, BlockOffset
);
689 return STATUS_REGISTRY_CORRUPT
;
692 assertmsg((Bin
->BlockSize
% 4096) == 0,
693 ("BlockSize (0x%.08x) must be multiple of 4K\n",
696 /* Allocate the hive block */
697 Hive
->BlockList
[BlockIndex
] = ExAllocatePool (PagedPool
,
699 if (Hive
->BlockList
[BlockIndex
] == NULL
)
701 DPRINT1 ("ExAllocatePool() failed\n");
702 return STATUS_INSUFFICIENT_RESOURCES
;
706 RtlCopyMemory (Hive
->BlockList
[BlockIndex
],
710 if (Bin
->BlockSize
> 4096)
712 for (j
= 1; j
< Bin
->BlockSize
/ 4096; j
++)
714 Hive
->BlockList
[BlockIndex
+ j
] = Hive
->BlockList
[BlockIndex
];
718 BlockIndex
+= Bin
->BlockSize
/ 4096;
719 BlockOffset
+= Bin
->BlockSize
;
722 return STATUS_SUCCESS
;
727 CmiFreeHiveBins (PREGISTRY_HIVE Hive
)
733 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
735 if (Hive
->BlockList
[i
] == NULL
)
738 if (Hive
->BlockList
[i
] != Bin
)
740 Bin
= Hive
->BlockList
[i
];
741 ExFreePool (Hive
->BlockList
[i
]);
743 Hive
->BlockList
[i
] = NULL
;
749 CmiCreateHiveFreeCellList(PREGISTRY_HIVE Hive
)
751 BLOCK_OFFSET BlockOffset
;
752 PCELL_HEADER FreeBlock
;
758 /* Initialize the free cell list */
759 Hive
->FreeListSize
= 0;
760 Hive
->FreeListMax
= 0;
761 Hive
->FreeList
= NULL
;
762 Hive
->FreeListOffset
= NULL
;
766 while (BlockIndex
< Hive
->BlockListSize
)
768 Bin
= Hive
->BlockList
[BlockIndex
];
770 /* Search free blocks and add to list */
771 FreeOffset
= REG_HBIN_DATA_OFFSET
;
772 while (FreeOffset
< Bin
->BlockSize
)
774 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) Bin
+ FreeOffset
);
775 if (FreeBlock
->CellSize
> 0)
777 Status
= CmiAddFree(Hive
,
779 Bin
->BlockOffset
+ FreeOffset
,
782 if (!NT_SUCCESS(Status
))
787 FreeOffset
+= FreeBlock
->CellSize
;
791 FreeOffset
-= FreeBlock
->CellSize
;
795 BlockIndex
+= Bin
->BlockSize
/ 4096;
796 BlockOffset
+= Bin
->BlockSize
;
799 return STATUS_SUCCESS
;
804 CmiFreeHiveFreeCellList(PREGISTRY_HIVE Hive
)
806 ExFreePool (Hive
->FreeList
);
807 ExFreePool (Hive
->FreeListOffset
);
809 Hive
->FreeListSize
= 0;
810 Hive
->FreeListMax
= 0;
811 Hive
->FreeList
= NULL
;
812 Hive
->FreeListOffset
= NULL
;
817 CmiCreateHiveBitmap(PREGISTRY_HIVE Hive
)
821 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
822 BitmapSize
= ROUND_UP(Hive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
823 DPRINT("Hive->BlockListSize: %lu\n", Hive
->BlockListSize
);
824 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
826 /* Allocate bitmap */
827 Hive
->BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
829 if (Hive
->BitmapBuffer
== NULL
)
831 return STATUS_INSUFFICIENT_RESOURCES
;
834 RtlInitializeBitMap(&Hive
->DirtyBitMap
,
838 /* Initialize bitmap */
839 RtlClearAllBits(&Hive
->DirtyBitMap
);
840 Hive
->HiveDirty
= FALSE
;
842 return STATUS_SUCCESS
;
847 CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive
,
850 OBJECT_ATTRIBUTES ObjectAttributes
;
851 ULONG CreateDisposition
;
852 IO_STATUS_BLOCK IoSB
;
854 HANDLE SectionHandle
;
859 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) called\n",
860 RegistryHive
, Filename
);
862 /* Duplicate Filename */
863 Status
= RtlCreateUnicodeString(&RegistryHive
->HiveFileName
,
865 if (!NT_SUCCESS(Status
))
867 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status
);
871 /* Create log file name */
872 RegistryHive
->LogFileName
.Length
= (wcslen(Filename
) + 4) * sizeof(WCHAR
);
873 RegistryHive
->LogFileName
.MaximumLength
= RegistryHive
->LogFileName
.Length
+ sizeof(WCHAR
);
874 RegistryHive
->LogFileName
.Buffer
= ExAllocatePool(NonPagedPool
,
875 RegistryHive
->LogFileName
.MaximumLength
);
876 if (RegistryHive
->LogFileName
.Buffer
== NULL
)
878 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
879 DPRINT("ExAllocatePool() failed\n");
880 return(STATUS_INSUFFICIENT_RESOURCES
);
882 wcscpy(RegistryHive
->LogFileName
.Buffer
,
884 wcscat(RegistryHive
->LogFileName
.Buffer
,
888 /* Check and eventually fix a hive */
889 Status
= CmiCheckAndFixHive(RegistryHive
);
890 if (!NT_SUCCESS(Status
))
892 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
893 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
894 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status
);
899 InitializeObjectAttributes(&ObjectAttributes
,
900 &RegistryHive
->HiveFileName
,
905 CreateDisposition
= FILE_OPEN_IF
;
906 Status
= NtCreateFile(&FileHandle
,
911 FILE_ATTRIBUTE_NORMAL
,
914 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
917 if (!NT_SUCCESS(Status
))
919 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
920 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
921 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
925 if (IoSB
.Information
!= FILE_OPENED
)
927 Status
= CmiCreateNewRegFile(FileHandle
);
928 if (!NT_SUCCESS(Status
))
930 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status
);
932 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
933 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
938 /* Create the hive section */
939 Status
= NtCreateSection(&SectionHandle
,
947 if (!NT_SUCCESS(Status
))
949 DPRINT1("NtCreateSection() failed (Status %lx)\n", Status
);
950 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
951 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
955 /* Map the hive file */
958 Status
= NtMapViewOfSection(SectionHandle
,
968 if (!NT_SUCCESS(Status
))
970 DPRINT1("MmMapViewInSystemSpace() failed (Status %lx)\n", Status
);
971 NtClose(SectionHandle
);
972 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
973 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
976 DPRINT("ViewBase %p ViewSize %lx\n", ViewBase
, ViewSize
);
978 /* Copy hive header and initalize hive */
979 RtlCopyMemory (RegistryHive
->HiveHeader
,
981 sizeof(HIVE_HEADER
));
982 RegistryHive
->FileSize
= ViewSize
;
983 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ 4096) - 1;
984 RegistryHive
->UpdateCounter
= RegistryHive
->HiveHeader
->UpdateCounter1
;
986 /* Allocate hive block list */
987 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
988 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
989 if (RegistryHive
->BlockList
== NULL
)
991 DPRINT1("Failed to allocate the hive block list\n");
992 NtUnmapViewOfSection(NtCurrentProcess(),
994 NtClose(SectionHandle
);
995 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
996 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
997 return STATUS_INSUFFICIENT_RESOURCES
;
1000 /* Import the hive bins */
1001 Status
= CmiImportHiveBins (RegistryHive
,
1003 if (!NT_SUCCESS(Status
))
1005 ExFreePool(RegistryHive
->BlockList
);
1006 NtUnmapViewOfSection(NtCurrentProcess(),
1008 NtClose(SectionHandle
);
1009 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1010 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1014 /* Unmap and dereference the hive section */
1015 NtUnmapViewOfSection(NtCurrentProcess(),
1017 NtClose(SectionHandle
);
1019 /* Initialize the free cell list */
1020 Status
= CmiCreateHiveFreeCellList (RegistryHive
);
1021 if (!NT_SUCCESS(Status
))
1023 CmiFreeHiveBins(RegistryHive
);
1024 ExFreePool(RegistryHive
->BlockList
);
1025 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1026 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1030 /* Create the block bitmap */
1031 Status
= CmiCreateHiveBitmap (RegistryHive
);
1032 if (!NT_SUCCESS(Status
))
1034 CmiFreeHiveFreeCellList(RegistryHive
);
1035 CmiFreeHiveBins(RegistryHive
);
1036 ExFreePool(RegistryHive
->BlockList
);
1037 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
1038 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
1042 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n",
1043 RegistryHive
, Filename
);
1045 return(STATUS_SUCCESS
);
1050 CmiCreateVolatileHive(PREGISTRY_HIVE
*RegistryHive
)
1052 PKEY_CELL RootKeyCell
;
1053 PREGISTRY_HIVE Hive
;
1055 *RegistryHive
= NULL
;
1057 Hive
= ExAllocatePool (NonPagedPool
,
1058 sizeof(REGISTRY_HIVE
));
1060 return STATUS_INSUFFICIENT_RESOURCES
;
1062 RtlZeroMemory (Hive
,
1063 sizeof(REGISTRY_HIVE
));
1065 DPRINT("Hive %x\n", Hive
);
1067 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1068 sizeof(HIVE_HEADER
));
1069 if (Hive
->HiveHeader
== NULL
)
1072 return STATUS_INSUFFICIENT_RESOURCES
;
1075 Hive
->Flags
= (HIVE_NO_FILE
| HIVE_POINTER
);
1077 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1079 RootKeyCell
= (PKEY_CELL
)ExAllocatePool (NonPagedPool
,
1081 if (RootKeyCell
== NULL
)
1083 ExFreePool(Hive
->HiveHeader
);
1085 return STATUS_INSUFFICIENT_RESOURCES
;
1088 CmiCreateDefaultRootKeyCell (RootKeyCell
);
1089 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)RootKeyCell
;
1091 ExInitializeResourceLite (&Hive
->HiveResource
);
1093 /* Acquire hive list lock exclusively */
1094 KeEnterCriticalRegion();
1095 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1098 /* Add the new hive to the hive list */
1099 InsertTailList (&CmiHiveListHead
,
1102 /* Release hive list lock */
1103 ExReleaseResourceLite (&CmiHiveListLock
);
1104 KeLeaveCriticalRegion();
1106 VERIFY_REGISTRY_HIVE (Hive
);
1108 *RegistryHive
= Hive
;
1110 return STATUS_SUCCESS
;
1115 CmiCreateTempHive(PREGISTRY_HIVE
*RegistryHive
)
1118 PCELL_HEADER FreeCell
;
1119 PREGISTRY_HIVE Hive
;
1122 DPRINT ("CmiCreateTempHive() called\n");
1124 *RegistryHive
= NULL
;
1126 Hive
= ExAllocatePool (NonPagedPool
,
1127 sizeof(REGISTRY_HIVE
));
1130 DPRINT1 ("Failed to allocate registry hive block\n");
1131 return STATUS_INSUFFICIENT_RESOURCES
;
1133 RtlZeroMemory (Hive
,
1134 sizeof(REGISTRY_HIVE
));
1136 DPRINT ("Hive %x\n", Hive
);
1138 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool (NonPagedPool
,
1140 if (Hive
->HiveHeader
== NULL
)
1142 DPRINT1 ("Failed to allocate hive header block\n");
1144 return STATUS_INSUFFICIENT_RESOURCES
;
1146 RtlZeroMemory (Hive
->HiveHeader
,
1149 DPRINT ("HiveHeader %x\n", Hive
->HiveHeader
);
1151 Hive
->Flags
= HIVE_NO_FILE
;
1153 RtlInitUnicodeString (&Hive
->HiveFileName
,
1155 RtlInitUnicodeString (&Hive
->LogFileName
,
1158 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
1160 /* Allocate hive block list */
1161 Hive
->BlockList
= ExAllocatePool (NonPagedPool
,
1163 if (Hive
->BlockList
== NULL
)
1165 DPRINT1 ("Failed to allocate hive block list\n");
1166 ExFreePool(Hive
->HiveHeader
);
1168 return STATUS_INSUFFICIENT_RESOURCES
;
1171 /* Allocate first Bin */
1172 Hive
->BlockList
[0] = ExAllocatePool (NonPagedPool
,
1174 if (Hive
->BlockList
[0] == NULL
)
1176 DPRINT1 ("Failed to allocate first bin\n");
1177 ExFreePool(Hive
->BlockList
);
1178 ExFreePool(Hive
->HiveHeader
);
1180 return STATUS_INSUFFICIENT_RESOURCES
;
1183 Hive
->FileSize
= 2* REG_BLOCK_SIZE
;
1184 Hive
->BlockListSize
= 1;
1185 Hive
->UpdateCounter
= Hive
->HiveHeader
->UpdateCounter1
;
1188 BinCell
= (PHBIN
)Hive
->BlockList
[0];
1189 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)BinCell
+ REG_HBIN_DATA_OFFSET
);
1191 CmiCreateDefaultBinCell (BinCell
);
1194 BinCell
->BlockOffset
= 0;
1196 /* Offset to root key block */
1197 Hive
->HiveHeader
->RootKeyOffset
= (BLOCK_OFFSET
)-1;
1199 /* The rest of the block is free */
1200 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
1202 /* Create the free cell list */
1203 Status
= CmiCreateHiveFreeCellList (Hive
);
1204 if (Hive
->BlockList
[0] == NULL
)
1206 DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status
);
1207 ExFreePool(Hive
->BlockList
[0]);
1208 ExFreePool(Hive
->BlockList
);
1209 ExFreePool(Hive
->HiveHeader
);
1215 ExInitializeResourceLite (&Hive
->HiveResource
);
1217 /* Acquire hive list lock exclusively */
1218 KeEnterCriticalRegion();
1219 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1222 /* Add the new hive to the hive list */
1223 InsertTailList (&CmiHiveListHead
,
1226 /* Release hive list lock */
1227 ExReleaseResourceLite (&CmiHiveListLock
);
1228 KeLeaveCriticalRegion();
1230 VERIFY_REGISTRY_HIVE (Hive
);
1232 *RegistryHive
= Hive
;
1234 return STATUS_SUCCESS
;
1239 CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1240 IN PUNICODE_STRING FileName
,
1243 PREGISTRY_HIVE Hive
;
1246 DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName
);
1248 if (Flags
& ~REG_NO_LAZY_FLUSH
)
1249 return STATUS_INVALID_PARAMETER
;
1251 Hive
= ExAllocatePool (NonPagedPool
,
1252 sizeof(REGISTRY_HIVE
));
1255 DPRINT1 ("Failed to allocate hive header.\n");
1256 return STATUS_INSUFFICIENT_RESOURCES
;
1258 RtlZeroMemory (Hive
,
1259 sizeof(REGISTRY_HIVE
));
1261 DPRINT ("Hive %x\n", Hive
);
1262 Hive
->Flags
= (Flags
& REG_NO_LAZY_FLUSH
) ? HIVE_NO_SYNCH
: 0;
1264 Hive
->HiveHeader
= (PHIVE_HEADER
)ExAllocatePool(NonPagedPool
,
1265 sizeof(HIVE_HEADER
));
1266 if (Hive
->HiveHeader
== NULL
)
1268 DPRINT1 ("Failed to allocate hive header.\n");
1270 return STATUS_INSUFFICIENT_RESOURCES
;
1273 Status
= CmiInitNonVolatileRegistryHive (Hive
,
1275 if (!NT_SUCCESS (Status
))
1277 DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status
);
1278 ExFreePool (Hive
->HiveHeader
);
1283 ExInitializeResourceLite (&Hive
->HiveResource
);
1285 /* Add the new hive to the hive list */
1286 KeEnterCriticalRegion();
1287 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1289 InsertTailList (&CmiHiveListHead
,
1291 ExReleaseResourceLite (&CmiHiveListLock
);
1292 KeLeaveCriticalRegion();
1295 VERIFY_REGISTRY_HIVE(Hive
);
1298 Status
= CmiConnectHive (KeyObjectAttributes
,
1300 if (!NT_SUCCESS(Status
))
1302 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status
);
1303 // CmiRemoveRegistryHive (Hive);
1306 DPRINT ("CmiLoadHive() done\n");
1313 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
1315 if (RegistryHive
->Flags
& HIVE_POINTER
)
1316 return STATUS_UNSUCCESSFUL
;
1318 /* Acquire hive list lock exclusively */
1319 KeEnterCriticalRegion();
1320 ExAcquireResourceExclusiveLite (&CmiHiveListLock
,
1323 /* Remove hive from hive list */
1324 RemoveEntryList (&RegistryHive
->HiveList
);
1326 /* Release hive list lock */
1327 ExReleaseResourceLite (&CmiHiveListLock
);
1328 KeLeaveCriticalRegion();
1330 /* Release file names */
1331 RtlFreeUnicodeString (&RegistryHive
->HiveFileName
);
1332 RtlFreeUnicodeString (&RegistryHive
->LogFileName
);
1334 /* Release hive bitmap */
1335 ExFreePool (RegistryHive
->BitmapBuffer
);
1337 /* Release free cell list */
1338 ExFreePool (RegistryHive
->FreeList
);
1339 ExFreePool (RegistryHive
->FreeListOffset
);
1341 /* Release hive resource */
1342 ExDeleteResource (&RegistryHive
->HiveResource
);
1344 /* Release bins and bin list */
1345 CmiFreeHiveBins (RegistryHive
);
1346 ExFreePool (RegistryHive
->BlockList
);
1348 /* Release hive header */
1349 ExFreePool (RegistryHive
->HiveHeader
);
1352 ExFreePool (RegistryHive
);
1354 return STATUS_SUCCESS
;
1359 CmiCalcChecksum(PULONG Buffer
)
1364 for (i
= 0; i
< 127; i
++)
1372 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
1374 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1375 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1376 OBJECT_ATTRIBUTES ObjectAttributes
;
1377 IO_STATUS_BLOCK IoStatusBlock
;
1379 LARGE_INTEGER FileOffset
;
1388 DPRINT("CmiStartLogUpdate() called\n");
1390 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1391 BufferSize
= sizeof(HIVE_HEADER
) +
1394 BufferSize
= ROUND_UP(BufferSize
, 4096);
1396 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1398 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1401 DPRINT("ExAllocatePool() failed\n");
1402 return(STATUS_INSUFFICIENT_RESOURCES
);
1405 /* Open log file for writing */
1406 InitializeObjectAttributes(&ObjectAttributes
,
1407 &RegistryHive
->LogFileName
,
1412 Status
= NtCreateFile(&FileHandle
,
1417 FILE_ATTRIBUTE_NORMAL
,
1420 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1423 if (!NT_SUCCESS(Status
))
1425 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1430 /* Update firt update counter and checksum */
1431 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1432 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1434 /* Copy hive header */
1435 RtlCopyMemory(Buffer
,
1436 RegistryHive
->HiveHeader
,
1437 sizeof(HIVE_HEADER
));
1438 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1445 RegistryHive
->DirtyBitMap
.Buffer
,
1448 /* Write hive block and block bitmap */
1449 #if defined(__GNUC__)
1450 FileOffset
.QuadPart
= 0ULL;
1452 FileOffset
.QuadPart
= 0;
1454 Status
= NtWriteFile(FileHandle
,
1463 if (!NT_SUCCESS(Status
))
1465 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1466 NtClose(FileHandle
);
1472 /* Write dirty blocks */
1473 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1477 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1480 if ((BlockIndex
== (ULONG
)-1) ||
1481 (BlockIndex
>= RegistryHive
->BlockListSize
))
1483 DPRINT("No more set bits\n");
1484 Status
= STATUS_SUCCESS
;
1488 DPRINT("Block %lu is dirty\n", BlockIndex
);
1490 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
];
1491 DPRINT("BlockPtr %p\n", BlockPtr
);
1492 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1494 /* Write hive block */
1495 Status
= NtWriteFile(FileHandle
,
1504 if (!NT_SUCCESS(Status
))
1506 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1507 NtClose(FileHandle
);
1512 #if defined(__GNUC__)
1513 FileOffset
.QuadPart
+= 4096ULL;
1515 FileOffset
.QuadPart
+= 4096;
1519 /* Truncate log file */
1520 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1521 Status
= NtSetInformationFile(FileHandle
,
1524 sizeof(FILE_END_OF_FILE_INFORMATION
),
1525 FileEndOfFileInformation
);
1526 if (!NT_SUCCESS(Status
))
1528 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1529 NtClose(FileHandle
);
1533 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1534 Status
= NtSetInformationFile(FileHandle
,
1536 &FileAllocationInfo
,
1537 sizeof(FILE_ALLOCATION_INFORMATION
),
1538 FileAllocationInformation
);
1539 if (!NT_SUCCESS(Status
))
1541 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1542 NtClose(FileHandle
);
1546 /* Flush the log file */
1547 Status
= NtFlushBuffersFile(FileHandle
,
1549 if (!NT_SUCCESS(Status
))
1551 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1554 NtClose(FileHandle
);
1561 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1563 OBJECT_ATTRIBUTES ObjectAttributes
;
1564 IO_STATUS_BLOCK IoStatusBlock
;
1566 LARGE_INTEGER FileOffset
;
1573 DPRINT("CmiFinishLogUpdate() called\n");
1575 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1576 BufferSize
= sizeof(HIVE_HEADER
) +
1579 BufferSize
= ROUND_UP(BufferSize
, 4096);
1581 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1583 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1586 DPRINT("ExAllocatePool() failed\n");
1587 return(STATUS_INSUFFICIENT_RESOURCES
);
1590 /* Open log file for writing */
1591 InitializeObjectAttributes(&ObjectAttributes
,
1592 &RegistryHive
->LogFileName
,
1597 Status
= NtCreateFile(&FileHandle
,
1602 FILE_ATTRIBUTE_NORMAL
,
1605 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1608 if (!NT_SUCCESS(Status
))
1610 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1615 /* Update first and second update counter and checksum */
1616 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1617 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1618 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1620 /* Copy hive header */
1621 RtlCopyMemory(Buffer
,
1622 RegistryHive
->HiveHeader
,
1623 sizeof(HIVE_HEADER
));
1624 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1626 /* Write empty block bitmap */
1634 /* Write hive block and block bitmap */
1635 #if defined(__GNUC__)
1636 FileOffset
.QuadPart
= 0ULL;
1638 FileOffset
.QuadPart
= 0;
1640 Status
= NtWriteFile(FileHandle
,
1649 if (!NT_SUCCESS(Status
))
1651 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1652 NtClose(FileHandle
);
1659 /* Flush the log file */
1660 Status
= NtFlushBuffersFile(FileHandle
,
1662 if (!NT_SUCCESS(Status
))
1664 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1667 NtClose(FileHandle
);
1674 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1676 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1677 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1678 OBJECT_ATTRIBUTES ObjectAttributes
;
1679 IO_STATUS_BLOCK IoStatusBlock
;
1685 DPRINT("CmiCleanupLogUpdate() called\n");
1687 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1688 BufferSize
= sizeof(HIVE_HEADER
) +
1691 BufferSize
= ROUND_UP(BufferSize
, 4096);
1693 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1695 /* Open log file for writing */
1696 InitializeObjectAttributes(&ObjectAttributes
,
1697 &RegistryHive
->LogFileName
,
1702 Status
= NtCreateFile(&FileHandle
,
1707 FILE_ATTRIBUTE_NORMAL
,
1710 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1713 if (!NT_SUCCESS(Status
))
1715 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1719 /* Truncate log file */
1720 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1721 Status
= NtSetInformationFile(FileHandle
,
1724 sizeof(FILE_END_OF_FILE_INFORMATION
),
1725 FileEndOfFileInformation
);
1726 if (!NT_SUCCESS(Status
))
1728 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1729 NtClose(FileHandle
);
1733 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1734 Status
= NtSetInformationFile(FileHandle
,
1736 &FileAllocationInfo
,
1737 sizeof(FILE_ALLOCATION_INFORMATION
),
1738 FileAllocationInformation
);
1739 if (!NT_SUCCESS(Status
))
1741 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1742 NtClose(FileHandle
);
1746 /* Flush the log file */
1747 Status
= NtFlushBuffersFile(FileHandle
,
1749 if (!NT_SUCCESS(Status
))
1751 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1754 NtClose(FileHandle
);
1761 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1763 OBJECT_ATTRIBUTES ObjectAttributes
;
1764 IO_STATUS_BLOCK IoStatusBlock
;
1766 LARGE_INTEGER FileOffset
;
1771 DPRINT("CmiStartHiveUpdate() called\n");
1773 /* Open hive for writing */
1774 InitializeObjectAttributes(&ObjectAttributes
,
1775 &RegistryHive
->HiveFileName
,
1780 Status
= NtCreateFile(&FileHandle
,
1785 FILE_ATTRIBUTE_NORMAL
,
1788 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1791 if (!NT_SUCCESS(Status
))
1793 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1797 /* Update firt update counter and checksum */
1798 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1799 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1801 /* Write hive block */
1802 #if defined(__GNUC__)
1803 FileOffset
.QuadPart
= 0ULL;
1805 FileOffset
.QuadPart
= 0;
1807 Status
= NtWriteFile(FileHandle
,
1812 RegistryHive
->HiveHeader
,
1813 sizeof(HIVE_HEADER
),
1816 if (!NT_SUCCESS(Status
))
1818 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1819 NtClose(FileHandle
);
1826 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1829 if ((BlockIndex
== (ULONG
)-1) ||
1830 (BlockIndex
>= RegistryHive
->BlockListSize
))
1832 DPRINT("No more set bits\n");
1833 Status
= STATUS_SUCCESS
;
1837 DPRINT("Block %lu is dirty\n", BlockIndex
);
1839 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
];
1840 DPRINT("BlockPtr %p\n", BlockPtr
);
1842 #if defined(__GNUC__)
1843 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096ULL;
1845 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096;
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
,
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 #if defined(__GNUC__)
1923 FileOffset
.QuadPart
= 0ULL;
1925 FileOffset
.QuadPart
= 0;
1927 Status
= NtWriteFile(FileHandle
,
1932 RegistryHive
->HiveHeader
,
1933 sizeof(HIVE_HEADER
),
1936 if (!NT_SUCCESS(Status
))
1938 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1939 NtClose(FileHandle
);
1943 Status
= NtFlushBuffersFile(FileHandle
,
1945 if (!NT_SUCCESS(Status
))
1947 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1950 NtClose(FileHandle
);
1957 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1961 DPRINT("CmiFlushRegistryHive() called\n");
1963 if (RegistryHive
->HiveDirty
== FALSE
)
1965 return(STATUS_SUCCESS
);
1968 DPRINT("Hive '%wZ' is dirty\n",
1969 &RegistryHive
->HiveFileName
);
1970 DPRINT("Log file: '%wZ'\n",
1971 &RegistryHive
->LogFileName
);
1973 /* Update hive header modification time */
1974 NtQuerySystemTime(&RegistryHive
->HiveHeader
->DateModified
);
1976 /* Start log update */
1977 Status
= CmiStartLogUpdate(RegistryHive
);
1978 if (!NT_SUCCESS(Status
))
1980 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1984 /* Finish log update */
1985 Status
= CmiFinishLogUpdate(RegistryHive
);
1986 if (!NT_SUCCESS(Status
))
1988 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1992 /* Start hive update */
1993 Status
= CmiStartHiveUpdate(RegistryHive
);
1994 if (!NT_SUCCESS(Status
))
1996 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
2000 /* Finish the hive update */
2001 Status
= CmiFinishHiveUpdate(RegistryHive
);
2002 if (!NT_SUCCESS(Status
))
2004 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
2008 /* Cleanup log update */
2009 Status
= CmiCleanupLogUpdate(RegistryHive
);
2010 if (!NT_SUCCESS(Status
))
2012 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
2016 /* Increment hive update counter */
2017 RegistryHive
->UpdateCounter
++;
2019 /* Clear dirty bitmap and dirty flag */
2020 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
2021 RegistryHive
->HiveDirty
= FALSE
;
2023 DPRINT("CmiFlushRegistryHive() done\n");
2025 return(STATUS_SUCCESS
);
2030 CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject
)
2037 VERIFY_KEY_OBJECT(KeyObject
);
2039 KeyCell
= KeyObject
->KeyCell
;
2040 VERIFY_KEY_CELL(KeyCell
);
2042 SubKeyCount
= (KeyCell
== NULL
) ? 0 : KeyCell
->NumberOfSubKeys
;
2044 /* Search for volatile or 'foreign' keys */
2045 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2047 CurKey
= KeyObject
->SubKeys
[i
];
2048 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2049 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2060 CmiGetMaxNameLength(PKEY_OBJECT KeyObject
)
2062 PHASH_TABLE_CELL HashBlock
;
2064 PKEY_CELL CurSubKeyCell
;
2070 VERIFY_KEY_OBJECT(KeyObject
);
2072 KeyCell
= KeyObject
->KeyCell
;
2073 VERIFY_KEY_CELL(KeyCell
);
2076 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2077 KeyCell
->HashTableOffset
,
2079 if (HashBlock
== NULL
)
2081 DPRINT("CmiGetBlock() failed\n");
2085 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2087 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2089 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2090 HashBlock
->Table
[i
].KeyOffset
,
2092 if (CurSubKeyCell
== NULL
)
2094 DPRINT("CmiGetBlock() failed\n");
2097 NameSize
= CurSubKeyCell
->NameSize
;
2098 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2100 NameSize
*= sizeof(WCHAR
);
2102 if (MaxName
< NameSize
)
2110 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2111 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2113 CurKey
= KeyObject
->SubKeys
[i
];
2114 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2115 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2117 CurSubKeyCell
= CurKey
->KeyCell
;
2118 if (CurSubKeyCell
== NULL
)
2120 DPRINT("CmiGetBlock() failed\n");
2124 NameSize
= CurSubKeyCell
->NameSize
;
2125 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2127 NameSize
*= sizeof(WCHAR
);
2130 if (MaxName
< NameSize
)
2142 CmiGetMaxClassLength(PKEY_OBJECT KeyObject
)
2144 PHASH_TABLE_CELL HashBlock
;
2146 PKEY_CELL CurSubKeyCell
;
2151 VERIFY_KEY_OBJECT(KeyObject
);
2153 KeyCell
= KeyObject
->KeyCell
;
2154 VERIFY_KEY_CELL(KeyCell
);
2157 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2158 KeyCell
->HashTableOffset
,
2160 if (HashBlock
== NULL
)
2162 DPRINT("CmiGetBlock() failed\n");
2166 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2168 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2170 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2171 HashBlock
->Table
[i
].KeyOffset
,
2173 if (CurSubKeyCell
== NULL
)
2175 DPRINT("CmiGetBlock() failed\n");
2179 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2181 MaxClass
= CurSubKeyCell
->ClassSize
;
2187 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2188 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2190 CurKey
= KeyObject
->SubKeys
[i
];
2191 if (CurKey
->RegistryHive
== CmiVolatileHive
||
2192 CurKey
->RegistryHive
!= KeyObject
->RegistryHive
)
2194 CurSubKeyCell
= CurKey
->KeyCell
;
2195 if (CurSubKeyCell
== NULL
)
2197 DPRINT("CmiGetBlock() failed\n");
2201 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2203 MaxClass
= CurSubKeyCell
->ClassSize
;
2213 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
2216 PVALUE_LIST_CELL ValueListCell
;
2217 PVALUE_CELL CurValueCell
;
2222 VERIFY_KEY_CELL(KeyCell
);
2225 ValueListCell
= CmiGetCell (RegistryHive
,
2226 KeyCell
->ValueListOffset
,
2228 if (ValueListCell
== NULL
)
2230 DPRINT("CmiGetBlock() failed\n");
2234 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2236 CurValueCell
= CmiGetCell (RegistryHive
,
2237 ValueListCell
->ValueOffset
[i
],
2239 if (CurValueCell
== NULL
)
2241 DPRINT("CmiGetBlock() failed\n");
2244 if (CurValueCell
!= NULL
)
2246 Size
= CurValueCell
->NameSize
;
2247 if (CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
2249 Size
*= sizeof(WCHAR
);
2251 if (MaxValueName
< Size
)
2253 MaxValueName
= Size
;
2258 return MaxValueName
;
2263 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
2266 PVALUE_LIST_CELL ValueListCell
;
2267 PVALUE_CELL CurValueCell
;
2271 VERIFY_KEY_CELL(KeyCell
);
2274 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2275 if (ValueListCell
== NULL
)
2280 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2282 CurValueCell
= CmiGetCell (RegistryHive
,
2283 ValueListCell
->ValueOffset
[i
],NULL
);
2284 if ((CurValueCell
!= NULL
) &&
2285 (MaxValueData
< (LONG
)(CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2287 MaxValueData
= CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2291 return MaxValueData
;
2296 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
2297 IN PKEY_CELL KeyCell
,
2298 OUT PKEY_CELL
*SubKeyCell
,
2299 OUT BLOCK_OFFSET
*BlockOffset
,
2300 IN PUNICODE_STRING KeyName
,
2301 IN ACCESS_MASK DesiredAccess
,
2302 IN ULONG Attributes
)
2304 PHASH_TABLE_CELL HashBlock
;
2305 PKEY_CELL CurSubKeyCell
;
2308 VERIFY_KEY_CELL(KeyCell
);
2310 DPRINT("Scanning for sub key %wZ\n", KeyName
);
2312 assert(RegistryHive
);
2316 /* The key does not have any subkeys */
2317 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
2319 return STATUS_SUCCESS
;
2322 /* Get hash table */
2323 HashBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2324 if (HashBlock
== NULL
)
2326 DPRINT("CmiGetBlock() failed\n");
2327 return STATUS_UNSUCCESSFUL
;
2330 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
) && (i
< HashBlock
->HashTableSize
); i
++)
2332 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2334 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2335 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1 &&
2336 (HashBlock
->Table
[i
].HashValue
== 0 ||
2337 CmiCompareHashI(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2339 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2340 HashBlock
->Table
[i
].KeyOffset
,
2342 if (CurSubKeyCell
== NULL
)
2344 DPRINT("CmiGetBlock() failed\n");
2345 return STATUS_UNSUCCESSFUL
;
2348 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2350 *SubKeyCell
= CurSubKeyCell
;
2351 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2358 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2359 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2360 (HashBlock
->Table
[i
].HashValue
== 0 ||
2361 CmiCompareHash(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2363 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2364 HashBlock
->Table
[i
].KeyOffset
,
2366 if (CurSubKeyCell
== NULL
)
2368 DPRINT("CmiGetBlock() failed\n");
2369 return STATUS_UNSUCCESSFUL
;
2372 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2374 *SubKeyCell
= CurSubKeyCell
;
2375 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2382 return STATUS_SUCCESS
;
2387 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2388 PKEY_OBJECT ParentKey
,
2390 PUNICODE_STRING SubKeyName
,
2392 PUNICODE_STRING Class
,
2393 ULONG CreateOptions
)
2395 PHASH_TABLE_CELL HashBlock
;
2396 BLOCK_OFFSET NKBOffset
;
2397 PKEY_CELL NewKeyCell
;
2399 PKEY_CELL ParentKeyCell
;
2400 PDATA_CELL ClassCell
;
2407 ParentKeyCell
= ParentKey
->KeyCell
;
2409 VERIFY_KEY_CELL(ParentKeyCell
);
2411 /* Skip leading backslash */
2412 if (SubKeyName
->Buffer
[0] == L
'\\')
2414 NamePtr
= &SubKeyName
->Buffer
[1];
2415 NameSize
= SubKeyName
->Length
- sizeof(WCHAR
);
2419 NamePtr
= SubKeyName
->Buffer
;
2420 NameSize
= SubKeyName
->Length
;
2423 /* Check whether key name can be packed */
2425 for (i
= 0; i
< NameSize
/ sizeof(WCHAR
); i
++)
2427 if (NamePtr
[i
] & 0xFF00)
2434 /* Adjust name size */
2437 NameSize
= NameSize
/ sizeof(WCHAR
);
2440 DPRINT("Key %S Length %lu %s\n", NamePtr
, NameSize
, (Packable
)?"True":"False");
2442 Status
= STATUS_SUCCESS
;
2444 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2445 Status
= CmiAllocateCell (RegistryHive
,
2447 (PVOID
) &NewKeyCell
,
2449 if (NewKeyCell
== NULL
)
2451 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2455 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2456 NewKeyCell
->Flags
= 0;
2457 NtQuerySystemTime(&NewKeyCell
->LastWriteTime
);
2458 NewKeyCell
->ParentKeyOffset
= -1;
2459 NewKeyCell
->NumberOfSubKeys
= 0;
2460 NewKeyCell
->HashTableOffset
= -1;
2461 NewKeyCell
->NumberOfValues
= 0;
2462 NewKeyCell
->ValueListOffset
= -1;
2463 NewKeyCell
->SecurityKeyOffset
= -1;
2464 NewKeyCell
->ClassNameOffset
= -1;
2466 /* Pack the key name */
2467 NewKeyCell
->NameSize
= NameSize
;
2470 NewKeyCell
->Flags
|= REG_KEY_NAME_PACKED
;
2471 for (i
= 0; i
< NameSize
; i
++)
2473 NewKeyCell
->Name
[i
] = (CHAR
)(NamePtr
[i
] & 0x00FF);
2478 RtlCopyMemory(NewKeyCell
->Name
,
2483 VERIFY_KEY_CELL(NewKeyCell
);
2487 NewKeyCell
->ClassSize
= Class
->Length
;
2488 Status
= CmiAllocateCell (RegistryHive
,
2489 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
2491 &NewKeyCell
->ClassNameOffset
);
2492 RtlCopyMemory (ClassCell
->Data
,
2498 if (!NT_SUCCESS(Status
))
2503 SubKey
->KeyCell
= NewKeyCell
;
2504 SubKey
->KeyCellOffset
= NKBOffset
;
2506 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2507 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(ParentKey
->RegistryHive
)))
2512 if (ParentKeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2514 Status
= CmiAllocateHashTableCell (RegistryHive
,
2516 &ParentKeyCell
->HashTableOffset
,
2517 REG_INIT_HASH_TABLE_SIZE
);
2518 if (!NT_SUCCESS(Status
))
2525 HashBlock
= CmiGetCell (RegistryHive
,
2526 ParentKeyCell
->HashTableOffset
,
2528 if (HashBlock
== NULL
)
2530 DPRINT("CmiGetCell() failed\n");
2531 return STATUS_UNSUCCESSFUL
;
2534 if (((ParentKeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2536 PHASH_TABLE_CELL NewHashBlock
;
2537 BLOCK_OFFSET HTOffset
;
2539 /* Reallocate the hash table cell */
2540 Status
= CmiAllocateHashTableCell (RegistryHive
,
2543 HashBlock
->HashTableSize
+
2544 REG_EXTEND_HASH_TABLE_SIZE
);
2545 if (!NT_SUCCESS(Status
))
2550 RtlZeroMemory(&NewHashBlock
->Table
[0],
2551 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2552 RtlCopyMemory(&NewHashBlock
->Table
[0],
2553 &HashBlock
->Table
[0],
2554 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2555 CmiDestroyCell (RegistryHive
,
2557 ParentKeyCell
->HashTableOffset
);
2558 ParentKeyCell
->HashTableOffset
= HTOffset
;
2559 HashBlock
= NewHashBlock
;
2563 Status
= CmiAddKeyToHashTable(RegistryHive
,
2565 ParentKeyCell
->HashTableOffset
,
2568 if (NT_SUCCESS(Status
))
2570 ParentKeyCell
->NumberOfSubKeys
++;
2573 NtQuerySystemTime (&ParentKeyCell
->LastWriteTime
);
2574 CmiMarkBlockDirty (RegistryHive
, ParentKey
->KeyCellOffset
);
2581 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2582 PKEY_OBJECT ParentKey
,
2585 PHASH_TABLE_CELL HashBlock
;
2586 PVALUE_LIST_CELL ValueList
;
2587 PVALUE_CELL ValueCell
;
2588 PDATA_CELL DataCell
;
2591 DPRINT("CmiRemoveSubKey() called\n");
2593 /* Remove all values */
2594 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2596 /* Get pointer to the value list cell */
2597 ValueList
= CmiGetCell (RegistryHive
,
2598 SubKey
->KeyCell
->ValueListOffset
,
2600 if (ValueList
== NULL
)
2602 DPRINT("CmiGetCell() failed\n");
2603 return STATUS_UNSUCCESSFUL
;
2606 if (ValueList
!= NULL
)
2608 /* Enumerate all values */
2609 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2611 /* Get pointer to value cell */
2612 ValueCell
= CmiGetCell (RegistryHive
,
2613 ValueList
->ValueOffset
[i
],
2615 if (ValueCell
!= NULL
)
2617 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
2619 DataCell
= CmiGetCell (RegistryHive
,
2620 ValueCell
->DataOffset
,
2622 if (DataCell
== NULL
)
2624 DPRINT("CmiGetCell() failed\n");
2625 return STATUS_UNSUCCESSFUL
;
2628 if (DataCell
!= NULL
)
2630 /* Destroy data cell */
2631 CmiDestroyCell (RegistryHive
,
2633 ValueCell
->DataOffset
);
2637 /* Destroy value cell */
2638 CmiDestroyCell (RegistryHive
,
2640 ValueList
->ValueOffset
[i
]);
2645 /* Destroy value list cell */
2646 CmiDestroyCell (RegistryHive
,
2648 SubKey
->KeyCell
->ValueListOffset
);
2650 SubKey
->KeyCell
->NumberOfValues
= 0;
2651 SubKey
->KeyCell
->ValueListOffset
= (BLOCK_OFFSET
)-1;
2654 /* Remove the key from the parent key's hash block */
2655 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2657 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2658 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2659 ParentKey
->KeyCell
->HashTableOffset
,
2661 if (HashBlock
== NULL
)
2663 DPRINT("CmiGetCell() failed\n");
2664 return STATUS_UNSUCCESSFUL
;
2666 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2667 if (HashBlock
!= NULL
)
2669 CmiRemoveKeyFromHashTable(ParentKey
->RegistryHive
,
2671 SubKey
->KeyCellOffset
);
2672 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2673 ParentKey
->KeyCell
->HashTableOffset
);
2677 /* Remove the key's hash block */
2678 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2680 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
);
2681 HashBlock
= CmiGetCell (RegistryHive
,
2682 SubKey
->KeyCell
->HashTableOffset
,
2684 if (HashBlock
== NULL
)
2686 DPRINT("CmiGetCell() failed\n");
2687 return STATUS_UNSUCCESSFUL
;
2689 DPRINT("SubKey HashBlock %p\n", HashBlock
);
2690 if (HashBlock
!= NULL
)
2692 CmiDestroyCell (RegistryHive
,
2694 SubKey
->KeyCell
->HashTableOffset
);
2695 SubKey
->KeyCell
->HashTableOffset
= -1;
2699 /* Decrement the number of the parent key's sub keys */
2700 if (ParentKey
!= NULL
)
2702 DPRINT("ParentKey %p\n", ParentKey
);
2703 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2705 /* Remove the parent key's hash table */
2706 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2708 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2709 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2710 ParentKey
->KeyCell
->HashTableOffset
,
2712 if (HashBlock
== NULL
)
2714 DPRINT("CmiGetCell() failed\n");
2715 return STATUS_UNSUCCESSFUL
;
2717 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2718 if (HashBlock
!= NULL
)
2720 CmiDestroyCell (ParentKey
->RegistryHive
,
2722 ParentKey
->KeyCell
->HashTableOffset
);
2723 ParentKey
->KeyCell
->HashTableOffset
= (BLOCK_OFFSET
)-1;
2727 NtQuerySystemTime(&ParentKey
->KeyCell
->LastWriteTime
);
2728 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2729 ParentKey
->KeyCellOffset
);
2732 /* Destroy key cell */
2733 CmiDestroyCell (RegistryHive
,
2735 SubKey
->KeyCellOffset
);
2736 SubKey
->KeyCell
= NULL
;
2737 SubKey
->KeyCellOffset
= (BLOCK_OFFSET
)-1;
2739 return(STATUS_SUCCESS
);
2744 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2745 IN PKEY_CELL KeyCell
,
2746 IN PUNICODE_STRING ValueName
,
2747 OUT PVALUE_CELL
*ValueCell
,
2748 OUT BLOCK_OFFSET
*ValueCellOffset
)
2750 PVALUE_LIST_CELL ValueListCell
;
2751 PVALUE_CELL CurValueCell
;
2755 if (ValueCellOffset
!= NULL
)
2756 *ValueCellOffset
= (BLOCK_OFFSET
)-1;
2758 /* The key does not have any values */
2759 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2761 return STATUS_OBJECT_NAME_NOT_FOUND
;
2764 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2765 if (ValueListCell
== NULL
)
2767 DPRINT("ValueListCell is NULL\n");
2768 return STATUS_UNSUCCESSFUL
;
2771 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2773 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2775 CurValueCell
= CmiGetCell (RegistryHive
,
2776 ValueListCell
->ValueOffset
[i
],
2778 if (CurValueCell
== NULL
)
2780 DPRINT("CmiGetBlock() failed\n");
2781 return STATUS_UNSUCCESSFUL
;
2784 if ((CurValueCell
!= NULL
) &&
2785 CmiComparePackedNames(ValueName
,
2787 CurValueCell
->NameSize
,
2788 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2790 *ValueCell
= CurValueCell
;
2791 if (ValueCellOffset
!= NULL
)
2792 *ValueCellOffset
= ValueListCell
->ValueOffset
[i
];
2793 //DPRINT("Found value %s\n", ValueName);
2794 return STATUS_SUCCESS
;
2798 return STATUS_OBJECT_NAME_NOT_FOUND
;
2803 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2804 IN PKEY_CELL KeyCell
,
2806 OUT PVALUE_CELL
*ValueCell
)
2808 PVALUE_LIST_CELL ValueListCell
;
2809 PVALUE_CELL CurValueCell
;
2813 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2815 return STATUS_NO_MORE_ENTRIES
;
2818 if (Index
>= KeyCell
->NumberOfValues
)
2820 return STATUS_NO_MORE_ENTRIES
;
2824 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2825 if (ValueListCell
== NULL
)
2827 DPRINT("CmiGetBlock() failed\n");
2828 return STATUS_UNSUCCESSFUL
;
2831 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2834 CurValueCell
= CmiGetCell (RegistryHive
,
2835 ValueListCell
->ValueOffset
[Index
],
2837 if (CurValueCell
== NULL
)
2839 DPRINT("CmiGetBlock() failed\n");
2840 return STATUS_UNSUCCESSFUL
;
2843 *ValueCell
= CurValueCell
;
2845 return STATUS_SUCCESS
;
2850 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2851 IN PKEY_CELL KeyCell
,
2852 IN BLOCK_OFFSET KeyCellOffset
,
2853 IN PUNICODE_STRING ValueName
,
2854 OUT PVALUE_CELL
*pValueCell
,
2855 OUT BLOCK_OFFSET
*pValueCellOffset
)
2857 PVALUE_LIST_CELL NewValueListCell
;
2858 PVALUE_LIST_CELL ValueListCell
;
2859 PVALUE_CELL NewValueCell
;
2860 BLOCK_OFFSET NewValueListCellOffset
;
2861 BLOCK_OFFSET ValueListCellOffset
;
2862 BLOCK_OFFSET NewValueCellOffset
;
2866 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG
)KeyCell
->ValueListOffset
);
2868 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2869 if (ValueListCell
== NULL
)
2871 CellSize
= sizeof(VALUE_LIST_CELL
) +
2872 (3 * sizeof(BLOCK_OFFSET
));
2873 Status
= CmiAllocateCell (RegistryHive
,
2875 (PVOID
) &ValueListCell
,
2876 &ValueListCellOffset
);
2877 if (!NT_SUCCESS(Status
))
2882 KeyCell
->ValueListOffset
= ValueListCellOffset
;
2883 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2884 CmiMarkBlockDirty(RegistryHive
, ValueListCellOffset
);
2886 else if (KeyCell
->NumberOfValues
>=
2887 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
)))
2889 CellSize
= sizeof(VALUE_LIST_CELL
) +
2890 ((KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) * sizeof(BLOCK_OFFSET
));
2891 Status
= CmiAllocateCell (RegistryHive
,
2893 (PVOID
) &NewValueListCell
,
2894 &NewValueListCellOffset
);
2895 if (!NT_SUCCESS(Status
))
2900 RtlCopyMemory(&NewValueListCell
->ValueOffset
[0],
2901 &ValueListCell
->ValueOffset
[0],
2902 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2903 CmiDestroyCell (RegistryHive
, ValueListCell
, KeyCell
->ValueListOffset
);
2904 CmiMarkBlockDirty (RegistryHive
, KeyCell
->ValueListOffset
);
2906 KeyCell
->ValueListOffset
= NewValueListCellOffset
;
2907 ValueListCell
= NewValueListCell
;
2908 CmiMarkBlockDirty (RegistryHive
, KeyCellOffset
);
2909 CmiMarkBlockDirty (RegistryHive
, NewValueListCellOffset
);
2912 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2913 KeyCell
->NumberOfValues
,
2914 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2915 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
),
2916 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
));
2918 Status
= CmiAllocateValueCell(RegistryHive
,
2920 &NewValueCellOffset
,
2922 if (!NT_SUCCESS(Status
))
2927 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = NewValueCellOffset
;
2928 KeyCell
->NumberOfValues
++;
2930 CmiMarkBlockDirty(RegistryHive
, KeyCellOffset
);
2931 CmiMarkBlockDirty(RegistryHive
, KeyCell
->ValueListOffset
);
2932 CmiMarkBlockDirty(RegistryHive
, NewValueCellOffset
);
2934 *pValueCell
= NewValueCell
;
2935 *pValueCellOffset
= NewValueCellOffset
;
2937 return STATUS_SUCCESS
;
2942 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2943 IN PKEY_CELL KeyCell
,
2944 IN BLOCK_OFFSET KeyCellOffset
,
2945 IN PUNICODE_STRING ValueName
)
2947 PVALUE_LIST_CELL ValueListCell
;
2948 PVALUE_CELL CurValueCell
;
2951 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2953 if (ValueListCell
== NULL
)
2955 DPRINT("CmiGetBlock() failed\n");
2956 return STATUS_SUCCESS
;
2959 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2961 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2963 CurValueCell
= CmiGetCell (RegistryHive
, ValueListCell
->ValueOffset
[i
], NULL
);
2964 if (CurValueCell
== NULL
)
2966 DPRINT("CmiGetBlock() failed\n");
2967 return STATUS_UNSUCCESSFUL
;
2970 if ((CurValueCell
!= NULL
) &&
2971 CmiComparePackedNames(ValueName
,
2973 CurValueCell
->NameSize
,
2974 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2976 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->ValueOffset
[i
]);
2978 if ((KeyCell
->NumberOfValues
- 1) < i
)
2980 RtlCopyMemory(&ValueListCell
->ValueOffset
[i
],
2981 &ValueListCell
->ValueOffset
[i
+ 1],
2982 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2986 RtlZeroMemory(&ValueListCell
->ValueOffset
[i
], sizeof(BLOCK_OFFSET
));
2989 KeyCell
->NumberOfValues
-= 1;
2994 if (KeyCell
->NumberOfValues
== 0)
2996 CmiDestroyCell (RegistryHive
,
2998 KeyCell
->ValueListOffset
);
3002 CmiMarkBlockDirty(RegistryHive
,
3003 KeyCell
->ValueListOffset
);
3006 CmiMarkBlockDirty(RegistryHive
,
3009 return STATUS_SUCCESS
;
3014 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive
,
3015 OUT PHASH_TABLE_CELL
*HashBlock
,
3016 OUT BLOCK_OFFSET
*HBOffset
,
3017 IN ULONG SubKeyCount
)
3019 PHASH_TABLE_CELL NewHashBlock
;
3023 Status
= STATUS_SUCCESS
;
3025 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
3026 (SubKeyCount
* sizeof(HASH_RECORD
));
3027 Status
= CmiAllocateCell (RegistryHive
,
3029 (PVOID
*) &NewHashBlock
,
3032 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
3034 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3038 assert(SubKeyCount
<= 0xffff); /* should really be USHORT_MAX or similar */
3039 NewHashBlock
->Id
= REG_HASH_TABLE_CELL_ID
;
3040 NewHashBlock
->HashTableSize
= (USHORT
)SubKeyCount
;
3041 *HashBlock
= NewHashBlock
;
3049 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
3050 PHASH_TABLE_CELL HashBlock
,
3053 BLOCK_OFFSET KeyOffset
;
3056 if (HashBlock
== NULL
)
3059 if (IsPointerHive(RegistryHive
))
3061 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
3065 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
3066 KeyCell
= CmiGetCell (RegistryHive
, KeyOffset
, NULL
);
3074 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
3075 PHASH_TABLE_CELL HashCell
,
3076 BLOCK_OFFSET HashCellOffset
,
3077 PKEY_CELL NewKeyCell
,
3078 BLOCK_OFFSET NKBOffset
)
3082 for (i
= 0; i
< HashCell
->HashTableSize
; i
++)
3084 if (HashCell
->Table
[i
].KeyOffset
== 0)
3086 HashCell
->Table
[i
].KeyOffset
= NKBOffset
;
3087 HashCell
->Table
[i
].HashValue
= 0;
3088 if (NewKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3090 RtlCopyMemory(&HashCell
->Table
[i
].HashValue
,
3092 min(NewKeyCell
->NameSize
, sizeof(ULONG
)));
3094 CmiMarkBlockDirty(RegistryHive
, HashCellOffset
);
3095 return STATUS_SUCCESS
;
3099 return STATUS_UNSUCCESSFUL
;
3104 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
3105 PHASH_TABLE_CELL HashBlock
,
3106 BLOCK_OFFSET NKBOffset
)
3110 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3112 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
3114 HashBlock
->Table
[i
].KeyOffset
= 0;
3115 HashBlock
->Table
[i
].HashValue
= 0;
3116 return STATUS_SUCCESS
;
3120 return STATUS_UNSUCCESSFUL
;
3125 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
3126 PVALUE_CELL
*ValueCell
,
3127 BLOCK_OFFSET
*VBOffset
,
3128 IN PUNICODE_STRING ValueName
)
3130 PVALUE_CELL NewValueCell
;
3136 Status
= STATUS_SUCCESS
;
3138 NameSize
= CmiGetPackedNameLength(ValueName
,
3141 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
3143 Status
= CmiAllocateCell (RegistryHive
,
3144 sizeof(VALUE_CELL
) + NameSize
,
3145 (PVOID
*) &NewValueCell
,
3147 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
3149 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3153 assert(NameSize
<= 0xffff); /* should really be USHORT_MAX or similar */
3154 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
3155 NewValueCell
->NameSize
= (USHORT
)NameSize
;
3158 /* Pack the value name */
3159 for (i
= 0; i
< NameSize
; i
++)
3160 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
3161 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
3165 /* Copy the value name */
3166 RtlCopyMemory(NewValueCell
->Name
,
3169 NewValueCell
->Flags
= 0;
3171 NewValueCell
->DataType
= 0;
3172 NewValueCell
->DataSize
= 0;
3173 NewValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
3174 *ValueCell
= NewValueCell
;
3182 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
3183 PVALUE_CELL ValueCell
,
3184 BLOCK_OFFSET VBOffset
)
3190 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell
, VBOffset
);
3192 VERIFY_VALUE_CELL(ValueCell
);
3194 /* Destroy the data cell */
3195 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
3197 pBlock
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, &pBin
);
3200 DPRINT("CmiGetBlock() failed\n");
3201 return STATUS_UNSUCCESSFUL
;
3204 Status
= CmiDestroyCell (RegistryHive
, pBlock
, ValueCell
->DataOffset
);
3205 if (!NT_SUCCESS(Status
))
3210 /* Update time of heap */
3211 if (!IsNoFileHive(RegistryHive
))
3212 NtQuerySystemTime(&pBin
->DateModified
);
3215 /* Destroy the value cell */
3216 Status
= CmiDestroyCell (RegistryHive
, ValueCell
, VBOffset
);
3218 /* Update time of heap */
3219 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, VBOffset
, &pBin
))
3221 NtQuerySystemTime(&pBin
->DateModified
);
3229 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
3231 BLOCK_OFFSET
*NewBlockOffset
)
3233 PCELL_HEADER tmpBlock
;
3234 PHBIN
* tmpBlockList
;
3237 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
3240 return STATUS_INSUFFICIENT_RESOURCES
;
3243 tmpBin
->BlockId
= REG_BIN_ID
;
3244 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
3245 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
3246 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
3247 tmpBin
->Unused1
= 0;
3248 ZwQuerySystemTime(&tmpBin
->DateModified
);
3249 tmpBin
->Unused2
= 0;
3251 /* Increase size of list of blocks */
3252 tmpBlockList
= ExAllocatePool(NonPagedPool
,
3253 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
3254 if (tmpBlockList
== NULL
)
3257 return STATUS_INSUFFICIENT_RESOURCES
;
3260 if (RegistryHive
->BlockListSize
> 0)
3262 RtlCopyMemory (tmpBlockList
,
3263 RegistryHive
->BlockList
,
3264 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
3265 ExFreePool(RegistryHive
->BlockList
);
3268 RegistryHive
->BlockList
= tmpBlockList
;
3269 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
] = tmpBin
;
3270 RegistryHive
->BlockListSize
++;
3272 /* Initialize a free block in this heap : */
3273 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
3274 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
3276 /* Grow bitmap if necessary */
3277 if (IsNoFileHive(RegistryHive
) &&
3278 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
3280 PULONG BitmapBuffer
;
3283 DPRINT("Grow hive bitmap\n");
3285 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3286 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
3287 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
3288 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
3289 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
3291 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
3292 RtlCopyMemory(BitmapBuffer
,
3293 RegistryHive
->DirtyBitMap
.Buffer
,
3294 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
3295 ExFreePool(RegistryHive
->BitmapBuffer
);
3296 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
3297 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
3298 RegistryHive
->BitmapBuffer
,
3302 *NewBlock
= (PVOID
) tmpBlock
;
3305 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
3307 /* Mark new bin dirty */
3308 CmiMarkBinDirty(RegistryHive
,
3309 tmpBin
->BlockOffset
);
3311 return STATUS_SUCCESS
;
3316 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
3319 BLOCK_OFFSET
*CellOffset
)
3321 PCELL_HEADER NewCell
;
3327 Status
= STATUS_SUCCESS
;
3329 /* Round to 16 bytes multiple */
3330 CellSize
= ROUND_UP(CellSize
, 16);
3332 /* Handle volatile hives first */
3333 if (IsPointerHive(RegistryHive
))
3335 NewCell
= ExAllocatePool(NonPagedPool
, CellSize
);
3337 if (NewCell
== NULL
)
3339 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3343 RtlZeroMemory(NewCell
, CellSize
);
3344 NewCell
->CellSize
= -CellSize
;
3347 if (CellOffset
!= NULL
)
3348 *CellOffset
= (BLOCK_OFFSET
) NewCell
;
3353 /* first search in free blocks */
3355 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3357 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
3359 NewCell
= RegistryHive
->FreeList
[i
];
3360 if (CellOffset
!= NULL
)
3361 *CellOffset
= RegistryHive
->FreeListOffset
[i
];
3363 /* Update time of heap */
3364 Temp
= CmiGetCell (RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
3367 DPRINT("CmiGetBlock() failed\n");
3368 return STATUS_UNSUCCESSFUL
;
3373 NtQuerySystemTime(&pBin
->DateModified
);
3374 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
3377 if ((i
+ 1) < RegistryHive
->FreeListSize
)
3379 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
3380 &RegistryHive
->FreeList
[i
+ 1],
3381 sizeof(RegistryHive
->FreeList
[0])
3382 * (RegistryHive
->FreeListSize
- i
- 1));
3383 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
3384 &RegistryHive
->FreeListOffset
[i
+ 1],
3385 sizeof(RegistryHive
->FreeListOffset
[0])
3386 * (RegistryHive
->FreeListSize
- i
- 1));
3388 RegistryHive
->FreeListSize
--;
3393 /* Need to extend hive file : */
3394 if (NewCell
== NULL
)
3397 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewCell
, CellOffset
);
3400 if (NT_SUCCESS(Status
))
3404 /* Split the block in two parts */
3405 if (NewCell
->CellSize
> CellSize
)
3407 NewCell
= (PCELL_HEADER
) ((ULONG_PTR
) NewCell
+ CellSize
);
3408 NewCell
->CellSize
= ((PCELL_HEADER
) (*Cell
))->CellSize
- CellSize
;
3409 CmiAddFree(RegistryHive
,
3411 *CellOffset
+ CellSize
,
3413 CmiMarkBlockDirty(RegistryHive
,
3414 *CellOffset
+ CellSize
);
3416 else if (NewCell
->CellSize
< CellSize
)
3418 return(STATUS_UNSUCCESSFUL
);
3421 RtlZeroMemory(*Cell
, CellSize
);
3422 ((PCELL_HEADER
) (*Cell
))->CellSize
= -CellSize
;
3431 CmiDestroyCell (PREGISTRY_HIVE RegistryHive
,
3433 BLOCK_OFFSET CellOffset
)
3438 Status
= STATUS_SUCCESS
;
3440 if (IsPointerHive(RegistryHive
))
3446 PCELL_HEADER pFree
= Cell
;
3448 if (pFree
->CellSize
< 0)
3449 pFree
->CellSize
= -pFree
->CellSize
;
3451 /* Clear block (except the block size) */
3452 RtlZeroMemory(((char*)pFree
) + sizeof(ULONG
),
3453 pFree
->CellSize
- sizeof(ULONG
));
3455 /* Add block to the list of free blocks */
3456 CmiAddFree(RegistryHive
, Cell
, CellOffset
, TRUE
);
3458 /* Update time of heap */
3459 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, CellOffset
,&pBin
))
3460 NtQuerySystemTime(&pBin
->DateModified
);
3462 CmiMarkBlockDirty(RegistryHive
, CellOffset
);
3470 CmiGetCell (PREGISTRY_HIVE RegistryHive
,
3471 BLOCK_OFFSET CellOffset
,
3481 if (CellOffset
== (BLOCK_OFFSET
)-1)
3486 if (IsPointerHive (RegistryHive
))
3488 return (PVOID
)CellOffset
;
3491 if (CellOffset
> RegistryHive
->BlockListSize
* 4096)
3493 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3494 CellOffset
, RegistryHive
->BlockListSize
* 4096);
3498 pBin
= RegistryHive
->BlockList
[CellOffset
/ 4096];
3509 return((PVOID
)((ULONG_PTR
)pBin
+ (CellOffset
- pBin
->BlockOffset
)));
3514 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3515 PCELL_HEADER FreeBlock
,
3516 BLOCK_OFFSET FreeOffset
)
3518 BLOCK_OFFSET BlockOffset
;
3519 BLOCK_OFFSET BinOffset
;
3525 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3526 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3528 CmiGetCell (RegistryHive
,
3531 DPRINT("Bin %p\n", Bin
);
3535 BinOffset
= Bin
->BlockOffset
;
3536 BinSize
= Bin
->BlockSize
;
3537 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3539 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3541 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3542 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3543 if (BlockOffset
> BinOffset
&&
3544 BlockOffset
< BinOffset
+ BinSize
)
3546 DPRINT("Free block: Offset %lx Size %lx\n",
3547 BlockOffset
, BlockSize
);
3549 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3550 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3551 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3553 DPRINT("Merge current block with previous and next block\n");
3555 RegistryHive
->FreeList
[i
]->CellSize
+=
3556 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3558 FreeBlock
->CellSize
= 0;
3559 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3562 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3564 RtlMoveMemory(&RegistryHive
->FreeList
[i
+ 1],
3565 &RegistryHive
->FreeList
[i
+ 2],
3566 sizeof(RegistryHive
->FreeList
[0])
3567 * (RegistryHive
->FreeListSize
- i
- 2));
3568 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3569 &RegistryHive
->FreeListOffset
[i
+ 2],
3570 sizeof(RegistryHive
->FreeListOffset
[0])
3571 * (RegistryHive
->FreeListSize
- i
- 2));
3573 RegistryHive
->FreeListSize
--;
3575 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3579 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3581 DPRINT("Merge current block with previous block\n");
3583 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3584 FreeBlock
->CellSize
= 0;
3586 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3590 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3592 DPRINT("Merge current block with next block\n");
3594 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3595 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3596 RegistryHive
->FreeList
[i
] = FreeBlock
;
3597 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3599 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3611 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3612 PCELL_HEADER FreeBlock
,
3613 BLOCK_OFFSET FreeOffset
,
3614 BOOLEAN MergeFreeBlocks
)
3616 PCELL_HEADER
*tmpList
;
3617 BLOCK_OFFSET
*tmpListOffset
;
3622 assert(RegistryHive
);
3625 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3626 FreeBlock
, FreeOffset
);
3628 /* Merge free blocks */
3629 if (MergeFreeBlocks
== TRUE
)
3631 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3632 return(STATUS_SUCCESS
);
3635 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3637 tmpList
= ExAllocatePool(PagedPool
,
3638 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3639 if (tmpList
== NULL
)
3640 return STATUS_INSUFFICIENT_RESOURCES
;
3642 tmpListOffset
= ExAllocatePool(PagedPool
,
3643 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3645 if (tmpListOffset
== NULL
)
3647 ExFreePool(tmpList
);
3648 return STATUS_INSUFFICIENT_RESOURCES
;
3651 if (RegistryHive
->FreeListMax
)
3653 RtlMoveMemory(tmpList
,
3654 RegistryHive
->FreeList
,
3655 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3656 RtlMoveMemory(tmpListOffset
,
3657 RegistryHive
->FreeListOffset
,
3658 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3659 ExFreePool(RegistryHive
->FreeList
);
3660 ExFreePool(RegistryHive
->FreeListOffset
);
3662 RegistryHive
->FreeList
= tmpList
;
3663 RegistryHive
->FreeListOffset
= tmpListOffset
;
3664 RegistryHive
->FreeListMax
+= 32;
3667 /* Add new offset to free list, maintaining list in ascending order */
3668 if ((RegistryHive
->FreeListSize
== 0)
3669 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3671 /* Add to end of list */
3672 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3673 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3675 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3677 /* Add to begin of list */
3678 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3679 &RegistryHive
->FreeList
[0],
3680 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3681 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3682 &RegistryHive
->FreeListOffset
[0],
3683 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3684 RegistryHive
->FreeList
[0] = FreeBlock
;
3685 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3686 RegistryHive
->FreeListSize
++;
3690 /* Search where to insert */
3692 maxInd
= RegistryHive
->FreeListSize
- 1;
3693 while ((maxInd
- minInd
) > 1)
3695 medInd
= (minInd
+ maxInd
) / 2;
3696 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3702 /* Insert before maxInd */
3703 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3704 &RegistryHive
->FreeList
[maxInd
],
3705 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3706 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3707 &RegistryHive
->FreeListOffset
[maxInd
],
3708 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3709 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3710 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3711 RegistryHive
->FreeListSize
++;
3714 return STATUS_SUCCESS
;
3719 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3720 BLOCK_OFFSET BlockOffset
)
3727 if (IsNoFileHive(RegistryHive
))
3730 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3732 BlockNumber
= (ULONG
)BlockOffset
/ 4096;
3734 Cell
= CmiGetCell (RegistryHive
,
3738 CellSize
= Cell
->CellSize
;
3740 CellSize
= -CellSize
;
3742 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, 4096) - ROUND_DOWN(BlockOffset
, 4096)) / 4096;
3744 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3747 (Cell
->CellSize
< 0) ? "used" : "free",
3750 RegistryHive
->HiveDirty
= TRUE
;
3751 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3758 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3759 BLOCK_OFFSET BinOffset
)
3765 if (IsNoFileHive(RegistryHive
))
3768 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3770 BlockNumber
= (ULONG
)BinOffset
/ 4096;
3772 Bin
= RegistryHive
->BlockList
[BlockNumber
];
3774 BlockCount
= Bin
->BlockSize
/ 4096;
3776 DPRINT(" BlockNumber %lu Size %lu BlockCount %lu\n",
3781 RegistryHive
->HiveDirty
= TRUE
;
3782 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3789 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3790 OUT PBOOLEAN Packable
)
3794 if (Packable
!= NULL
)
3797 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3799 if (Name
->Buffer
[i
] & 0xFF00)
3801 if (Packable
!= NULL
)
3803 return Name
->Length
;
3807 return (Name
->Length
/ sizeof(WCHAR
));
3812 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3813 IN PCHAR NameBuffer
,
3814 IN USHORT NameBufferSize
,
3815 IN BOOLEAN NamePacked
)
3820 if (NamePacked
== TRUE
)
3822 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3825 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3827 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3833 if (Name
->Length
!= NameBufferSize
)
3836 UNameBuffer
= (PWCHAR
)NameBuffer
;
3838 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3840 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3850 CmiCopyPackedName(PWCHAR NameBuffer
,
3851 PCHAR PackedNameBuffer
,
3852 ULONG PackedNameSize
)
3856 for (i
= 0; i
< PackedNameSize
; i
++)
3857 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];
3862 CmiCompareHash(PUNICODE_STRING KeyName
,
3867 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3868 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3869 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3870 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3872 return (strncmp(Buffer
, HashString
, 4) == 0);
3877 CmiCompareHashI(PUNICODE_STRING KeyName
,
3882 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3883 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3884 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3885 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3887 return (_strnicmp(Buffer
, HashString
, 4) == 0);
3892 CmiCompareKeyNames(PUNICODE_STRING KeyName
,
3898 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3900 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3902 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3905 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3907 if (KeyName
->Buffer
[i
] != (WCHAR
)KeyCell
->Name
[i
])
3913 if (KeyName
->Length
!= KeyCell
->NameSize
)
3916 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3917 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3919 if (KeyName
->Buffer
[i
] != UnicodeName
[i
])
3929 CmiCompareKeyNamesI(PUNICODE_STRING KeyName
,
3935 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3937 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3939 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3942 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3944 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3945 RtlUpcaseUnicodeChar((WCHAR
)KeyCell
->Name
[i
]))
3951 if (KeyName
->Length
!= KeyCell
->NameSize
)
3954 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3955 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3957 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3958 RtlUpcaseUnicodeChar(UnicodeName
[i
]))
3968 CmiCopyKey (PREGISTRY_HIVE DstHive
,
3969 PKEY_CELL DstKeyCell
,
3970 PREGISTRY_HIVE SrcHive
,
3971 PKEY_CELL SrcKeyCell
)
3973 PKEY_CELL NewKeyCell
;
3974 ULONG NewKeyCellSize
;
3975 BLOCK_OFFSET NewKeyCellOffset
;
3976 PHASH_TABLE_CELL NewHashTableCell
;
3977 ULONG NewHashTableSize
;
3978 BLOCK_OFFSET NewHashTableOffset
;
3982 DPRINT ("CmiCopyKey() called\n");
3984 if (DstKeyCell
== NULL
)
3986 /* Allocate and copy key cell */
3987 NewKeyCellSize
= sizeof(KEY_CELL
) + SrcKeyCell
->NameSize
;
3988 Status
= CmiAllocateCell (DstHive
,
3990 (PVOID
) &NewKeyCell
,
3992 if (!NT_SUCCESS(Status
))
3994 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
3997 if (NewKeyCell
== NULL
)
3999 DPRINT1 ("Failed to allocate a key cell\n");
4000 return STATUS_INSUFFICIENT_RESOURCES
;
4003 RtlCopyMemory (NewKeyCell
,
4007 DstHive
->HiveHeader
->RootKeyOffset
= NewKeyCellOffset
;
4009 /* Copy class name */
4010 if (SrcKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4012 PDATA_CELL SrcClassNameCell
;
4013 PDATA_CELL NewClassNameCell
;
4014 BLOCK_OFFSET NewClassNameOffset
;
4016 SrcClassNameCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ClassNameOffset
, NULL
),
4018 NewKeyCell
->ClassSize
= SrcKeyCell
->ClassSize
;
4019 Status
= CmiAllocateCell (DstHive
,
4020 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
4021 (PVOID
)&NewClassNameCell
,
4022 &NewClassNameOffset
);
4023 if (!NT_SUCCESS(Status
))
4025 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4029 RtlCopyMemory (NewClassNameCell
,
4031 NewKeyCell
->ClassSize
);
4032 NewKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4037 NewKeyCell
= DstKeyCell
;
4040 /* Allocate hash table */
4041 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4043 NewHashTableSize
= ROUND_UP(SrcKeyCell
->NumberOfSubKeys
+ 1, 4) - 1;
4044 Status
= CmiAllocateHashTableCell (DstHive
,
4046 &NewHashTableOffset
,
4048 if (!NT_SUCCESS(Status
))
4050 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status
);
4053 NewKeyCell
->HashTableOffset
= NewHashTableOffset
;
4056 /* Allocate and copy value list and values */
4057 if (SrcKeyCell
->NumberOfValues
!= 0)
4059 PVALUE_LIST_CELL NewValueListCell
;
4060 PVALUE_LIST_CELL SrcValueListCell
;
4061 PVALUE_CELL NewValueCell
;
4062 PVALUE_CELL SrcValueCell
;
4063 PDATA_CELL SrcValueDataCell
;
4064 PDATA_CELL NewValueDataCell
;
4065 BLOCK_OFFSET ValueCellOffset
;
4066 BLOCK_OFFSET ValueDataCellOffset
;
4067 ULONG NewValueListCellSize
;
4068 ULONG NewValueCellSize
;
4071 NewValueListCellSize
=
4072 ROUND_UP(SrcKeyCell
->NumberOfValues
, 4) * sizeof(BLOCK_OFFSET
);
4073 Status
= CmiAllocateCell (DstHive
,
4074 NewValueListCellSize
,
4075 (PVOID
)&NewValueListCell
,
4076 &NewKeyCell
->ValueListOffset
);
4077 if (!NT_SUCCESS(Status
))
4079 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4083 RtlZeroMemory (NewValueListCell
,
4084 NewValueListCellSize
);
4087 SrcValueListCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ValueListOffset
, NULL
);
4088 for (i
= 0; i
< SrcKeyCell
->NumberOfValues
; i
++)
4090 /* Copy value cell */
4091 SrcValueCell
= CmiGetCell (SrcHive
, SrcValueListCell
->ValueOffset
[i
], NULL
);
4093 NewValueCellSize
= sizeof(VALUE_CELL
) + SrcValueCell
->NameSize
;
4094 Status
= CmiAllocateCell (DstHive
,
4096 (PVOID
*) &NewValueCell
,
4098 if (!NT_SUCCESS(Status
))
4100 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4104 NewValueListCell
->ValueOffset
[i
] = ValueCellOffset
;
4105 RtlCopyMemory (NewValueCell
,
4109 /* Copy value data cell */
4110 if (SrcValueCell
->DataSize
> (LONG
) sizeof(PVOID
))
4112 SrcValueDataCell
= CmiGetCell (SrcHive
, SrcValueCell
->DataOffset
, NULL
);
4114 Status
= CmiAllocateCell (DstHive
,
4115 sizeof(CELL_HEADER
) + SrcValueCell
->DataSize
,
4116 (PVOID
*) &NewValueDataCell
,
4117 &ValueDataCellOffset
);
4118 if (!NT_SUCCESS(Status
))
4120 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4123 RtlCopyMemory (NewValueDataCell
,
4125 SrcValueCell
->DataSize
);
4126 NewValueCell
->DataOffset
= ValueDataCellOffset
;
4132 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4134 PHASH_TABLE_CELL SrcHashTableCell
;
4135 PKEY_CELL SrcSubKeyCell
;
4136 PKEY_CELL NewSubKeyCell
;
4137 ULONG NewSubKeyCellSize
;
4138 BLOCK_OFFSET NewSubKeyCellOffset
;
4139 PHASH_RECORD SrcHashRecord
;
4141 SrcHashTableCell
= CmiGetCell (SrcHive
,
4142 SrcKeyCell
->HashTableOffset
,
4145 for (i
= 0; i
< SrcKeyCell
->NumberOfSubKeys
; i
++)
4147 SrcHashRecord
= &SrcHashTableCell
->Table
[i
];
4148 SrcSubKeyCell
= CmiGetCell (SrcHive
, SrcHashRecord
->KeyOffset
, NULL
);
4150 /* Allocate and copy key cell */
4151 NewSubKeyCellSize
= sizeof(KEY_CELL
) + SrcSubKeyCell
->NameSize
;
4152 Status
= CmiAllocateCell (DstHive
,
4154 (PVOID
)&NewSubKeyCell
,
4155 &NewSubKeyCellOffset
);
4156 if (!NT_SUCCESS(Status
))
4158 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4161 if (NewKeyCell
== NULL
)
4163 DPRINT1 ("Failed to allocate a sub key cell\n");
4164 return STATUS_INSUFFICIENT_RESOURCES
;
4167 NewHashTableCell
->Table
[i
].KeyOffset
= NewSubKeyCellOffset
;
4168 NewHashTableCell
->Table
[i
].HashValue
= SrcHashRecord
->HashValue
;
4170 RtlCopyMemory (NewSubKeyCell
,
4174 /* Copy class name */
4175 if (SrcSubKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4177 PDATA_CELL SrcClassNameCell
;
4178 PDATA_CELL NewClassNameCell
;
4179 BLOCK_OFFSET NewClassNameOffset
;
4181 SrcClassNameCell
= CmiGetCell (SrcHive
,
4182 SrcSubKeyCell
->ClassNameOffset
,
4185 NewSubKeyCell
->ClassSize
= SrcSubKeyCell
->ClassSize
;
4186 Status
= CmiAllocateCell (DstHive
,
4187 sizeof(CELL_HEADER
) + NewSubKeyCell
->ClassSize
,
4188 (PVOID
)&NewClassNameCell
,
4189 &NewClassNameOffset
);
4190 if (!NT_SUCCESS(Status
))
4192 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4196 NewSubKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4197 RtlCopyMemory (NewClassNameCell
,
4199 NewSubKeyCell
->ClassSize
);
4202 /* Copy subkey data and subkeys */
4203 Status
= CmiCopyKey (DstHive
,
4207 if (!NT_SUCCESS(Status
))
4209 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4215 return STATUS_SUCCESS
;
4220 CmiSaveTempHive (PREGISTRY_HIVE Hive
,
4223 IO_STATUS_BLOCK IoStatusBlock
;
4224 LARGE_INTEGER FileOffset
;
4229 DPRINT ("CmiSaveTempHive() called\n");
4231 Hive
->HiveHeader
->Checksum
= CmiCalcChecksum ((PULONG
)Hive
->HiveHeader
);
4233 /* Write hive block */
4234 #if defined(__GNUC__)
4235 FileOffset
.QuadPart
= 0ULL;
4237 FileOffset
.QuadPart
= 0;
4239 Status
= NtWriteFile (FileHandle
,
4245 sizeof(HIVE_HEADER
),
4248 if (!NT_SUCCESS(Status
))
4250 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4254 DPRINT ("Saving %lu blocks\n", Hive
->BlockListSize
);
4255 for (BlockIndex
= 0; BlockIndex
< Hive
->BlockListSize
; BlockIndex
++)
4257 BlockPtr
= Hive
->BlockList
[BlockIndex
];
4258 DPRINT ("BlockPtr %p\n", BlockPtr
);
4260 #if defined(__GNUC__)
4261 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096ULL;
4263 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096;
4265 DPRINT ("File offset %I64x\n", FileOffset
.QuadPart
);
4267 /* Write hive block */
4268 Status
= NtWriteFile (FileHandle
,
4277 if (!NT_SUCCESS(Status
))
4279 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4284 Status
= NtFlushBuffersFile (FileHandle
,
4286 if (!NT_SUCCESS(Status
))
4288 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
4291 DPRINT ("CmiSaveTempHive() done\n");