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 CmiGetMaxNameLength(PKEY_OBJECT KeyObject
)
2032 PHASH_TABLE_CELL HashBlock
;
2034 PKEY_CELL CurSubKeyCell
;
2040 VERIFY_KEY_OBJECT(KeyObject
);
2042 KeyCell
= KeyObject
->KeyCell
;
2043 VERIFY_KEY_CELL(KeyCell
);
2046 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2047 KeyCell
->HashTableOffset
,
2049 if (HashBlock
== NULL
)
2051 DPRINT("CmiGetBlock() failed\n");
2055 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2057 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2059 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2060 HashBlock
->Table
[i
].KeyOffset
,
2062 if (CurSubKeyCell
== NULL
)
2064 DPRINT("CmiGetBlock() failed\n");
2067 NameSize
= CurSubKeyCell
->NameSize
;
2068 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2070 NameSize
*= sizeof(WCHAR
);
2072 if (MaxName
< NameSize
)
2079 if (KeyObject
->RegistryHive
!= CmiVolatileHive
)
2081 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2082 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2084 CurKey
= KeyObject
->SubKeys
[i
];
2085 if (CurKey
->RegistryHive
== CmiVolatileHive
)
2087 CurSubKeyCell
= CurKey
->KeyCell
;
2088 if (CurSubKeyCell
== NULL
)
2090 DPRINT("CmiGetBlock() failed\n");
2093 NameSize
= CurSubKeyCell
->NameSize
;
2094 if (CurSubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
2096 NameSize
*= sizeof(WCHAR
);
2098 if (MaxName
< NameSize
)
2111 CmiGetMaxClassLength(PKEY_OBJECT KeyObject
)
2113 PHASH_TABLE_CELL HashBlock
;
2115 PKEY_CELL CurSubKeyCell
;
2120 VERIFY_KEY_OBJECT(KeyObject
);
2122 KeyCell
= KeyObject
->KeyCell
;
2123 VERIFY_KEY_CELL(KeyCell
);
2126 HashBlock
= CmiGetCell (KeyObject
->RegistryHive
,
2127 KeyCell
->HashTableOffset
,
2129 if (HashBlock
== NULL
)
2131 DPRINT("CmiGetBlock() failed\n");
2135 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2137 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
2139 CurSubKeyCell
= CmiGetCell (KeyObject
->RegistryHive
,
2140 HashBlock
->Table
[i
].KeyOffset
,
2142 if (CurSubKeyCell
== NULL
)
2144 DPRINT("CmiGetBlock() failed\n");
2148 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2150 MaxClass
= CurSubKeyCell
->ClassSize
;
2155 if (KeyObject
->RegistryHive
!= CmiVolatileHive
)
2157 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject
->NumberOfSubKeys
);
2158 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
2160 CurKey
= KeyObject
->SubKeys
[i
];
2161 if (CurKey
->RegistryHive
== CmiVolatileHive
)
2163 CurSubKeyCell
= CurKey
->KeyCell
;
2164 if (CurSubKeyCell
== NULL
)
2166 DPRINT("CmiGetBlock() failed\n");
2169 if (MaxClass
< CurSubKeyCell
->ClassSize
)
2171 MaxClass
= CurSubKeyCell
->ClassSize
;
2182 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
2185 PVALUE_LIST_CELL ValueListCell
;
2186 PVALUE_CELL CurValueCell
;
2191 VERIFY_KEY_CELL(KeyCell
);
2194 ValueListCell
= CmiGetCell (RegistryHive
,
2195 KeyCell
->ValueListOffset
,
2197 if (ValueListCell
== NULL
)
2199 DPRINT("CmiGetBlock() failed\n");
2203 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2205 CurValueCell
= CmiGetCell (RegistryHive
,
2206 ValueListCell
->ValueOffset
[i
],
2208 if (CurValueCell
== NULL
)
2210 DPRINT("CmiGetBlock() failed\n");
2213 if (CurValueCell
!= NULL
)
2215 Size
= CurValueCell
->NameSize
;
2216 if (CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
2218 Size
*= sizeof(WCHAR
);
2220 if (MaxValueName
< Size
)
2222 MaxValueName
= Size
;
2227 return MaxValueName
;
2232 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
2235 PVALUE_LIST_CELL ValueListCell
;
2236 PVALUE_CELL CurValueCell
;
2240 VERIFY_KEY_CELL(KeyCell
);
2243 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2244 if (ValueListCell
== NULL
)
2249 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2251 CurValueCell
= CmiGetCell (RegistryHive
,
2252 ValueListCell
->ValueOffset
[i
],NULL
);
2253 if ((CurValueCell
!= NULL
) &&
2254 (MaxValueData
< (LONG
)(CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2256 MaxValueData
= CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2260 return MaxValueData
;
2265 CmiScanForSubKey(IN PREGISTRY_HIVE ParentKeyRegistryHive
,
2266 IN PKEY_CELL ParentKeyCell
,
2267 OUT PREGISTRY_HIVE
*SubKeyRegistryHive
,
2268 OUT PKEY_CELL
*SubKeyCell
,
2269 OUT BLOCK_OFFSET
*SubKeyCellOffset
,
2270 IN PUNICODE_STRING KeyName
,
2271 IN ACCESS_MASK DesiredAccess
,
2272 IN ULONG Attributes
)
2274 PHASH_TABLE_CELL HashCell
;
2275 PKEY_CELL CurSubKeyCell
;
2276 PHIVE_LINK HiveLink
;
2279 VERIFY_KEY_CELL(ParentKeyCell
);
2281 DPRINT("Scanning for sub key %wZ\n", KeyName
);
2283 // assert(RegistryHive);
2287 /* The key does not have any subkeys */
2288 if (ParentKeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
2290 return STATUS_SUCCESS
;
2293 /* Get hash table */
2294 HashCell
= CmiGetCell (ParentKeyRegistryHive
, ParentKeyCell
->HashTableOffset
, NULL
);
2295 if (HashCell
== NULL
)
2297 DPRINT("CmiGetBlock() failed\n");
2298 return STATUS_UNSUCCESSFUL
;
2301 for (i
= 0; (i
< ParentKeyCell
->NumberOfSubKeys
) && (i
< HashCell
->HashTableSize
); i
++)
2303 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2305 if (HashCell
->Table
[i
].KeyOffset
!= 0 &&
2306 HashCell
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1 &&
2307 (HashCell
->Table
[i
].HashValue
== 0 ||
2308 CmiCompareHashI(KeyName
, (PCHAR
)&HashCell
->Table
[i
].HashValue
)))
2310 if (HashCell
->Table
[i
].KeyOffset
& 1)
2312 HiveLink
= (PHIVE_LINK
)(HashCell
->Table
[i
].KeyOffset
& ~1);
2314 CurSubKeyCell
= CmiGetCell (HiveLink
->SubKeyRegistryHive
,
2315 HiveLink
->SubKeyCellOffset
,
2317 if (CurSubKeyCell
== NULL
)
2319 DPRINT("CmiGetBlock() failed\n");
2320 return STATUS_UNSUCCESSFUL
;
2323 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2325 *SubKeyRegistryHive
= HiveLink
->SubKeyRegistryHive
;
2326 *SubKeyCell
= CurSubKeyCell
;
2327 *SubKeyCellOffset
= HiveLink
->SubKeyCellOffset
;
2333 CurSubKeyCell
= CmiGetCell (ParentKeyRegistryHive
,
2334 HashCell
->Table
[i
].KeyOffset
,
2336 if (CurSubKeyCell
== NULL
)
2338 DPRINT("CmiGetBlock() failed\n");
2339 return STATUS_UNSUCCESSFUL
;
2342 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2344 *SubKeyRegistryHive
= ParentKeyRegistryHive
;
2345 *SubKeyCell
= CurSubKeyCell
;
2346 *SubKeyCellOffset
= HashCell
->Table
[i
].KeyOffset
;
2354 if (HashCell
->Table
[i
].KeyOffset
!= 0 &&
2355 HashCell
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2356 (HashCell
->Table
[i
].HashValue
== 0 ||
2357 CmiCompareHash(KeyName
, (PCHAR
)&HashCell
->Table
[i
].HashValue
)))
2359 if (HashCell
->Table
[i
].KeyOffset
& 1)
2361 HiveLink
= (PHIVE_LINK
)(HashCell
->Table
[i
].KeyOffset
& ~1);
2363 CurSubKeyCell
= CmiGetCell (HiveLink
->SubKeyRegistryHive
,
2364 HiveLink
->SubKeyCellOffset
,
2366 if (CurSubKeyCell
== NULL
)
2368 DPRINT("CmiGetBlock() failed\n");
2369 return STATUS_UNSUCCESSFUL
;
2372 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2374 *SubKeyRegistryHive
= HiveLink
->SubKeyRegistryHive
;
2375 *SubKeyCell
= CurSubKeyCell
;
2376 *SubKeyCellOffset
= HiveLink
->SubKeyCellOffset
;
2382 CurSubKeyCell
= CmiGetCell (ParentKeyRegistryHive
,
2383 HashCell
->Table
[i
].KeyOffset
,
2385 if (CurSubKeyCell
== NULL
)
2387 DPRINT("CmiGetBlock() failed\n");
2388 return STATUS_UNSUCCESSFUL
;
2391 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2393 *SubKeyRegistryHive
= ParentKeyRegistryHive
;
2394 *SubKeyCell
= CurSubKeyCell
;
2395 *SubKeyCellOffset
= HashCell
->Table
[i
].KeyOffset
;
2403 return STATUS_SUCCESS
;
2408 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2409 PKEY_OBJECT ParentKey
,
2411 PUNICODE_STRING SubKeyName
,
2413 PUNICODE_STRING Class
,
2414 ULONG CreateOptions
)
2416 BLOCK_OFFSET NKBOffset
;
2417 PKEY_CELL NewKeyCell
;
2419 PKEY_CELL ParentKeyCell
;
2420 PDATA_CELL ClassCell
;
2427 ParentKeyCell
= ParentKey
->KeyCell
;
2429 VERIFY_KEY_CELL(ParentKeyCell
);
2431 /* Skip leading backslash */
2432 if (SubKeyName
->Buffer
[0] == L
'\\')
2434 NamePtr
= &SubKeyName
->Buffer
[1];
2435 NameSize
= SubKeyName
->Length
- sizeof(WCHAR
);
2439 NamePtr
= SubKeyName
->Buffer
;
2440 NameSize
= SubKeyName
->Length
;
2443 /* Check whether key name can be packed */
2445 for (i
= 0; i
< NameSize
/ sizeof(WCHAR
); i
++)
2447 if (NamePtr
[i
] & 0xFF00)
2454 /* Adjust name size */
2457 NameSize
= NameSize
/ sizeof(WCHAR
);
2460 DPRINT("Key %S Length %lu %s\n", NamePtr
, NameSize
, (Packable
)?"True":"False");
2462 Status
= STATUS_SUCCESS
;
2464 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2465 Status
= CmiAllocateCell (RegistryHive
,
2467 (PVOID
) &NewKeyCell
,
2469 if (NewKeyCell
== NULL
)
2471 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2475 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2476 NewKeyCell
->Flags
= 0;
2477 NtQuerySystemTime(&NewKeyCell
->LastWriteTime
);
2478 NewKeyCell
->ParentKeyOffset
= -1;
2479 NewKeyCell
->NumberOfSubKeys
= 0;
2480 NewKeyCell
->HashTableOffset
= -1;
2481 NewKeyCell
->NumberOfValues
= 0;
2482 NewKeyCell
->ValueListOffset
= -1;
2483 NewKeyCell
->SecurityKeyOffset
= -1;
2484 NewKeyCell
->ClassNameOffset
= -1;
2486 /* Pack the key name */
2487 NewKeyCell
->NameSize
= NameSize
;
2490 NewKeyCell
->Flags
|= REG_KEY_NAME_PACKED
;
2491 for (i
= 0; i
< NameSize
; i
++)
2493 NewKeyCell
->Name
[i
] = (CHAR
)(NamePtr
[i
] & 0x00FF);
2498 RtlCopyMemory(NewKeyCell
->Name
,
2503 VERIFY_KEY_CELL(NewKeyCell
);
2507 NewKeyCell
->ClassSize
= Class
->Length
;
2508 Status
= CmiAllocateCell (RegistryHive
,
2509 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
2511 &NewKeyCell
->ClassNameOffset
);
2512 RtlCopyMemory (ClassCell
->Data
,
2518 if (!NT_SUCCESS(Status
))
2523 SubKey
->KeyCell
= NewKeyCell
;
2524 SubKey
->KeyCellOffset
= NKBOffset
;
2526 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2527 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(ParentKey
->RegistryHive
)))
2532 Status
= CmiAddKeyToHashTable(ParentKey
->RegistryHive
,
2534 ParentKey
->KeyCellOffset
,
2538 if (!NT_SUCCESS(Status
))
2543 NtQuerySystemTime (&ParentKeyCell
->LastWriteTime
);
2544 CmiMarkBlockDirty (ParentKey
->RegistryHive
, ParentKey
->KeyCellOffset
);
2551 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2552 PKEY_OBJECT ParentKey
,
2555 PHASH_TABLE_CELL HashBlock
;
2556 PVALUE_LIST_CELL ValueList
;
2557 PVALUE_CELL ValueCell
;
2558 PDATA_CELL DataCell
;
2561 DPRINT("CmiRemoveSubKey() called\n");
2563 /* Remove all values */
2564 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2566 /* Get pointer to the value list cell */
2567 ValueList
= CmiGetCell (RegistryHive
,
2568 SubKey
->KeyCell
->ValueListOffset
,
2570 if (ValueList
== NULL
)
2572 DPRINT("CmiGetCell() failed\n");
2573 return STATUS_UNSUCCESSFUL
;
2576 if (ValueList
!= NULL
)
2578 /* Enumerate all values */
2579 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2581 /* Get pointer to value cell */
2582 ValueCell
= CmiGetCell (RegistryHive
,
2583 ValueList
->ValueOffset
[i
],
2585 if (ValueCell
!= NULL
)
2587 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
2589 DataCell
= CmiGetCell (RegistryHive
,
2590 ValueCell
->DataOffset
,
2592 if (DataCell
== NULL
)
2594 DPRINT("CmiGetCell() failed\n");
2595 return STATUS_UNSUCCESSFUL
;
2598 if (DataCell
!= NULL
)
2600 /* Destroy data cell */
2601 CmiDestroyCell (RegistryHive
,
2603 ValueCell
->DataOffset
);
2607 /* Destroy value cell */
2608 CmiDestroyCell (RegistryHive
,
2610 ValueList
->ValueOffset
[i
]);
2615 /* Destroy value list cell */
2616 CmiDestroyCell (RegistryHive
,
2618 SubKey
->KeyCell
->ValueListOffset
);
2620 SubKey
->KeyCell
->NumberOfValues
= 0;
2621 SubKey
->KeyCell
->ValueListOffset
= (BLOCK_OFFSET
)-1;
2624 /* Remove the key from the parent key's hash block */
2625 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2627 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2628 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2629 ParentKey
->KeyCell
->HashTableOffset
,
2631 if (HashBlock
== NULL
)
2633 DPRINT("CmiGetCell() failed\n");
2634 return STATUS_UNSUCCESSFUL
;
2636 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2637 if (HashBlock
!= NULL
)
2639 CmiRemoveKeyFromHashTable(ParentKey
->RegistryHive
,
2641 SubKey
->KeyCellOffset
);
2642 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2643 ParentKey
->KeyCell
->HashTableOffset
);
2647 /* Remove the key's hash block */
2648 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2650 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
);
2651 HashBlock
= CmiGetCell (RegistryHive
,
2652 SubKey
->KeyCell
->HashTableOffset
,
2654 if (HashBlock
== NULL
)
2656 DPRINT("CmiGetCell() failed\n");
2657 return STATUS_UNSUCCESSFUL
;
2659 DPRINT("SubKey HashBlock %p\n", HashBlock
);
2660 if (HashBlock
!= NULL
)
2662 CmiDestroyCell (RegistryHive
,
2664 SubKey
->KeyCell
->HashTableOffset
);
2665 SubKey
->KeyCell
->HashTableOffset
= -1;
2669 /* Decrement the number of the parent key's sub keys */
2670 if (ParentKey
!= NULL
)
2672 DPRINT("ParentKey %p\n", ParentKey
);
2673 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2675 /* Remove the parent key's hash table */
2676 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2678 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2679 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2680 ParentKey
->KeyCell
->HashTableOffset
,
2682 if (HashBlock
== NULL
)
2684 DPRINT("CmiGetCell() failed\n");
2685 return STATUS_UNSUCCESSFUL
;
2687 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2688 if (HashBlock
!= NULL
)
2690 CmiDestroyCell (ParentKey
->RegistryHive
,
2692 ParentKey
->KeyCell
->HashTableOffset
);
2693 ParentKey
->KeyCell
->HashTableOffset
= (BLOCK_OFFSET
)-1;
2697 NtQuerySystemTime(&ParentKey
->KeyCell
->LastWriteTime
);
2698 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2699 ParentKey
->KeyCellOffset
);
2702 /* Destroy key cell */
2703 CmiDestroyCell (RegistryHive
,
2705 SubKey
->KeyCellOffset
);
2706 SubKey
->KeyCell
= NULL
;
2707 SubKey
->KeyCellOffset
= (BLOCK_OFFSET
)-1;
2709 return(STATUS_SUCCESS
);
2714 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2715 IN PKEY_CELL KeyCell
,
2716 IN PUNICODE_STRING ValueName
,
2717 OUT PVALUE_CELL
*ValueCell
,
2718 OUT BLOCK_OFFSET
*VBOffset
)
2720 PVALUE_LIST_CELL ValueListCell
;
2721 PVALUE_CELL CurValueCell
;
2726 /* The key does not have any values */
2727 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2729 return STATUS_SUCCESS
;
2732 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2733 if (ValueListCell
== NULL
)
2735 DPRINT("ValueListCell is NULL\n");
2736 return STATUS_UNSUCCESSFUL
;
2739 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2741 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2743 CurValueCell
= CmiGetCell (RegistryHive
,
2744 ValueListCell
->ValueOffset
[i
],
2746 if (CurValueCell
== NULL
)
2748 DPRINT("CmiGetBlock() failed\n");
2749 return STATUS_UNSUCCESSFUL
;
2752 if ((CurValueCell
!= NULL
) &&
2753 CmiComparePackedNames(ValueName
,
2755 CurValueCell
->NameSize
,
2756 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2758 *ValueCell
= CurValueCell
;
2760 *VBOffset
= ValueListCell
->ValueOffset
[i
];
2761 //DPRINT("Found value %s\n", ValueName);
2766 return STATUS_SUCCESS
;
2771 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2772 IN PKEY_CELL KeyCell
,
2774 OUT PVALUE_CELL
*ValueCell
)
2776 PVALUE_LIST_CELL ValueListCell
;
2777 PVALUE_CELL CurValueCell
;
2781 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2783 return STATUS_NO_MORE_ENTRIES
;
2786 if (Index
>= KeyCell
->NumberOfValues
)
2788 return STATUS_NO_MORE_ENTRIES
;
2792 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2793 if (ValueListCell
== NULL
)
2795 DPRINT("CmiGetBlock() failed\n");
2796 return STATUS_UNSUCCESSFUL
;
2799 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2802 CurValueCell
= CmiGetCell (RegistryHive
,
2803 ValueListCell
->ValueOffset
[Index
],
2805 if (CurValueCell
== NULL
)
2807 DPRINT("CmiGetBlock() failed\n");
2808 return STATUS_UNSUCCESSFUL
;
2811 *ValueCell
= CurValueCell
;
2813 return STATUS_SUCCESS
;
2818 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2819 IN PKEY_CELL KeyCell
,
2820 IN PUNICODE_STRING ValueName
,
2821 OUT PVALUE_CELL
*pValueCell
,
2822 OUT BLOCK_OFFSET
*pVBOffset
)
2824 PVALUE_LIST_CELL NewValueListCell
;
2825 PVALUE_LIST_CELL ValueListCell
;
2826 PVALUE_CELL NewValueCell
;
2827 BLOCK_OFFSET VLBOffset
;
2828 BLOCK_OFFSET VBOffset
;
2832 Status
= CmiAllocateValueCell(RegistryHive
,
2836 if (!NT_SUCCESS(Status
))
2841 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG
)KeyCell
->ValueListOffset
);
2843 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2845 if (ValueListCell
== NULL
)
2847 CellSize
= sizeof(VALUE_LIST_CELL
) +
2848 (3 * sizeof(BLOCK_OFFSET
));
2849 Status
= CmiAllocateCell (RegistryHive
,
2851 (PVOID
) &ValueListCell
,
2854 if (!NT_SUCCESS(Status
))
2856 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2859 KeyCell
->ValueListOffset
= VLBOffset
;
2861 else if (KeyCell
->NumberOfValues
>=
2862 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
)))
2864 CellSize
= sizeof(VALUE_LIST_CELL
) +
2865 ((KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) * sizeof(BLOCK_OFFSET
));
2866 Status
= CmiAllocateCell (RegistryHive
,
2868 (PVOID
) &NewValueListCell
,
2870 if (!NT_SUCCESS(Status
))
2872 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2876 RtlCopyMemory(&NewValueListCell
->ValueOffset
[0],
2877 &ValueListCell
->ValueOffset
[0],
2878 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2879 CmiDestroyCell (RegistryHive
, ValueListCell
, KeyCell
->ValueListOffset
);
2880 KeyCell
->ValueListOffset
= VLBOffset
;
2881 ValueListCell
= NewValueListCell
;
2884 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2885 KeyCell
->NumberOfValues
,
2886 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2887 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
),
2888 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
));
2890 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = VBOffset
;
2891 KeyCell
->NumberOfValues
++;
2893 *pValueCell
= NewValueCell
;
2894 *pVBOffset
= VBOffset
;
2896 return STATUS_SUCCESS
;
2901 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2902 IN PKEY_CELL KeyCell
,
2903 IN BLOCK_OFFSET KeyCellOffset
,
2904 IN PUNICODE_STRING ValueName
)
2906 PVALUE_LIST_CELL ValueListCell
;
2907 PVALUE_CELL CurValueCell
;
2910 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2912 if (ValueListCell
== NULL
)
2914 DPRINT("CmiGetBlock() failed\n");
2915 return STATUS_SUCCESS
;
2918 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2920 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2922 CurValueCell
= CmiGetCell (RegistryHive
, ValueListCell
->ValueOffset
[i
], NULL
);
2923 if (CurValueCell
== NULL
)
2925 DPRINT("CmiGetBlock() failed\n");
2926 return STATUS_UNSUCCESSFUL
;
2929 if ((CurValueCell
!= NULL
) &&
2930 CmiComparePackedNames(ValueName
,
2932 CurValueCell
->NameSize
,
2933 (BOOLEAN
)((CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
) ? TRUE
: FALSE
)))
2935 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->ValueOffset
[i
]);
2937 if ((KeyCell
->NumberOfValues
- 1) < i
)
2939 RtlCopyMemory(&ValueListCell
->ValueOffset
[i
],
2940 &ValueListCell
->ValueOffset
[i
+ 1],
2941 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2945 RtlZeroMemory(&ValueListCell
->ValueOffset
[i
], sizeof(BLOCK_OFFSET
));
2948 KeyCell
->NumberOfValues
-= 1;
2953 if (KeyCell
->NumberOfValues
== 0)
2955 CmiDestroyCell (RegistryHive
,
2957 KeyCell
->ValueListOffset
);
2961 CmiMarkBlockDirty(RegistryHive
,
2962 KeyCell
->ValueListOffset
);
2965 CmiMarkBlockDirty(RegistryHive
,
2968 return STATUS_SUCCESS
;
2973 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive
,
2974 OUT PHASH_TABLE_CELL
*HashBlock
,
2975 OUT BLOCK_OFFSET
*HBOffset
,
2976 IN ULONG SubKeyCount
)
2978 PHASH_TABLE_CELL NewHashBlock
;
2982 Status
= STATUS_SUCCESS
;
2984 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
2985 (SubKeyCount
* sizeof(HASH_RECORD
));
2986 Status
= CmiAllocateCell (RegistryHive
,
2988 (PVOID
*) &NewHashBlock
,
2991 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
2993 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2997 assert(SubKeyCount
<= 0xffff); /* should really be USHORT_MAX or similar */
2998 NewHashBlock
->Id
= REG_HASH_TABLE_CELL_ID
;
2999 NewHashBlock
->HashTableSize
= (USHORT
)SubKeyCount
;
3000 *HashBlock
= NewHashBlock
;
3008 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
3009 PHASH_TABLE_CELL HashCell
,
3012 BLOCK_OFFSET KeyOffset
;
3013 PHIVE_LINK HiveLink
;
3016 if (HashCell
== NULL
)
3019 if (HashCell
->Table
[Index
].KeyOffset
& 1)
3021 HiveLink
= (PHIVE_LINK
)(HashCell
->Table
[Index
].KeyOffset
& ~1);
3022 KeyCell
= CmiGetCell (HiveLink
->SubKeyRegistryHive
,
3023 HiveLink
->SubKeyCellOffset
,
3026 else if (IsPointerHive(RegistryHive
))
3028 KeyCell
= (PKEY_CELL
) HashCell
->Table
[Index
].KeyOffset
;
3032 KeyOffset
= HashCell
->Table
[Index
].KeyOffset
;
3033 KeyCell
= CmiGetCell (RegistryHive
, KeyOffset
, NULL
);
3041 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
3042 PKEY_CELL ParentKeyCell
,
3043 BLOCK_OFFSET ParentKeyCellOffset
,
3044 PREGISTRY_HIVE NewKeyRegistryHive
,
3045 PKEY_CELL NewKeyCell
,
3046 BLOCK_OFFSET NewKeyCellOffset
)
3048 BLOCK_OFFSET HashCellOffset
;
3049 PHASH_TABLE_CELL HashCell
;
3053 if (ParentKeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
3055 Status
= CmiAllocateHashTableCell (RegistryHive
,
3057 &ParentKeyCell
->HashTableOffset
,
3058 REG_INIT_HASH_TABLE_SIZE
);
3059 if (!NT_SUCCESS(Status
))
3063 CmiMarkBlockDirty(RegistryHive
, ParentKeyCellOffset
);
3067 HashCell
= CmiGetCell (RegistryHive
,
3068 ParentKeyCell
->HashTableOffset
,
3070 if (HashCell
== NULL
)
3072 DPRINT("CmiGetCell() failed\n");
3073 return STATUS_UNSUCCESSFUL
;
3076 if (((ParentKeyCell
->NumberOfSubKeys
+ 1) >= HashCell
->HashTableSize
))
3078 PHASH_TABLE_CELL NewHashCell
;
3079 BLOCK_OFFSET NewHashCellOffset
;
3081 /* Reallocate the hash table cell */
3082 Status
= CmiAllocateHashTableCell (RegistryHive
,
3085 HashCell
->HashTableSize
+
3086 REG_EXTEND_HASH_TABLE_SIZE
);
3087 if (!NT_SUCCESS(Status
))
3092 RtlZeroMemory(&NewHashCell
->Table
[0],
3093 sizeof(NewHashCell
->Table
[0]) * NewHashCell
->HashTableSize
);
3094 RtlCopyMemory(&NewHashCell
->Table
[0],
3095 &HashCell
->Table
[0],
3096 sizeof(NewHashCell
->Table
[0]) * HashCell
->HashTableSize
);
3097 CmiDestroyCell (RegistryHive
,
3099 ParentKeyCell
->HashTableOffset
);
3100 ParentKeyCell
->HashTableOffset
= NewHashCellOffset
;
3101 HashCell
= NewHashCell
;
3102 CmiMarkBlockDirty(RegistryHive
, ParentKeyCellOffset
);
3106 for (i
= 0; i
< HashCell
->HashTableSize
; i
++)
3108 if (HashCell
->Table
[i
].KeyOffset
== 0)
3110 if (NewKeyRegistryHive
!= NULL
&& NewKeyRegistryHive
!= RegistryHive
)
3112 PHIVE_LINK HiveLink
;
3114 HiveLink
= ExAllocatePool (NonPagedPool
, sizeof(HIVE_LINK
));
3115 if (HiveLink
== NULL
)
3116 return STATUS_INSUFFICIENT_RESOURCES
;
3118 InsertTailList (&CmiHiveLinkListHead
, &HiveLink
->Entry
);
3119 HiveLink
->ParentKeyRegistryHive
= RegistryHive
;
3120 HiveLink
->ParentKeyCellOffset
= ParentKeyCellOffset
;
3121 HiveLink
->SubKeyRegistryHive
= NewKeyRegistryHive
;
3122 HiveLink
->SubKeyCellOffset
= NewKeyCellOffset
;
3124 HashCell
->Table
[i
].KeyOffset
= (BLOCK_OFFSET
)((ULONG
)HiveLink
| 1);
3128 HashCell
->Table
[i
].KeyOffset
= NewKeyCellOffset
;
3130 HashCell
->Table
[i
].HashValue
= 0;
3131 if (NewKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3133 RtlCopyMemory(&HashCell
->Table
[i
].HashValue
,
3135 min(NewKeyCell
->NameSize
, sizeof(ULONG
)));
3137 CmiMarkBlockDirty(RegistryHive
, HashCellOffset
);
3138 ParentKeyCell
->NumberOfSubKeys
++;
3139 CmiMarkBlockDirty(RegistryHive
, ParentKeyCellOffset
);
3140 return STATUS_SUCCESS
;
3144 return STATUS_UNSUCCESSFUL
;
3149 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
3150 PHASH_TABLE_CELL HashBlock
,
3151 BLOCK_OFFSET NKBOffset
)
3155 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3157 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
3159 HashBlock
->Table
[i
].KeyOffset
= 0;
3160 HashBlock
->Table
[i
].HashValue
= 0;
3161 return STATUS_SUCCESS
;
3165 return STATUS_UNSUCCESSFUL
;
3170 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
3171 PVALUE_CELL
*ValueCell
,
3172 BLOCK_OFFSET
*VBOffset
,
3173 IN PUNICODE_STRING ValueName
)
3175 PVALUE_CELL NewValueCell
;
3181 Status
= STATUS_SUCCESS
;
3183 NameSize
= CmiGetPackedNameLength(ValueName
,
3186 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
3188 Status
= CmiAllocateCell (RegistryHive
,
3189 sizeof(VALUE_CELL
) + NameSize
,
3190 (PVOID
*) &NewValueCell
,
3192 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
3194 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3198 assert(NameSize
<= 0xffff); /* should really be USHORT_MAX or similar */
3199 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
3200 NewValueCell
->NameSize
= (USHORT
)NameSize
;
3203 /* Pack the value name */
3204 for (i
= 0; i
< NameSize
; i
++)
3205 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
3206 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
3210 /* Copy the value name */
3211 RtlCopyMemory(NewValueCell
->Name
,
3214 NewValueCell
->Flags
= 0;
3216 NewValueCell
->DataType
= 0;
3217 NewValueCell
->DataSize
= 0;
3218 NewValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
3219 *ValueCell
= NewValueCell
;
3227 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
3228 PVALUE_CELL ValueCell
,
3229 BLOCK_OFFSET VBOffset
)
3235 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell
, VBOffset
);
3237 VERIFY_VALUE_CELL(ValueCell
);
3239 /* Destroy the data cell */
3240 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
3242 pBlock
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, &pBin
);
3245 DPRINT("CmiGetBlock() failed\n");
3246 return STATUS_UNSUCCESSFUL
;
3249 Status
= CmiDestroyCell (RegistryHive
, pBlock
, ValueCell
->DataOffset
);
3250 if (!NT_SUCCESS(Status
))
3255 /* Update time of heap */
3256 if (!IsNoFileHive(RegistryHive
))
3257 NtQuerySystemTime(&pBin
->DateModified
);
3260 /* Destroy the value cell */
3261 Status
= CmiDestroyCell (RegistryHive
, ValueCell
, VBOffset
);
3263 /* Update time of heap */
3264 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, VBOffset
, &pBin
))
3266 NtQuerySystemTime(&pBin
->DateModified
);
3274 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
3276 BLOCK_OFFSET
*NewBlockOffset
)
3278 PCELL_HEADER tmpBlock
;
3279 PHBIN
* tmpBlockList
;
3282 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
3285 return STATUS_INSUFFICIENT_RESOURCES
;
3288 tmpBin
->BlockId
= REG_BIN_ID
;
3289 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
3290 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
3291 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
3292 tmpBin
->Unused1
= 0;
3293 ZwQuerySystemTime(&tmpBin
->DateModified
);
3294 tmpBin
->Unused2
= 0;
3296 /* Increase size of list of blocks */
3297 tmpBlockList
= ExAllocatePool(NonPagedPool
,
3298 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
3299 if (tmpBlockList
== NULL
)
3302 return STATUS_INSUFFICIENT_RESOURCES
;
3305 if (RegistryHive
->BlockListSize
> 0)
3307 RtlCopyMemory (tmpBlockList
,
3308 RegistryHive
->BlockList
,
3309 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
3310 ExFreePool(RegistryHive
->BlockList
);
3313 RegistryHive
->BlockList
= tmpBlockList
;
3314 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
] = tmpBin
;
3315 RegistryHive
->BlockListSize
++;
3317 /* Initialize a free block in this heap : */
3318 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
3319 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
3321 /* Grow bitmap if necessary */
3322 if (IsNoFileHive(RegistryHive
) &&
3323 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
3325 PULONG BitmapBuffer
;
3328 DPRINT("Grow hive bitmap\n");
3330 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3331 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
3332 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
3333 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
3334 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
3336 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
3337 RtlCopyMemory(BitmapBuffer
,
3338 RegistryHive
->DirtyBitMap
.Buffer
,
3339 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
3340 ExFreePool(RegistryHive
->BitmapBuffer
);
3341 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
3342 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
3343 RegistryHive
->BitmapBuffer
,
3347 *NewBlock
= (PVOID
) tmpBlock
;
3350 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
3352 /* Mark new bin dirty */
3353 CmiMarkBinDirty(RegistryHive
,
3354 tmpBin
->BlockOffset
);
3356 return STATUS_SUCCESS
;
3361 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
3364 BLOCK_OFFSET
*CellOffset
)
3366 PCELL_HEADER NewCell
;
3372 Status
= STATUS_SUCCESS
;
3374 /* Round to 16 bytes multiple */
3375 CellSize
= ROUND_UP(CellSize
, 16);
3377 /* Handle volatile hives first */
3378 if (IsPointerHive(RegistryHive
))
3380 NewCell
= ExAllocatePool(NonPagedPool
, CellSize
);
3382 if (NewCell
== NULL
)
3384 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3388 RtlZeroMemory(NewCell
, CellSize
);
3389 NewCell
->CellSize
= -CellSize
;
3392 if (CellOffset
!= NULL
)
3393 *CellOffset
= (BLOCK_OFFSET
) NewCell
;
3398 /* first search in free blocks */
3400 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3402 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
3404 NewCell
= RegistryHive
->FreeList
[i
];
3405 if (CellOffset
!= NULL
)
3406 *CellOffset
= RegistryHive
->FreeListOffset
[i
];
3408 /* Update time of heap */
3409 Temp
= CmiGetCell (RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
3412 DPRINT("CmiGetBlock() failed\n");
3413 return STATUS_UNSUCCESSFUL
;
3418 NtQuerySystemTime(&pBin
->DateModified
);
3419 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
3422 if ((i
+ 1) < RegistryHive
->FreeListSize
)
3424 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
3425 &RegistryHive
->FreeList
[i
+ 1],
3426 sizeof(RegistryHive
->FreeList
[0])
3427 * (RegistryHive
->FreeListSize
- i
- 1));
3428 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
3429 &RegistryHive
->FreeListOffset
[i
+ 1],
3430 sizeof(RegistryHive
->FreeListOffset
[0])
3431 * (RegistryHive
->FreeListSize
- i
- 1));
3433 RegistryHive
->FreeListSize
--;
3438 /* Need to extend hive file : */
3439 if (NewCell
== NULL
)
3442 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewCell
, CellOffset
);
3445 if (NT_SUCCESS(Status
))
3449 /* Split the block in two parts */
3450 if (NewCell
->CellSize
> CellSize
)
3452 NewCell
= (PCELL_HEADER
) ((ULONG_PTR
) NewCell
+ CellSize
);
3453 NewCell
->CellSize
= ((PCELL_HEADER
) (*Cell
))->CellSize
- CellSize
;
3454 CmiAddFree(RegistryHive
,
3456 *CellOffset
+ CellSize
,
3458 CmiMarkBlockDirty(RegistryHive
,
3459 *CellOffset
+ CellSize
);
3461 else if (NewCell
->CellSize
< CellSize
)
3463 return(STATUS_UNSUCCESSFUL
);
3466 RtlZeroMemory(*Cell
, CellSize
);
3467 ((PCELL_HEADER
) (*Cell
))->CellSize
= -CellSize
;
3476 CmiDestroyCell (PREGISTRY_HIVE RegistryHive
,
3478 BLOCK_OFFSET CellOffset
)
3483 Status
= STATUS_SUCCESS
;
3485 if (IsPointerHive(RegistryHive
))
3491 PCELL_HEADER pFree
= Cell
;
3493 if (pFree
->CellSize
< 0)
3494 pFree
->CellSize
= -pFree
->CellSize
;
3496 /* Clear block (except the block size) */
3497 RtlZeroMemory(((char*)pFree
) + sizeof(ULONG
),
3498 pFree
->CellSize
- sizeof(ULONG
));
3500 /* Add block to the list of free blocks */
3501 CmiAddFree(RegistryHive
, Cell
, CellOffset
, TRUE
);
3503 /* Update time of heap */
3504 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, CellOffset
,&pBin
))
3505 NtQuerySystemTime(&pBin
->DateModified
);
3507 CmiMarkBlockDirty(RegistryHive
, CellOffset
);
3515 CmiGetCell (PREGISTRY_HIVE RegistryHive
,
3516 BLOCK_OFFSET CellOffset
,
3526 if (CellOffset
== (BLOCK_OFFSET
)-1)
3531 if (IsPointerHive (RegistryHive
))
3533 return (PVOID
)CellOffset
;
3536 if (CellOffset
> RegistryHive
->BlockListSize
* 4096)
3538 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3539 CellOffset
, RegistryHive
->BlockListSize
* 4096);
3543 pBin
= RegistryHive
->BlockList
[CellOffset
/ 4096];
3554 return((PVOID
)((ULONG_PTR
)pBin
+ (CellOffset
- pBin
->BlockOffset
)));
3559 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3560 PCELL_HEADER FreeBlock
,
3561 BLOCK_OFFSET FreeOffset
)
3563 BLOCK_OFFSET BlockOffset
;
3564 BLOCK_OFFSET BinOffset
;
3570 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3571 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3573 CmiGetCell (RegistryHive
,
3576 DPRINT("Bin %p\n", Bin
);
3580 BinOffset
= Bin
->BlockOffset
;
3581 BinSize
= Bin
->BlockSize
;
3582 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3584 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3586 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3587 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3588 if (BlockOffset
> BinOffset
&&
3589 BlockOffset
< BinOffset
+ BinSize
)
3591 DPRINT("Free block: Offset %lx Size %lx\n",
3592 BlockOffset
, BlockSize
);
3594 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3595 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3596 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3598 DPRINT("Merge current block with previous and next block\n");
3600 RegistryHive
->FreeList
[i
]->CellSize
+=
3601 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3603 FreeBlock
->CellSize
= 0;
3604 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3607 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3609 RtlMoveMemory(&RegistryHive
->FreeList
[i
+ 1],
3610 &RegistryHive
->FreeList
[i
+ 2],
3611 sizeof(RegistryHive
->FreeList
[0])
3612 * (RegistryHive
->FreeListSize
- i
- 2));
3613 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3614 &RegistryHive
->FreeListOffset
[i
+ 2],
3615 sizeof(RegistryHive
->FreeListOffset
[0])
3616 * (RegistryHive
->FreeListSize
- i
- 2));
3618 RegistryHive
->FreeListSize
--;
3620 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3624 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3626 DPRINT("Merge current block with previous block\n");
3628 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3629 FreeBlock
->CellSize
= 0;
3631 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3635 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3637 DPRINT("Merge current block with next block\n");
3639 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3640 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3641 RegistryHive
->FreeList
[i
] = FreeBlock
;
3642 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3644 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3656 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3657 PCELL_HEADER FreeBlock
,
3658 BLOCK_OFFSET FreeOffset
,
3659 BOOLEAN MergeFreeBlocks
)
3661 PCELL_HEADER
*tmpList
;
3662 BLOCK_OFFSET
*tmpListOffset
;
3667 assert(RegistryHive
);
3670 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3671 FreeBlock
, FreeOffset
);
3673 /* Merge free blocks */
3674 if (MergeFreeBlocks
== TRUE
)
3676 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3677 return(STATUS_SUCCESS
);
3680 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3682 tmpList
= ExAllocatePool(PagedPool
,
3683 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3684 if (tmpList
== NULL
)
3685 return STATUS_INSUFFICIENT_RESOURCES
;
3687 tmpListOffset
= ExAllocatePool(PagedPool
,
3688 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3690 if (tmpListOffset
== NULL
)
3692 ExFreePool(tmpList
);
3693 return STATUS_INSUFFICIENT_RESOURCES
;
3696 if (RegistryHive
->FreeListMax
)
3698 RtlMoveMemory(tmpList
,
3699 RegistryHive
->FreeList
,
3700 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3701 RtlMoveMemory(tmpListOffset
,
3702 RegistryHive
->FreeListOffset
,
3703 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3704 ExFreePool(RegistryHive
->FreeList
);
3705 ExFreePool(RegistryHive
->FreeListOffset
);
3707 RegistryHive
->FreeList
= tmpList
;
3708 RegistryHive
->FreeListOffset
= tmpListOffset
;
3709 RegistryHive
->FreeListMax
+= 32;
3712 /* Add new offset to free list, maintaining list in ascending order */
3713 if ((RegistryHive
->FreeListSize
== 0)
3714 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3716 /* Add to end of list */
3717 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3718 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3720 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3722 /* Add to begin of list */
3723 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3724 &RegistryHive
->FreeList
[0],
3725 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3726 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3727 &RegistryHive
->FreeListOffset
[0],
3728 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3729 RegistryHive
->FreeList
[0] = FreeBlock
;
3730 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3731 RegistryHive
->FreeListSize
++;
3735 /* Search where to insert */
3737 maxInd
= RegistryHive
->FreeListSize
- 1;
3738 while ((maxInd
- minInd
) > 1)
3740 medInd
= (minInd
+ maxInd
) / 2;
3741 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3747 /* Insert before maxInd */
3748 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3749 &RegistryHive
->FreeList
[maxInd
],
3750 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3751 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3752 &RegistryHive
->FreeListOffset
[maxInd
],
3753 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3754 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3755 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3756 RegistryHive
->FreeListSize
++;
3759 return STATUS_SUCCESS
;
3764 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3765 BLOCK_OFFSET BlockOffset
)
3772 if (IsNoFileHive(RegistryHive
))
3775 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3777 BlockNumber
= (ULONG
)BlockOffset
/ 4096;
3779 Cell
= CmiGetCell (RegistryHive
,
3783 CellSize
= Cell
->CellSize
;
3785 CellSize
= -CellSize
;
3787 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, 4096) - ROUND_DOWN(BlockOffset
, 4096)) / 4096;
3789 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3792 (Cell
->CellSize
< 0) ? "used" : "free",
3795 RegistryHive
->HiveDirty
= TRUE
;
3796 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3803 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3804 BLOCK_OFFSET BinOffset
)
3810 if (IsNoFileHive(RegistryHive
))
3813 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3815 BlockNumber
= (ULONG
)BinOffset
/ 4096;
3817 Bin
= RegistryHive
->BlockList
[BlockNumber
];
3819 BlockCount
= Bin
->BlockSize
/ 4096;
3821 DPRINT(" BlockNumber %lu Size %lu BlockCount %lu\n",
3826 RegistryHive
->HiveDirty
= TRUE
;
3827 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3834 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3835 OUT PBOOLEAN Packable
)
3839 if (Packable
!= NULL
)
3842 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3844 if (Name
->Buffer
[i
] & 0xFF00)
3846 if (Packable
!= NULL
)
3848 return Name
->Length
;
3852 return (Name
->Length
/ sizeof(WCHAR
));
3857 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3858 IN PCHAR NameBuffer
,
3859 IN USHORT NameBufferSize
,
3860 IN BOOLEAN NamePacked
)
3865 if (NamePacked
== TRUE
)
3867 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3870 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3872 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3878 if (Name
->Length
!= NameBufferSize
)
3881 UNameBuffer
= (PWCHAR
)NameBuffer
;
3883 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3885 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3895 CmiCopyPackedName(PWCHAR NameBuffer
,
3896 PCHAR PackedNameBuffer
,
3897 ULONG PackedNameSize
)
3901 for (i
= 0; i
< PackedNameSize
; i
++)
3902 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];
3907 CmiCompareHash(PUNICODE_STRING KeyName
,
3912 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3913 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3914 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3915 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3917 return (strncmp(Buffer
, HashString
, 4) == 0);
3922 CmiCompareHashI(PUNICODE_STRING KeyName
,
3927 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3928 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3929 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3930 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3932 return (_strnicmp(Buffer
, HashString
, 4) == 0);
3937 CmiCompareKeyNames(PUNICODE_STRING KeyName
,
3943 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3945 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3947 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3950 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3952 if (KeyName
->Buffer
[i
] != (WCHAR
)KeyCell
->Name
[i
])
3958 if (KeyName
->Length
!= KeyCell
->NameSize
)
3961 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3962 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3964 if (KeyName
->Buffer
[i
] != UnicodeName
[i
])
3974 CmiCompareKeyNamesI(PUNICODE_STRING KeyName
,
3980 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3982 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3984 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3987 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3989 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3990 RtlUpcaseUnicodeChar((WCHAR
)KeyCell
->Name
[i
]))
3996 if (KeyName
->Length
!= KeyCell
->NameSize
)
3999 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
4000 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
4002 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
4003 RtlUpcaseUnicodeChar(UnicodeName
[i
]))
4013 CmiCopyKey (PREGISTRY_HIVE DstHive
,
4014 PKEY_CELL DstKeyCell
,
4015 PREGISTRY_HIVE SrcHive
,
4016 PKEY_CELL SrcKeyCell
)
4018 PKEY_CELL NewKeyCell
;
4019 ULONG NewKeyCellSize
;
4020 BLOCK_OFFSET NewKeyCellOffset
;
4021 PHASH_TABLE_CELL NewHashTableCell
;
4022 ULONG NewHashTableSize
;
4023 BLOCK_OFFSET NewHashTableOffset
;
4027 DPRINT ("CmiCopyKey() called\n");
4029 if (DstKeyCell
== NULL
)
4031 /* Allocate and copy key cell */
4032 NewKeyCellSize
= sizeof(KEY_CELL
) + SrcKeyCell
->NameSize
;
4033 Status
= CmiAllocateCell (DstHive
,
4035 (PVOID
) &NewKeyCell
,
4037 if (!NT_SUCCESS(Status
))
4039 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4042 if (NewKeyCell
== NULL
)
4044 DPRINT1 ("Failed to allocate a key cell\n");
4045 return STATUS_INSUFFICIENT_RESOURCES
;
4048 RtlCopyMemory (NewKeyCell
,
4052 DstHive
->HiveHeader
->RootKeyOffset
= NewKeyCellOffset
;
4054 /* Copy class name */
4055 if (SrcKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4057 PDATA_CELL SrcClassNameCell
;
4058 PDATA_CELL NewClassNameCell
;
4059 BLOCK_OFFSET NewClassNameOffset
;
4061 SrcClassNameCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ClassNameOffset
, NULL
),
4063 NewKeyCell
->ClassSize
= SrcKeyCell
->ClassSize
;
4064 Status
= CmiAllocateCell (DstHive
,
4065 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
4066 (PVOID
)&NewClassNameCell
,
4067 &NewClassNameOffset
);
4068 if (!NT_SUCCESS(Status
))
4070 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4074 RtlCopyMemory (NewClassNameCell
,
4076 NewKeyCell
->ClassSize
);
4077 NewKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4082 NewKeyCell
= DstKeyCell
;
4085 /* Allocate hash table */
4086 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4088 NewHashTableSize
= ROUND_UP(SrcKeyCell
->NumberOfSubKeys
+ 1, 4) - 1;
4089 Status
= CmiAllocateHashTableCell (DstHive
,
4091 &NewHashTableOffset
,
4093 if (!NT_SUCCESS(Status
))
4095 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status
);
4098 NewKeyCell
->HashTableOffset
= NewHashTableOffset
;
4101 /* Allocate and copy value list and values */
4102 if (SrcKeyCell
->NumberOfValues
!= 0)
4104 PVALUE_LIST_CELL NewValueListCell
;
4105 PVALUE_LIST_CELL SrcValueListCell
;
4106 PVALUE_CELL NewValueCell
;
4107 PVALUE_CELL SrcValueCell
;
4108 PDATA_CELL SrcValueDataCell
;
4109 PDATA_CELL NewValueDataCell
;
4110 BLOCK_OFFSET ValueCellOffset
;
4111 BLOCK_OFFSET ValueDataCellOffset
;
4112 ULONG NewValueListCellSize
;
4113 ULONG NewValueCellSize
;
4116 NewValueListCellSize
=
4117 ROUND_UP(SrcKeyCell
->NumberOfValues
, 4) * sizeof(BLOCK_OFFSET
);
4118 Status
= CmiAllocateCell (DstHive
,
4119 NewValueListCellSize
,
4120 (PVOID
)&NewValueListCell
,
4121 &NewKeyCell
->ValueListOffset
);
4122 if (!NT_SUCCESS(Status
))
4124 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4128 RtlZeroMemory (NewValueListCell
,
4129 NewValueListCellSize
);
4132 SrcValueListCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ValueListOffset
, NULL
);
4133 for (i
= 0; i
< SrcKeyCell
->NumberOfValues
; i
++)
4135 /* Copy value cell */
4136 SrcValueCell
= CmiGetCell (SrcHive
, SrcValueListCell
->ValueOffset
[i
], NULL
);
4138 NewValueCellSize
= sizeof(VALUE_CELL
) + SrcValueCell
->NameSize
;
4139 Status
= CmiAllocateCell (DstHive
,
4141 (PVOID
*) &NewValueCell
,
4143 if (!NT_SUCCESS(Status
))
4145 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4149 NewValueListCell
->ValueOffset
[i
] = ValueCellOffset
;
4150 RtlCopyMemory (NewValueCell
,
4154 /* Copy value data cell */
4155 if (SrcValueCell
->DataSize
> (LONG
) sizeof(PVOID
))
4157 SrcValueDataCell
= CmiGetCell (SrcHive
, SrcValueCell
->DataOffset
, NULL
);
4159 Status
= CmiAllocateCell (DstHive
,
4160 sizeof(CELL_HEADER
) + SrcValueCell
->DataSize
,
4161 (PVOID
*) &NewValueDataCell
,
4162 &ValueDataCellOffset
);
4163 if (!NT_SUCCESS(Status
))
4165 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4168 RtlCopyMemory (NewValueDataCell
,
4170 SrcValueCell
->DataSize
);
4171 NewValueCell
->DataOffset
= ValueDataCellOffset
;
4177 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4179 PHASH_TABLE_CELL SrcHashTableCell
;
4180 PKEY_CELL SrcSubKeyCell
;
4181 PKEY_CELL NewSubKeyCell
;
4182 ULONG NewSubKeyCellSize
;
4183 BLOCK_OFFSET NewSubKeyCellOffset
;
4184 PHASH_RECORD SrcHashRecord
;
4186 SrcHashTableCell
= CmiGetCell (SrcHive
,
4187 SrcKeyCell
->HashTableOffset
,
4190 for (i
= 0; i
< SrcKeyCell
->NumberOfSubKeys
; i
++)
4192 SrcHashRecord
= &SrcHashTableCell
->Table
[i
];
4193 SrcSubKeyCell
= CmiGetCell (SrcHive
, SrcHashRecord
->KeyOffset
, NULL
);
4195 /* Allocate and copy key cell */
4196 NewSubKeyCellSize
= sizeof(KEY_CELL
) + SrcSubKeyCell
->NameSize
;
4197 Status
= CmiAllocateCell (DstHive
,
4199 (PVOID
)&NewSubKeyCell
,
4200 &NewSubKeyCellOffset
);
4201 if (!NT_SUCCESS(Status
))
4203 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4206 if (NewKeyCell
== NULL
)
4208 DPRINT1 ("Failed to allocate a sub key cell\n");
4209 return STATUS_INSUFFICIENT_RESOURCES
;
4212 NewHashTableCell
->Table
[i
].KeyOffset
= NewSubKeyCellOffset
;
4213 NewHashTableCell
->Table
[i
].HashValue
= SrcHashRecord
->HashValue
;
4215 RtlCopyMemory (NewSubKeyCell
,
4219 /* Copy class name */
4220 if (SrcSubKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4222 PDATA_CELL SrcClassNameCell
;
4223 PDATA_CELL NewClassNameCell
;
4224 BLOCK_OFFSET NewClassNameOffset
;
4226 SrcClassNameCell
= CmiGetCell (SrcHive
,
4227 SrcSubKeyCell
->ClassNameOffset
,
4230 NewSubKeyCell
->ClassSize
= SrcSubKeyCell
->ClassSize
;
4231 Status
= CmiAllocateCell (DstHive
,
4232 sizeof(CELL_HEADER
) + NewSubKeyCell
->ClassSize
,
4233 (PVOID
)&NewClassNameCell
,
4234 &NewClassNameOffset
);
4235 if (!NT_SUCCESS(Status
))
4237 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4241 NewSubKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4242 RtlCopyMemory (NewClassNameCell
,
4244 NewSubKeyCell
->ClassSize
);
4247 /* Copy subkey data and subkeys */
4248 Status
= CmiCopyKey (DstHive
,
4252 if (!NT_SUCCESS(Status
))
4254 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4260 return STATUS_SUCCESS
;
4265 CmiSaveTempHive (PREGISTRY_HIVE Hive
,
4268 IO_STATUS_BLOCK IoStatusBlock
;
4269 LARGE_INTEGER FileOffset
;
4274 DPRINT ("CmiSaveTempHive() called\n");
4276 Hive
->HiveHeader
->Checksum
= CmiCalcChecksum ((PULONG
)Hive
->HiveHeader
);
4278 /* Write hive block */
4279 #if defined(__GNUC__)
4280 FileOffset
.QuadPart
= 0ULL;
4282 FileOffset
.QuadPart
= 0;
4284 Status
= NtWriteFile (FileHandle
,
4290 sizeof(HIVE_HEADER
),
4293 if (!NT_SUCCESS(Status
))
4295 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4299 DPRINT ("Saving %lu blocks\n", Hive
->BlockListSize
);
4300 for (BlockIndex
= 0; BlockIndex
< Hive
->BlockListSize
; BlockIndex
++)
4302 BlockPtr
= Hive
->BlockList
[BlockIndex
];
4303 DPRINT ("BlockPtr %p\n", BlockPtr
);
4305 #if defined(__GNUC__)
4306 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096ULL;
4308 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096;
4310 DPRINT ("File offset %I64x\n", FileOffset
.QuadPart
);
4312 /* Write hive block */
4313 Status
= NtWriteFile (FileHandle
,
4322 if (!NT_SUCCESS(Status
))
4324 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4329 Status
= NtFlushBuffersFile (FileHandle
,
4331 if (!NT_SUCCESS(Status
))
4333 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
4336 DPRINT ("CmiSaveTempHive() done\n");