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
< (CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2256 MaxValueData
= CurValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2260 return MaxValueData
;
2265 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
2266 IN PKEY_CELL KeyCell
,
2267 OUT PKEY_CELL
*SubKeyCell
,
2268 OUT BLOCK_OFFSET
*BlockOffset
,
2269 IN PUNICODE_STRING KeyName
,
2270 IN ACCESS_MASK DesiredAccess
,
2271 IN ULONG Attributes
)
2273 PHASH_TABLE_CELL HashBlock
;
2274 PKEY_CELL CurSubKeyCell
;
2277 VERIFY_KEY_CELL(KeyCell
);
2279 DPRINT("Scanning for sub key %wZ\n", KeyName
);
2281 assert(RegistryHive
);
2285 /* The key does not have any subkeys */
2286 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
2288 return STATUS_SUCCESS
;
2291 /* Get hash table */
2292 HashBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2293 if (HashBlock
== NULL
)
2295 DPRINT("CmiGetBlock() failed\n");
2296 return STATUS_UNSUCCESSFUL
;
2299 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
) && (i
< HashBlock
->HashTableSize
); i
++)
2301 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2303 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2304 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1 &&
2305 (HashBlock
->Table
[i
].HashValue
== 0 ||
2306 CmiCompareHashI(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2308 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2309 HashBlock
->Table
[i
].KeyOffset
,
2311 if (CurSubKeyCell
== NULL
)
2313 DPRINT("CmiGetBlock() failed\n");
2314 return STATUS_UNSUCCESSFUL
;
2317 if (CmiCompareKeyNamesI(KeyName
, CurSubKeyCell
))
2319 *SubKeyCell
= CurSubKeyCell
;
2320 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2327 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2328 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2329 (HashBlock
->Table
[i
].HashValue
== 0 ||
2330 CmiCompareHash(KeyName
, (PCHAR
)&HashBlock
->Table
[i
].HashValue
)))
2332 CurSubKeyCell
= CmiGetCell (RegistryHive
,
2333 HashBlock
->Table
[i
].KeyOffset
,
2335 if (CurSubKeyCell
== NULL
)
2337 DPRINT("CmiGetBlock() failed\n");
2338 return STATUS_UNSUCCESSFUL
;
2341 if (CmiCompareKeyNames(KeyName
, CurSubKeyCell
))
2343 *SubKeyCell
= CurSubKeyCell
;
2344 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2351 return STATUS_SUCCESS
;
2356 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2357 PKEY_OBJECT ParentKey
,
2359 PUNICODE_STRING SubKeyName
,
2361 PUNICODE_STRING Class
,
2362 ULONG CreateOptions
)
2364 PHASH_TABLE_CELL HashBlock
;
2365 BLOCK_OFFSET NKBOffset
;
2366 PKEY_CELL NewKeyCell
;
2368 PKEY_CELL ParentKeyCell
;
2369 PDATA_CELL ClassCell
;
2376 ParentKeyCell
= ParentKey
->KeyCell
;
2378 VERIFY_KEY_CELL(ParentKeyCell
);
2380 /* Skip leading backslash */
2381 if (SubKeyName
->Buffer
[0] == L
'\\')
2383 NamePtr
= &SubKeyName
->Buffer
[1];
2384 NameSize
= SubKeyName
->Length
- sizeof(WCHAR
);
2388 NamePtr
= SubKeyName
->Buffer
;
2389 NameSize
= SubKeyName
->Length
;
2392 /* Check whether key name can be packed */
2394 for (i
= 0; i
< NameSize
/ sizeof(WCHAR
); i
++)
2396 if (NamePtr
[i
] & 0xFF00)
2403 /* Adjust name size */
2406 NameSize
= NameSize
/ sizeof(WCHAR
);
2409 DPRINT("Key %S Length %lu %s\n", NamePtr
, NameSize
, (Packable
)?"True":"False");
2411 Status
= STATUS_SUCCESS
;
2413 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2414 Status
= CmiAllocateCell (RegistryHive
,
2416 (PVOID
) &NewKeyCell
,
2418 if (NewKeyCell
== NULL
)
2420 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2424 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2425 NewKeyCell
->Flags
= 0;
2426 NtQuerySystemTime(&NewKeyCell
->LastWriteTime
);
2427 NewKeyCell
->ParentKeyOffset
= -1;
2428 NewKeyCell
->NumberOfSubKeys
= 0;
2429 NewKeyCell
->HashTableOffset
= -1;
2430 NewKeyCell
->NumberOfValues
= 0;
2431 NewKeyCell
->ValueListOffset
= -1;
2432 NewKeyCell
->SecurityKeyOffset
= -1;
2433 NewKeyCell
->ClassNameOffset
= -1;
2435 /* Pack the key name */
2436 NewKeyCell
->NameSize
= NameSize
;
2439 NewKeyCell
->Flags
|= REG_KEY_NAME_PACKED
;
2440 for (i
= 0; i
< NameSize
; i
++)
2442 NewKeyCell
->Name
[i
] = (CHAR
)(NamePtr
[i
] & 0x00FF);
2447 RtlCopyMemory(NewKeyCell
->Name
,
2452 VERIFY_KEY_CELL(NewKeyCell
);
2456 NewKeyCell
->ClassSize
= Class
->Length
;
2457 Status
= CmiAllocateCell (RegistryHive
,
2458 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
2460 &NewKeyCell
->ClassNameOffset
);
2461 RtlCopyMemory (ClassCell
->Data
,
2467 if (!NT_SUCCESS(Status
))
2472 SubKey
->KeyCell
= NewKeyCell
;
2473 SubKey
->KeyCellOffset
= NKBOffset
;
2475 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2476 if (IsPointerHive(RegistryHive
) && (!IsPointerHive(ParentKey
->RegistryHive
)))
2481 if (ParentKeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2483 Status
= CmiAllocateHashTableCell (RegistryHive
,
2485 &ParentKeyCell
->HashTableOffset
,
2486 REG_INIT_HASH_TABLE_SIZE
);
2487 if (!NT_SUCCESS(Status
))
2494 HashBlock
= CmiGetCell (RegistryHive
,
2495 ParentKeyCell
->HashTableOffset
,
2497 if (HashBlock
== NULL
)
2499 DPRINT("CmiGetCell() failed\n");
2500 return STATUS_UNSUCCESSFUL
;
2503 if (((ParentKeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2505 PHASH_TABLE_CELL NewHashBlock
;
2506 BLOCK_OFFSET HTOffset
;
2508 /* Reallocate the hash table cell */
2509 Status
= CmiAllocateHashTableCell (RegistryHive
,
2512 HashBlock
->HashTableSize
+
2513 REG_EXTEND_HASH_TABLE_SIZE
);
2514 if (!NT_SUCCESS(Status
))
2519 RtlZeroMemory(&NewHashBlock
->Table
[0],
2520 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2521 RtlCopyMemory(&NewHashBlock
->Table
[0],
2522 &HashBlock
->Table
[0],
2523 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2524 CmiDestroyCell (RegistryHive
,
2526 ParentKeyCell
->HashTableOffset
);
2527 ParentKeyCell
->HashTableOffset
= HTOffset
;
2528 HashBlock
= NewHashBlock
;
2532 Status
= CmiAddKeyToHashTable(RegistryHive
,
2534 ParentKeyCell
->HashTableOffset
,
2537 if (NT_SUCCESS(Status
))
2539 ParentKeyCell
->NumberOfSubKeys
++;
2542 NtQuerySystemTime (&ParentKeyCell
->LastWriteTime
);
2543 CmiMarkBlockDirty (RegistryHive
, ParentKey
->KeyCellOffset
);
2550 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2551 PKEY_OBJECT ParentKey
,
2554 PHASH_TABLE_CELL HashBlock
;
2555 PVALUE_LIST_CELL ValueList
;
2556 PVALUE_CELL ValueCell
;
2557 PDATA_CELL DataCell
;
2560 DPRINT("CmiRemoveSubKey() called\n");
2562 /* Remove all values */
2563 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2565 /* Get pointer to the value list cell */
2566 ValueList
= CmiGetCell (RegistryHive
,
2567 SubKey
->KeyCell
->ValueListOffset
,
2569 if (ValueList
== NULL
)
2571 DPRINT("CmiGetCell() failed\n");
2572 return STATUS_UNSUCCESSFUL
;
2575 if (ValueList
!= NULL
)
2577 /* Enumerate all values */
2578 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2580 /* Get pointer to value cell */
2581 ValueCell
= CmiGetCell (RegistryHive
,
2582 ValueList
->ValueOffset
[i
],
2584 if (ValueCell
!= NULL
)
2586 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
2588 DataCell
= CmiGetCell (RegistryHive
,
2589 ValueCell
->DataOffset
,
2591 if (DataCell
== NULL
)
2593 DPRINT("CmiGetCell() failed\n");
2594 return STATUS_UNSUCCESSFUL
;
2597 if (DataCell
!= NULL
)
2599 /* Destroy data cell */
2600 CmiDestroyCell (RegistryHive
,
2602 ValueCell
->DataOffset
);
2606 /* Destroy value cell */
2607 CmiDestroyCell (RegistryHive
,
2609 ValueList
->ValueOffset
[i
]);
2614 /* Destroy value list cell */
2615 CmiDestroyCell (RegistryHive
,
2617 SubKey
->KeyCell
->ValueListOffset
);
2619 SubKey
->KeyCell
->NumberOfValues
= 0;
2620 SubKey
->KeyCell
->ValueListOffset
= (BLOCK_OFFSET
)-1;
2623 /* Remove the key from the parent key's hash block */
2624 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2626 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2627 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2628 ParentKey
->KeyCell
->HashTableOffset
,
2630 if (HashBlock
== NULL
)
2632 DPRINT("CmiGetCell() failed\n");
2633 return STATUS_UNSUCCESSFUL
;
2635 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2636 if (HashBlock
!= NULL
)
2638 CmiRemoveKeyFromHashTable(ParentKey
->RegistryHive
,
2640 SubKey
->KeyCellOffset
);
2641 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2642 ParentKey
->KeyCell
->HashTableOffset
);
2646 /* Remove the key's hash block */
2647 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2649 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
);
2650 HashBlock
= CmiGetCell (RegistryHive
,
2651 SubKey
->KeyCell
->HashTableOffset
,
2653 if (HashBlock
== NULL
)
2655 DPRINT("CmiGetCell() failed\n");
2656 return STATUS_UNSUCCESSFUL
;
2658 DPRINT("SubKey HashBlock %p\n", HashBlock
);
2659 if (HashBlock
!= NULL
)
2661 CmiDestroyCell (RegistryHive
,
2663 SubKey
->KeyCell
->HashTableOffset
);
2664 SubKey
->KeyCell
->HashTableOffset
= -1;
2668 /* Decrement the number of the parent key's sub keys */
2669 if (ParentKey
!= NULL
)
2671 DPRINT("ParentKey %p\n", ParentKey
);
2672 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2674 /* Remove the parent key's hash table */
2675 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2677 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
);
2678 HashBlock
= CmiGetCell (ParentKey
->RegistryHive
,
2679 ParentKey
->KeyCell
->HashTableOffset
,
2681 if (HashBlock
== NULL
)
2683 DPRINT("CmiGetCell() failed\n");
2684 return STATUS_UNSUCCESSFUL
;
2686 DPRINT("ParentKey HashBlock %p\n", HashBlock
);
2687 if (HashBlock
!= NULL
)
2689 CmiDestroyCell (ParentKey
->RegistryHive
,
2691 ParentKey
->KeyCell
->HashTableOffset
);
2692 ParentKey
->KeyCell
->HashTableOffset
= (BLOCK_OFFSET
)-1;
2696 NtQuerySystemTime(&ParentKey
->KeyCell
->LastWriteTime
);
2697 CmiMarkBlockDirty(ParentKey
->RegistryHive
,
2698 ParentKey
->KeyCellOffset
);
2701 /* Destroy key cell */
2702 CmiDestroyCell (RegistryHive
,
2704 SubKey
->KeyCellOffset
);
2705 SubKey
->KeyCell
= NULL
;
2706 SubKey
->KeyCellOffset
= (BLOCK_OFFSET
)-1;
2708 return(STATUS_SUCCESS
);
2713 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2714 IN PKEY_CELL KeyCell
,
2715 IN PUNICODE_STRING ValueName
,
2716 OUT PVALUE_CELL
*ValueCell
,
2717 OUT BLOCK_OFFSET
*VBOffset
)
2719 PVALUE_LIST_CELL ValueListCell
;
2720 PVALUE_CELL CurValueCell
;
2725 /* The key does not have any values */
2726 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2728 return STATUS_SUCCESS
;
2731 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2732 if (ValueListCell
== NULL
)
2734 DPRINT("ValueListCell is NULL\n");
2735 return STATUS_UNSUCCESSFUL
;
2738 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2740 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2742 CurValueCell
= CmiGetCell (RegistryHive
,
2743 ValueListCell
->ValueOffset
[i
],
2745 if (CurValueCell
== NULL
)
2747 DPRINT("CmiGetBlock() failed\n");
2748 return STATUS_UNSUCCESSFUL
;
2751 if ((CurValueCell
!= NULL
) &&
2752 CmiComparePackedNames(ValueName
,
2754 CurValueCell
->NameSize
,
2755 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
2757 *ValueCell
= CurValueCell
;
2759 *VBOffset
= ValueListCell
->ValueOffset
[i
];
2760 //DPRINT("Found value %s\n", ValueName);
2765 return STATUS_SUCCESS
;
2770 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2771 IN PKEY_CELL KeyCell
,
2773 OUT PVALUE_CELL
*ValueCell
)
2775 PVALUE_LIST_CELL ValueListCell
;
2776 PVALUE_CELL CurValueCell
;
2780 if (KeyCell
->ValueListOffset
== (BLOCK_OFFSET
)-1)
2782 return STATUS_NO_MORE_ENTRIES
;
2785 if (Index
>= KeyCell
->NumberOfValues
)
2787 return STATUS_NO_MORE_ENTRIES
;
2791 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2792 if (ValueListCell
== NULL
)
2794 DPRINT("CmiGetBlock() failed\n");
2795 return STATUS_UNSUCCESSFUL
;
2798 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2801 CurValueCell
= CmiGetCell (RegistryHive
,
2802 ValueListCell
->ValueOffset
[Index
],
2804 if (CurValueCell
== NULL
)
2806 DPRINT("CmiGetBlock() failed\n");
2807 return STATUS_UNSUCCESSFUL
;
2810 *ValueCell
= CurValueCell
;
2812 return STATUS_SUCCESS
;
2817 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2818 IN PKEY_CELL KeyCell
,
2819 IN PUNICODE_STRING ValueName
,
2820 OUT PVALUE_CELL
*pValueCell
,
2821 OUT BLOCK_OFFSET
*pVBOffset
)
2823 PVALUE_LIST_CELL NewValueListCell
;
2824 PVALUE_LIST_CELL ValueListCell
;
2825 PVALUE_CELL NewValueCell
;
2826 BLOCK_OFFSET VLBOffset
;
2827 BLOCK_OFFSET VBOffset
;
2831 Status
= CmiAllocateValueCell(RegistryHive
,
2835 if (!NT_SUCCESS(Status
))
2840 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG
)KeyCell
->ValueListOffset
);
2842 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2844 if (ValueListCell
== NULL
)
2846 CellSize
= sizeof(VALUE_LIST_CELL
) +
2847 (3 * sizeof(BLOCK_OFFSET
));
2848 Status
= CmiAllocateCell (RegistryHive
,
2850 (PVOID
) &ValueListCell
,
2853 if (!NT_SUCCESS(Status
))
2855 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2858 KeyCell
->ValueListOffset
= VLBOffset
;
2860 else if (KeyCell
->NumberOfValues
>=
2861 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
)))
2863 CellSize
= sizeof(VALUE_LIST_CELL
) +
2864 ((KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) * sizeof(BLOCK_OFFSET
));
2865 Status
= CmiAllocateCell (RegistryHive
,
2867 (PVOID
) &NewValueListCell
,
2869 if (!NT_SUCCESS(Status
))
2871 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2875 RtlCopyMemory(&NewValueListCell
->ValueOffset
[0],
2876 &ValueListCell
->ValueOffset
[0],
2877 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2878 CmiDestroyCell (RegistryHive
, ValueListCell
, KeyCell
->ValueListOffset
);
2879 KeyCell
->ValueListOffset
= VLBOffset
;
2880 ValueListCell
= NewValueListCell
;
2883 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2884 KeyCell
->NumberOfValues
,
2885 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2886 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
),
2887 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - sizeof(VALUE_LIST_CELL
)) / sizeof(BLOCK_OFFSET
));
2889 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = VBOffset
;
2890 KeyCell
->NumberOfValues
++;
2892 *pValueCell
= NewValueCell
;
2893 *pVBOffset
= VBOffset
;
2895 return STATUS_SUCCESS
;
2900 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2901 IN PKEY_CELL KeyCell
,
2902 IN BLOCK_OFFSET KeyCellOffset
,
2903 IN PUNICODE_STRING ValueName
)
2905 PVALUE_LIST_CELL ValueListCell
;
2906 PVALUE_CELL CurValueCell
;
2909 ValueListCell
= CmiGetCell (RegistryHive
, KeyCell
->ValueListOffset
, NULL
);
2911 if (ValueListCell
== NULL
)
2913 DPRINT("CmiGetBlock() failed\n");
2914 return STATUS_SUCCESS
;
2917 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2919 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2921 CurValueCell
= CmiGetCell (RegistryHive
, ValueListCell
->ValueOffset
[i
], NULL
);
2922 if (CurValueCell
== NULL
)
2924 DPRINT("CmiGetBlock() failed\n");
2925 return STATUS_UNSUCCESSFUL
;
2928 if ((CurValueCell
!= NULL
) &&
2929 CmiComparePackedNames(ValueName
,
2931 CurValueCell
->NameSize
,
2932 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
2934 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->ValueOffset
[i
]);
2936 if ((KeyCell
->NumberOfValues
- 1) < i
)
2938 RtlCopyMemory(&ValueListCell
->ValueOffset
[i
],
2939 &ValueListCell
->ValueOffset
[i
+ 1],
2940 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2944 RtlZeroMemory(&ValueListCell
->ValueOffset
[i
], sizeof(BLOCK_OFFSET
));
2947 KeyCell
->NumberOfValues
-= 1;
2952 if (KeyCell
->NumberOfValues
== 0)
2954 CmiDestroyCell (RegistryHive
,
2956 KeyCell
->ValueListOffset
);
2960 CmiMarkBlockDirty(RegistryHive
,
2961 KeyCell
->ValueListOffset
);
2964 CmiMarkBlockDirty(RegistryHive
,
2967 return STATUS_SUCCESS
;
2972 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive
,
2973 OUT PHASH_TABLE_CELL
*HashBlock
,
2974 OUT BLOCK_OFFSET
*HBOffset
,
2975 IN ULONG SubKeyCount
)
2977 PHASH_TABLE_CELL NewHashBlock
;
2981 Status
= STATUS_SUCCESS
;
2983 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
2984 (SubKeyCount
* sizeof(HASH_RECORD
));
2985 Status
= CmiAllocateCell (RegistryHive
,
2987 (PVOID
*) &NewHashBlock
,
2990 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
2992 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2996 NewHashBlock
->Id
= REG_HASH_TABLE_CELL_ID
;
2997 NewHashBlock
->HashTableSize
= SubKeyCount
;
2998 *HashBlock
= NewHashBlock
;
3006 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
3007 PHASH_TABLE_CELL HashBlock
,
3010 BLOCK_OFFSET KeyOffset
;
3013 if (HashBlock
== NULL
)
3016 if (IsPointerHive(RegistryHive
))
3018 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
3022 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
3023 KeyCell
= CmiGetCell (RegistryHive
, KeyOffset
, NULL
);
3031 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
3032 PHASH_TABLE_CELL HashCell
,
3033 BLOCK_OFFSET HashCellOffset
,
3034 PKEY_CELL NewKeyCell
,
3035 BLOCK_OFFSET NKBOffset
)
3039 for (i
= 0; i
< HashCell
->HashTableSize
; i
++)
3041 if (HashCell
->Table
[i
].KeyOffset
== 0)
3043 HashCell
->Table
[i
].KeyOffset
= NKBOffset
;
3044 HashCell
->Table
[i
].HashValue
= 0;
3045 if (NewKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3047 RtlCopyMemory(&HashCell
->Table
[i
].HashValue
,
3049 min(NewKeyCell
->NameSize
, sizeof(ULONG
)));
3051 CmiMarkBlockDirty(RegistryHive
, HashCellOffset
);
3052 return STATUS_SUCCESS
;
3056 return STATUS_UNSUCCESSFUL
;
3061 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
3062 PHASH_TABLE_CELL HashBlock
,
3063 BLOCK_OFFSET NKBOffset
)
3067 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
3069 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
3071 HashBlock
->Table
[i
].KeyOffset
= 0;
3072 HashBlock
->Table
[i
].HashValue
= 0;
3073 return STATUS_SUCCESS
;
3077 return STATUS_UNSUCCESSFUL
;
3082 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
3083 PVALUE_CELL
*ValueCell
,
3084 BLOCK_OFFSET
*VBOffset
,
3085 IN PUNICODE_STRING ValueName
)
3087 PVALUE_CELL NewValueCell
;
3093 Status
= STATUS_SUCCESS
;
3095 NameSize
= CmiGetPackedNameLength(ValueName
,
3098 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
3100 Status
= CmiAllocateCell (RegistryHive
,
3101 sizeof(VALUE_CELL
) + NameSize
,
3102 (PVOID
*) &NewValueCell
,
3104 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
3106 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3110 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
3111 NewValueCell
->NameSize
= NameSize
;
3114 /* Pack the value name */
3115 for (i
= 0; i
< NameSize
; i
++)
3116 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
3117 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
3121 /* Copy the value name */
3122 RtlCopyMemory(NewValueCell
->Name
,
3125 NewValueCell
->Flags
= 0;
3127 NewValueCell
->DataType
= 0;
3128 NewValueCell
->DataSize
= 0;
3129 NewValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
3130 *ValueCell
= NewValueCell
;
3138 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
3139 PVALUE_CELL ValueCell
,
3140 BLOCK_OFFSET VBOffset
)
3146 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell
, VBOffset
);
3148 VERIFY_VALUE_CELL(ValueCell
);
3150 /* Destroy the data cell */
3151 if (ValueCell
->DataSize
> sizeof(BLOCK_OFFSET
))
3153 pBlock
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, &pBin
);
3156 DPRINT("CmiGetBlock() failed\n");
3157 return STATUS_UNSUCCESSFUL
;
3160 Status
= CmiDestroyCell (RegistryHive
, pBlock
, ValueCell
->DataOffset
);
3161 if (!NT_SUCCESS(Status
))
3166 /* Update time of heap */
3167 if (!IsNoFileHive(RegistryHive
))
3168 NtQuerySystemTime(&pBin
->DateModified
);
3171 /* Destroy the value cell */
3172 Status
= CmiDestroyCell (RegistryHive
, ValueCell
, VBOffset
);
3174 /* Update time of heap */
3175 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, VBOffset
, &pBin
))
3177 NtQuerySystemTime(&pBin
->DateModified
);
3185 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
3187 BLOCK_OFFSET
*NewBlockOffset
)
3189 PCELL_HEADER tmpBlock
;
3190 PHBIN
* tmpBlockList
;
3193 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
3196 return STATUS_INSUFFICIENT_RESOURCES
;
3199 tmpBin
->BlockId
= REG_BIN_ID
;
3200 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
3201 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
3202 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
3203 tmpBin
->Unused1
= 0;
3204 ZwQuerySystemTime(&tmpBin
->DateModified
);
3205 tmpBin
->Unused2
= 0;
3207 /* Increase size of list of blocks */
3208 tmpBlockList
= ExAllocatePool(NonPagedPool
,
3209 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
3210 if (tmpBlockList
== NULL
)
3213 return STATUS_INSUFFICIENT_RESOURCES
;
3216 if (RegistryHive
->BlockListSize
> 0)
3218 RtlCopyMemory (tmpBlockList
,
3219 RegistryHive
->BlockList
,
3220 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
3221 ExFreePool(RegistryHive
->BlockList
);
3224 RegistryHive
->BlockList
= tmpBlockList
;
3225 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
] = tmpBin
;
3226 RegistryHive
->BlockListSize
++;
3228 /* Initialize a free block in this heap : */
3229 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
3230 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
3232 /* Grow bitmap if necessary */
3233 if (IsNoFileHive(RegistryHive
) &&
3234 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
3236 PULONG BitmapBuffer
;
3239 DPRINT("Grow hive bitmap\n");
3241 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3242 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
3243 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
3244 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
3245 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
3247 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
3248 RtlCopyMemory(BitmapBuffer
,
3249 RegistryHive
->DirtyBitMap
.Buffer
,
3250 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
3251 ExFreePool(RegistryHive
->BitmapBuffer
);
3252 RegistryHive
->BitmapBuffer
= BitmapBuffer
;
3253 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
3254 RegistryHive
->BitmapBuffer
,
3258 *NewBlock
= (PVOID
) tmpBlock
;
3261 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
3263 /* Mark new bin dirty */
3264 CmiMarkBinDirty(RegistryHive
,
3265 tmpBin
->BlockOffset
);
3267 return STATUS_SUCCESS
;
3272 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
3275 BLOCK_OFFSET
*CellOffset
)
3277 PCELL_HEADER NewCell
;
3283 Status
= STATUS_SUCCESS
;
3285 /* Round to 16 bytes multiple */
3286 CellSize
= ROUND_UP(CellSize
, 16);
3288 /* Handle volatile hives first */
3289 if (IsPointerHive(RegistryHive
))
3291 NewCell
= ExAllocatePool(NonPagedPool
, CellSize
);
3293 if (NewCell
== NULL
)
3295 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3299 RtlZeroMemory(NewCell
, CellSize
);
3300 NewCell
->CellSize
= -CellSize
;
3303 if (CellOffset
!= NULL
)
3304 *CellOffset
= (BLOCK_OFFSET
) NewCell
;
3309 /* first search in free blocks */
3311 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3313 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
3315 NewCell
= RegistryHive
->FreeList
[i
];
3316 if (CellOffset
!= NULL
)
3317 *CellOffset
= RegistryHive
->FreeListOffset
[i
];
3319 /* Update time of heap */
3320 Temp
= CmiGetCell (RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
3323 DPRINT("CmiGetBlock() failed\n");
3324 return STATUS_UNSUCCESSFUL
;
3329 NtQuerySystemTime(&pBin
->DateModified
);
3330 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
3333 if ((i
+ 1) < RegistryHive
->FreeListSize
)
3335 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
3336 &RegistryHive
->FreeList
[i
+ 1],
3337 sizeof(RegistryHive
->FreeList
[0])
3338 * (RegistryHive
->FreeListSize
- i
- 1));
3339 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
3340 &RegistryHive
->FreeListOffset
[i
+ 1],
3341 sizeof(RegistryHive
->FreeListOffset
[0])
3342 * (RegistryHive
->FreeListSize
- i
- 1));
3344 RegistryHive
->FreeListSize
--;
3349 /* Need to extend hive file : */
3350 if (NewCell
== NULL
)
3353 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewCell
, CellOffset
);
3356 if (NT_SUCCESS(Status
))
3360 /* Split the block in two parts */
3361 if (NewCell
->CellSize
> CellSize
)
3363 NewCell
= (PCELL_HEADER
) ((ULONG_PTR
) NewCell
+ CellSize
);
3364 NewCell
->CellSize
= ((PCELL_HEADER
) (*Cell
))->CellSize
- CellSize
;
3365 CmiAddFree(RegistryHive
,
3367 *CellOffset
+ CellSize
,
3369 CmiMarkBlockDirty(RegistryHive
,
3370 *CellOffset
+ CellSize
);
3372 else if (NewCell
->CellSize
< CellSize
)
3374 return(STATUS_UNSUCCESSFUL
);
3377 RtlZeroMemory(*Cell
, CellSize
);
3378 ((PCELL_HEADER
) (*Cell
))->CellSize
= -CellSize
;
3387 CmiDestroyCell (PREGISTRY_HIVE RegistryHive
,
3389 BLOCK_OFFSET CellOffset
)
3394 Status
= STATUS_SUCCESS
;
3396 if (IsPointerHive(RegistryHive
))
3402 PCELL_HEADER pFree
= Cell
;
3404 if (pFree
->CellSize
< 0)
3405 pFree
->CellSize
= -pFree
->CellSize
;
3407 /* Clear block (except the block size) */
3408 RtlZeroMemory(((char*)pFree
) + sizeof(ULONG
),
3409 pFree
->CellSize
- sizeof(ULONG
));
3411 /* Add block to the list of free blocks */
3412 CmiAddFree(RegistryHive
, Cell
, CellOffset
, TRUE
);
3414 /* Update time of heap */
3415 if (!IsNoFileHive(RegistryHive
) && CmiGetCell (RegistryHive
, CellOffset
,&pBin
))
3416 NtQuerySystemTime(&pBin
->DateModified
);
3418 CmiMarkBlockDirty(RegistryHive
, CellOffset
);
3426 CmiGetCell (PREGISTRY_HIVE RegistryHive
,
3427 BLOCK_OFFSET CellOffset
,
3437 if (CellOffset
== (BLOCK_OFFSET
)-1)
3442 if (IsPointerHive (RegistryHive
))
3444 return (PVOID
)CellOffset
;
3447 if (CellOffset
> RegistryHive
->BlockListSize
* 4096)
3449 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3450 CellOffset
, RegistryHive
->BlockListSize
* 4096);
3454 pBin
= RegistryHive
->BlockList
[CellOffset
/ 4096];
3465 return((PVOID
)((ULONG_PTR
)pBin
+ (CellOffset
- pBin
->BlockOffset
)));
3470 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3471 PCELL_HEADER FreeBlock
,
3472 BLOCK_OFFSET FreeOffset
)
3474 BLOCK_OFFSET BlockOffset
;
3475 BLOCK_OFFSET BinOffset
;
3481 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3482 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3484 CmiGetCell (RegistryHive
,
3487 DPRINT("Bin %p\n", Bin
);
3491 BinOffset
= Bin
->BlockOffset
;
3492 BinSize
= Bin
->BlockSize
;
3493 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3495 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3497 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3498 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3499 if (BlockOffset
> BinOffset
&&
3500 BlockOffset
< BinOffset
+ BinSize
)
3502 DPRINT("Free block: Offset %lx Size %lx\n",
3503 BlockOffset
, BlockSize
);
3505 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3506 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3507 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3509 DPRINT("Merge current block with previous and next block\n");
3511 RegistryHive
->FreeList
[i
]->CellSize
+=
3512 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3514 FreeBlock
->CellSize
= 0;
3515 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3518 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3520 RtlMoveMemory(&RegistryHive
->FreeList
[i
+ 1],
3521 &RegistryHive
->FreeList
[i
+ 2],
3522 sizeof(RegistryHive
->FreeList
[0])
3523 * (RegistryHive
->FreeListSize
- i
- 2));
3524 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3525 &RegistryHive
->FreeListOffset
[i
+ 2],
3526 sizeof(RegistryHive
->FreeListOffset
[0])
3527 * (RegistryHive
->FreeListSize
- i
- 2));
3529 RegistryHive
->FreeListSize
--;
3531 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3535 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3537 DPRINT("Merge current block with previous block\n");
3539 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3540 FreeBlock
->CellSize
= 0;
3542 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3546 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3548 DPRINT("Merge current block with next block\n");
3550 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3551 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3552 RegistryHive
->FreeList
[i
] = FreeBlock
;
3553 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3555 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3567 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3568 PCELL_HEADER FreeBlock
,
3569 BLOCK_OFFSET FreeOffset
,
3570 BOOLEAN MergeFreeBlocks
)
3572 PCELL_HEADER
*tmpList
;
3573 BLOCK_OFFSET
*tmpListOffset
;
3578 assert(RegistryHive
);
3581 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3582 FreeBlock
, FreeOffset
);
3584 /* Merge free blocks */
3585 if (MergeFreeBlocks
== TRUE
)
3587 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3588 return(STATUS_SUCCESS
);
3591 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3593 tmpList
= ExAllocatePool(PagedPool
,
3594 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3595 if (tmpList
== NULL
)
3596 return STATUS_INSUFFICIENT_RESOURCES
;
3598 tmpListOffset
= ExAllocatePool(PagedPool
,
3599 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
3601 if (tmpListOffset
== NULL
)
3603 ExFreePool(tmpList
);
3604 return STATUS_INSUFFICIENT_RESOURCES
;
3607 if (RegistryHive
->FreeListMax
)
3609 RtlMoveMemory(tmpList
,
3610 RegistryHive
->FreeList
,
3611 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3612 RtlMoveMemory(tmpListOffset
,
3613 RegistryHive
->FreeListOffset
,
3614 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
3615 ExFreePool(RegistryHive
->FreeList
);
3616 ExFreePool(RegistryHive
->FreeListOffset
);
3618 RegistryHive
->FreeList
= tmpList
;
3619 RegistryHive
->FreeListOffset
= tmpListOffset
;
3620 RegistryHive
->FreeListMax
+= 32;
3623 /* Add new offset to free list, maintaining list in ascending order */
3624 if ((RegistryHive
->FreeListSize
== 0)
3625 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3627 /* Add to end of list */
3628 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3629 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3631 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3633 /* Add to begin of list */
3634 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3635 &RegistryHive
->FreeList
[0],
3636 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3637 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3638 &RegistryHive
->FreeListOffset
[0],
3639 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3640 RegistryHive
->FreeList
[0] = FreeBlock
;
3641 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3642 RegistryHive
->FreeListSize
++;
3646 /* Search where to insert */
3648 maxInd
= RegistryHive
->FreeListSize
- 1;
3649 while ((maxInd
- minInd
) > 1)
3651 medInd
= (minInd
+ maxInd
) / 2;
3652 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3658 /* Insert before maxInd */
3659 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3660 &RegistryHive
->FreeList
[maxInd
],
3661 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3662 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3663 &RegistryHive
->FreeListOffset
[maxInd
],
3664 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3665 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3666 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3667 RegistryHive
->FreeListSize
++;
3670 return STATUS_SUCCESS
;
3675 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3676 BLOCK_OFFSET BlockOffset
)
3683 if (IsNoFileHive(RegistryHive
))
3686 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3688 BlockNumber
= (ULONG
)BlockOffset
/ 4096;
3690 Cell
= CmiGetCell (RegistryHive
,
3694 CellSize
= Cell
->CellSize
;
3696 CellSize
= -CellSize
;
3698 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, 4096) - ROUND_DOWN(BlockOffset
, 4096)) / 4096;
3700 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3703 (Cell
->CellSize
< 0) ? "used" : "free",
3706 RegistryHive
->HiveDirty
= TRUE
;
3707 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3714 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3715 BLOCK_OFFSET BinOffset
)
3721 if (IsNoFileHive(RegistryHive
))
3724 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3726 BlockNumber
= (ULONG
)BinOffset
/ 4096;
3728 Bin
= RegistryHive
->BlockList
[BlockNumber
];
3730 BlockCount
= Bin
->BlockSize
/ 4096;
3732 DPRINT(" BlockNumber %lu Size %lu BlockCount %lu\n",
3737 RegistryHive
->HiveDirty
= TRUE
;
3738 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3745 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3746 OUT PBOOLEAN Packable
)
3750 if (Packable
!= NULL
)
3753 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3755 if (Name
->Buffer
[i
] & 0xFF00)
3757 if (Packable
!= NULL
)
3759 return Name
->Length
;
3763 return (Name
->Length
/ sizeof(WCHAR
));
3768 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3769 IN PCHAR NameBuffer
,
3770 IN USHORT NameBufferSize
,
3771 IN BOOLEAN NamePacked
)
3776 if (NamePacked
== TRUE
)
3778 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3781 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3783 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3789 if (Name
->Length
!= NameBufferSize
)
3792 UNameBuffer
= (PWCHAR
)NameBuffer
;
3794 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3796 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3806 CmiCopyPackedName(PWCHAR NameBuffer
,
3807 PCHAR PackedNameBuffer
,
3808 ULONG PackedNameSize
)
3812 for (i
= 0; i
< PackedNameSize
; i
++)
3813 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];
3818 CmiCompareHash(PUNICODE_STRING KeyName
,
3823 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3824 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3825 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3826 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3828 return (strncmp(Buffer
, HashString
, 4) == 0);
3833 CmiCompareHashI(PUNICODE_STRING KeyName
,
3838 Buffer
[0] = (KeyName
->Length
>= 2) ? (CHAR
)KeyName
->Buffer
[0] : 0;
3839 Buffer
[1] = (KeyName
->Length
>= 4) ? (CHAR
)KeyName
->Buffer
[1] : 0;
3840 Buffer
[2] = (KeyName
->Length
>= 6) ? (CHAR
)KeyName
->Buffer
[2] : 0;
3841 Buffer
[3] = (KeyName
->Length
>= 8) ? (CHAR
)KeyName
->Buffer
[3] : 0;
3843 return (_strnicmp(Buffer
, HashString
, 4) == 0);
3848 CmiCompareKeyNames(PUNICODE_STRING KeyName
,
3854 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3856 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3858 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3861 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3863 if (KeyName
->Buffer
[i
] != (WCHAR
)KeyCell
->Name
[i
])
3869 if (KeyName
->Length
!= KeyCell
->NameSize
)
3872 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3873 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3875 if (KeyName
->Buffer
[i
] != UnicodeName
[i
])
3885 CmiCompareKeyNamesI(PUNICODE_STRING KeyName
,
3891 DPRINT("Flags: %hx\n", KeyCell
->Flags
);
3893 if (KeyCell
->Flags
& REG_KEY_NAME_PACKED
)
3895 if (KeyName
->Length
!= KeyCell
->NameSize
* sizeof(WCHAR
))
3898 for (i
= 0; i
< KeyCell
->NameSize
; i
++)
3900 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3901 RtlUpcaseUnicodeChar((WCHAR
)KeyCell
->Name
[i
]))
3907 if (KeyName
->Length
!= KeyCell
->NameSize
)
3910 UnicodeName
= (PWCHAR
)KeyCell
->Name
;
3911 for (i
= 0; i
< KeyCell
->NameSize
/ sizeof(WCHAR
); i
++)
3913 if (RtlUpcaseUnicodeChar(KeyName
->Buffer
[i
]) !=
3914 RtlUpcaseUnicodeChar(UnicodeName
[i
]))
3924 CmiCopyKey (PREGISTRY_HIVE DstHive
,
3925 PKEY_CELL DstKeyCell
,
3926 PREGISTRY_HIVE SrcHive
,
3927 PKEY_CELL SrcKeyCell
)
3929 PKEY_CELL NewKeyCell
;
3930 ULONG NewKeyCellSize
;
3931 BLOCK_OFFSET NewKeyCellOffset
;
3932 PHASH_TABLE_CELL NewHashTableCell
;
3933 ULONG NewHashTableSize
;
3934 BLOCK_OFFSET NewHashTableOffset
;
3938 DPRINT ("CmiCopyKey() called\n");
3940 if (DstKeyCell
== NULL
)
3942 /* Allocate and copy key cell */
3943 NewKeyCellSize
= sizeof(KEY_CELL
) + SrcKeyCell
->NameSize
;
3944 Status
= CmiAllocateCell (DstHive
,
3946 (PVOID
) &NewKeyCell
,
3948 if (!NT_SUCCESS(Status
))
3950 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
3953 if (NewKeyCell
== NULL
)
3955 DPRINT1 ("Failed to allocate a key cell\n");
3956 return STATUS_INSUFFICIENT_RESOURCES
;
3959 RtlCopyMemory (NewKeyCell
,
3963 DstHive
->HiveHeader
->RootKeyOffset
= NewKeyCellOffset
;
3965 /* Copy class name */
3966 if (SrcKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
3968 PDATA_CELL SrcClassNameCell
;
3969 PDATA_CELL NewClassNameCell
;
3970 BLOCK_OFFSET NewClassNameOffset
;
3972 SrcClassNameCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ClassNameOffset
, NULL
),
3974 NewKeyCell
->ClassSize
= SrcKeyCell
->ClassSize
;
3975 Status
= CmiAllocateCell (DstHive
,
3976 sizeof(CELL_HEADER
) + NewKeyCell
->ClassSize
,
3977 (PVOID
)&NewClassNameCell
,
3978 &NewClassNameOffset
);
3979 if (!NT_SUCCESS(Status
))
3981 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
3985 RtlCopyMemory (NewClassNameCell
,
3987 NewKeyCell
->ClassSize
);
3988 NewKeyCell
->ClassNameOffset
= NewClassNameOffset
;
3993 NewKeyCell
= DstKeyCell
;
3996 /* Allocate hash table */
3997 if (SrcKeyCell
->NumberOfSubKeys
> 0)
3999 NewHashTableSize
= ROUND_UP(SrcKeyCell
->NumberOfSubKeys
+ 1, 4) - 1;
4000 Status
= CmiAllocateHashTableCell (DstHive
,
4002 &NewHashTableOffset
,
4004 if (!NT_SUCCESS(Status
))
4006 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status
);
4009 NewKeyCell
->HashTableOffset
= NewHashTableOffset
;
4012 /* Allocate and copy value list and values */
4013 if (SrcKeyCell
->NumberOfValues
!= 0)
4015 PVALUE_LIST_CELL NewValueListCell
;
4016 PVALUE_LIST_CELL SrcValueListCell
;
4017 PVALUE_CELL NewValueCell
;
4018 PVALUE_CELL SrcValueCell
;
4019 PDATA_CELL SrcValueDataCell
;
4020 PDATA_CELL NewValueDataCell
;
4021 BLOCK_OFFSET ValueCellOffset
;
4022 BLOCK_OFFSET ValueDataCellOffset
;
4023 ULONG NewValueListCellSize
;
4024 ULONG NewValueCellSize
;
4027 NewValueListCellSize
=
4028 ROUND_UP(SrcKeyCell
->NumberOfValues
, 4) * sizeof(BLOCK_OFFSET
);
4029 Status
= CmiAllocateCell (DstHive
,
4030 NewValueListCellSize
,
4031 (PVOID
)&NewValueListCell
,
4032 &NewKeyCell
->ValueListOffset
);
4033 if (!NT_SUCCESS(Status
))
4035 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4039 RtlZeroMemory (NewValueListCell
,
4040 NewValueListCellSize
);
4043 SrcValueListCell
= CmiGetCell (SrcHive
, SrcKeyCell
->ValueListOffset
, NULL
);
4044 for (i
= 0; i
< SrcKeyCell
->NumberOfValues
; i
++)
4046 /* Copy value cell */
4047 SrcValueCell
= CmiGetCell (SrcHive
, SrcValueListCell
->ValueOffset
[i
], NULL
);
4049 NewValueCellSize
= sizeof(VALUE_CELL
) + SrcValueCell
->NameSize
;
4050 Status
= CmiAllocateCell (DstHive
,
4052 (PVOID
*) &NewValueCell
,
4054 if (!NT_SUCCESS(Status
))
4056 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4060 NewValueListCell
->ValueOffset
[i
] = ValueCellOffset
;
4061 RtlCopyMemory (NewValueCell
,
4065 /* Copy value data cell */
4066 if (SrcValueCell
->DataSize
> (LONG
) sizeof(PVOID
))
4068 SrcValueDataCell
= CmiGetCell (SrcHive
, SrcValueCell
->DataOffset
, NULL
);
4070 Status
= CmiAllocateCell (DstHive
,
4071 sizeof(CELL_HEADER
) + SrcValueCell
->DataSize
,
4072 (PVOID
*) &NewValueDataCell
,
4073 &ValueDataCellOffset
);
4074 if (!NT_SUCCESS(Status
))
4076 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4079 RtlCopyMemory (NewValueDataCell
,
4081 SrcValueCell
->DataSize
);
4082 NewValueCell
->DataOffset
= ValueDataCellOffset
;
4088 if (SrcKeyCell
->NumberOfSubKeys
> 0)
4090 PHASH_TABLE_CELL SrcHashTableCell
;
4091 PKEY_CELL SrcSubKeyCell
;
4092 PKEY_CELL NewSubKeyCell
;
4093 ULONG NewSubKeyCellSize
;
4094 BLOCK_OFFSET NewSubKeyCellOffset
;
4095 PHASH_RECORD SrcHashRecord
;
4097 SrcHashTableCell
= CmiGetCell (SrcHive
,
4098 SrcKeyCell
->HashTableOffset
,
4101 for (i
= 0; i
< SrcKeyCell
->NumberOfSubKeys
; i
++)
4103 SrcHashRecord
= &SrcHashTableCell
->Table
[i
];
4104 SrcSubKeyCell
= CmiGetCell (SrcHive
, SrcHashRecord
->KeyOffset
, NULL
);
4106 /* Allocate and copy key cell */
4107 NewSubKeyCellSize
= sizeof(KEY_CELL
) + SrcSubKeyCell
->NameSize
;
4108 Status
= CmiAllocateCell (DstHive
,
4110 (PVOID
)&NewSubKeyCell
,
4111 &NewSubKeyCellOffset
);
4112 if (!NT_SUCCESS(Status
))
4114 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4117 if (NewKeyCell
== NULL
)
4119 DPRINT1 ("Failed to allocate a sub key cell\n");
4120 return STATUS_INSUFFICIENT_RESOURCES
;
4123 NewHashTableCell
->Table
[i
].KeyOffset
= NewSubKeyCellOffset
;
4124 NewHashTableCell
->Table
[i
].HashValue
= SrcHashRecord
->HashValue
;
4126 RtlCopyMemory (NewSubKeyCell
,
4130 /* Copy class name */
4131 if (SrcSubKeyCell
->ClassNameOffset
!= (BLOCK_OFFSET
) -1)
4133 PDATA_CELL SrcClassNameCell
;
4134 PDATA_CELL NewClassNameCell
;
4135 BLOCK_OFFSET NewClassNameOffset
;
4137 SrcClassNameCell
= CmiGetCell (SrcHive
,
4138 SrcSubKeyCell
->ClassNameOffset
,
4141 NewSubKeyCell
->ClassSize
= SrcSubKeyCell
->ClassSize
;
4142 Status
= CmiAllocateCell (DstHive
,
4143 sizeof(CELL_HEADER
) + NewSubKeyCell
->ClassSize
,
4144 (PVOID
)&NewClassNameCell
,
4145 &NewClassNameOffset
);
4146 if (!NT_SUCCESS(Status
))
4148 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4152 NewSubKeyCell
->ClassNameOffset
= NewClassNameOffset
;
4153 RtlCopyMemory (NewClassNameCell
,
4155 NewSubKeyCell
->ClassSize
);
4158 /* Copy subkey data and subkeys */
4159 Status
= CmiCopyKey (DstHive
,
4163 if (!NT_SUCCESS(Status
))
4165 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status
);
4171 return STATUS_SUCCESS
;
4176 CmiSaveTempHive (PREGISTRY_HIVE Hive
,
4179 IO_STATUS_BLOCK IoStatusBlock
;
4180 LARGE_INTEGER FileOffset
;
4185 DPRINT ("CmiSaveTempHive() called\n");
4187 Hive
->HiveHeader
->Checksum
= CmiCalcChecksum ((PULONG
)Hive
->HiveHeader
);
4189 /* Write hive block */
4190 #if defined(__GNUC__)
4191 FileOffset
.QuadPart
= 0ULL;
4193 FileOffset
.QuadPart
= 0;
4195 Status
= NtWriteFile (FileHandle
,
4201 sizeof(HIVE_HEADER
),
4204 if (!NT_SUCCESS(Status
))
4206 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4210 DPRINT ("Saving %lu blocks\n", Hive
->BlockListSize
);
4211 for (BlockIndex
= 0; BlockIndex
< Hive
->BlockListSize
; BlockIndex
++)
4213 BlockPtr
= Hive
->BlockList
[BlockIndex
];
4214 DPRINT ("BlockPtr %p\n", BlockPtr
);
4216 #if defined(__GNUC__)
4217 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096ULL;
4219 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096;
4221 DPRINT ("File offset %I64x\n", FileOffset
.QuadPart
);
4223 /* Write hive block */
4224 Status
= NtWriteFile (FileHandle
,
4233 if (!NT_SUCCESS(Status
))
4235 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status
);
4240 Status
= NtFlushBuffersFile (FileHandle
,
4242 if (!NT_SUCCESS(Status
))
4244 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
4247 DPRINT ("CmiSaveTempHive() done\n");