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 <ddk/ntddk.h>
13 #include <ddk/ntifs.h>
15 #include <internal/ob.h>
18 #include <internal/pool.h>
19 #include <internal/registry.h>
20 #include <reactos/bugcodes.h>
23 #include <internal/debug.h>
28 /* uncomment to enable hive checks (incomplete and probably buggy) */
31 /* LOCAL MACROS *************************************************************/
33 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
34 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
36 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
38 BOOLEAN CmiDoVerify
= FALSE
;
41 CmiCalcChecksum(PULONG Buffer
);
43 /* FUNCTIONS ****************************************************************/
46 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header
)
49 RtlZeroMemory(Header
, sizeof(HIVE_HEADER
));
50 Header
->BlockId
= REG_HIVE_ID
;
51 Header
->UpdateCounter1
= 0;
52 Header
->UpdateCounter2
= 0;
53 Header
->DateModified
.dwLowDateTime
= 0;
54 Header
->DateModified
.dwHighDateTime
= 0;
60 Header
->RootKeyCell
= 0;
61 Header
->BlockSize
= REG_BLOCK_SIZE
;
68 CmiCreateDefaultBinCell(PHBIN BinCell
)
71 RtlZeroMemory(BinCell
, sizeof(HBIN
));
72 BinCell
->BlockId
= REG_BIN_ID
;
73 BinCell
->DateModified
.dwLowDateTime
= 0;
74 BinCell
->DateModified
.dwHighDateTime
= 0;
75 BinCell
->BlockSize
= REG_BLOCK_SIZE
;
80 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
)
83 RtlZeroMemory(RootKeyCell
, sizeof(KEY_CELL
));
85 RootKeyCell
->CellSize
= -(LONG
)sizeof(KEY_CELL
);
87 RootKeyCell
->CellSize
= -sizeof(KEY_CELL
);
89 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
90 RootKeyCell
->Type
= REG_ROOT_KEY_CELL_TYPE
;
91 NtQuerySystemTime((PTIME
) &RootKeyCell
->LastWriteTime
);
92 RootKeyCell
->ParentKeyOffset
= 0;
93 RootKeyCell
->NumberOfSubKeys
= 0;
94 RootKeyCell
->HashTableOffset
= -1;
95 RootKeyCell
->NumberOfValues
= 0;
96 RootKeyCell
->ValuesOffset
= -1;
97 RootKeyCell
->SecurityKeyOffset
= 0;
98 RootKeyCell
->ClassNameOffset
= -1;
99 RootKeyCell
->NameSize
= 0;
100 RootKeyCell
->ClassSize
= 0;
105 CmiVerifyBinCell(PHBIN BinCell
)
112 if (BinCell
->BlockId
!= REG_BIN_ID
)
114 DbgPrint("BlockId is %.08x (should be %.08x)\n",
115 BinCell
->BlockId
, REG_BIN_ID
);
116 assert(BinCell
->BlockId
== REG_BIN_ID
);
119 //BinCell->DateModified.dwLowDateTime
121 //BinCell->DateModified.dwHighDateTime
124 if (BinCell
->BlockSize
!= REG_BLOCK_SIZE
)
126 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
127 BinCell
->BlockSize
, REG_BLOCK_SIZE
);
128 assert(BinCell
->BlockSize
== REG_BLOCK_SIZE
);
136 CmiVerifyKeyCell(PKEY_CELL KeyCell
)
143 if (KeyCell
->CellSize
== 0)
145 DbgPrint("CellSize is %d (must not be 0)\n",
147 assert(KeyCell
->CellSize
!= 0);
150 if (KeyCell
->Id
!= REG_KEY_CELL_ID
)
152 DbgPrint("Id is %.08x (should be %.08x)\n",
153 KeyCell
->Id
, REG_KEY_CELL_ID
);
154 assert(KeyCell
->Id
== REG_KEY_CELL_ID
);
157 if ((KeyCell
->Type
!= REG_KEY_CELL_TYPE
)
158 && (KeyCell
->Type
!= REG_ROOT_KEY_CELL_TYPE
))
160 DbgPrint("Type is %.08x (should be %.08x or %.08x)\n",
161 KeyCell
->Type
, REG_KEY_CELL_TYPE
, REG_ROOT_KEY_CELL_TYPE
);
165 //KeyCell->LastWriteTime;
167 if (KeyCell
->ParentKeyOffset
< 0)
169 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
170 KeyCell
->ParentKeyOffset
);
171 assert(KeyCell
->ParentKeyOffset
>= 0);
174 if (KeyCell
->NumberOfSubKeys
< 0)
176 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
177 KeyCell
->NumberOfSubKeys
);
178 assert(KeyCell
->NumberOfSubKeys
>= 0);
181 //KeyCell->HashTableOffset;
183 if (KeyCell
->NumberOfValues
< 0)
185 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
186 KeyCell
->NumberOfValues
);
187 assert(KeyCell
->NumberOfValues
>= 0);
190 //KeyCell->ValuesOffset = -1;
192 if (KeyCell
->SecurityKeyOffset
< 0)
194 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
195 KeyCell
->SecurityKeyOffset
);
196 assert(KeyCell
->SecurityKeyOffset
>= 0);
199 //KeyCell->ClassNameOffset = -1;
210 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell
)
215 CmiVerifyKeyCell(RootKeyCell
);
217 if (RootKeyCell
->Type
!= REG_ROOT_KEY_CELL_TYPE
)
219 DbgPrint("Type is %.08x (should be %.08x)\n",
220 RootKeyCell
->Type
, REG_ROOT_KEY_CELL_TYPE
);
221 assert(RootKeyCell
->Type
== REG_ROOT_KEY_CELL_TYPE
);
229 CmiVerifyValueCell(PVALUE_CELL ValueCell
)
236 if (ValueCell
->CellSize
== 0)
238 DbgPrint("CellSize is %d (must not be 0)\n",
239 ValueCell
->CellSize
);
240 assert(ValueCell
->CellSize
!= 0);
243 if (ValueCell
->Id
!= REG_VALUE_CELL_ID
)
245 DbgPrint("Id is %.08x (should be %.08x)\n",
246 ValueCell
->Id
, REG_VALUE_CELL_ID
);
247 assert(ValueCell
->Id
== REG_VALUE_CELL_ID
);
250 //ValueCell->NameSize;
251 //ValueCell->LONG DataSize;
252 //ValueCell->DataOffset;
253 //ValueCell->ULONG DataType;
254 //ValueCell->USHORT Flags;
255 //ValueCell->USHORT Unused1;
256 //ValueCell->UCHAR Name[0];
262 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell
)
267 if (ValueListCell
->CellSize
== 0)
269 DbgPrint("CellSize is %d (must not be 0)\n",
270 ValueListCell
->CellSize
);
271 assert(ValueListCell
->CellSize
!= 0);
279 CmiVerifyKeyObject(PKEY_OBJECT KeyObject
)
284 if (KeyObject
->RegistryHive
== NULL
)
286 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
287 KeyObject
->RegistryHive
);
288 assert(KeyObject
->RegistryHive
!= NULL
);
291 if (KeyObject
->KeyCell
== NULL
)
293 DbgPrint("KeyCell is NULL (must not be NULL)\n",
295 assert(KeyObject
->KeyCell
!= NULL
);
298 if (KeyObject
->ParentKey
== NULL
)
300 DbgPrint("ParentKey is NULL (must not be NULL)\n",
301 KeyObject
->ParentKey
);
302 assert(KeyObject
->ParentKey
!= NULL
);
310 CmiVerifyHiveHeader(PHIVE_HEADER Header
)
315 if (Header
->BlockId
!= REG_HIVE_ID
)
317 DbgPrint("BlockId is %.08x (must be %.08x)\n",
320 assert(Header
->BlockId
== REG_HIVE_ID
);
323 if (Header
->Unused3
!= 1)
325 DbgPrint("Unused3 is %.08x (must be 1)\n",
327 assert(Header
->Unused3
== 1);
330 if (Header
->Unused4
!= 3)
332 DbgPrint("Unused4 is %.08x (must be 3)\n",
334 assert(Header
->Unused4
== 3);
337 if (Header
->Unused5
!= 0)
339 DbgPrint("Unused5 is %.08x (must be 0)\n",
341 assert(Header
->Unused5
== 0);
344 if (Header
->Unused6
!= 1)
346 DbgPrint("Unused6 is %.08x (must be 1)\n",
348 assert(Header
->Unused6
== 1);
351 if (Header
->Unused7
!= 1)
353 DbgPrint("Unused7 is %.08x (must be 1)\n",
355 assert(Header
->Unused7
== 1);
363 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive
)
368 CmiVerifyHiveHeader(RegistryHive
->HiveHeader
);
375 CmiPopulateHive(HANDLE FileHandle
)
377 IO_STATUS_BLOCK IoStatusBlock
;
378 LARGE_INTEGER FileOffset
;
379 PCELL_HEADER FreeCell
;
385 tBuf
= (PCHAR
) ExAllocatePool(NonPagedPool
, REG_BLOCK_SIZE
);
387 return STATUS_INSUFFICIENT_RESOURCES
;
389 BinCell
= (PHBIN
) tBuf
;
390 FreeCell
= (PCELL_HEADER
) (tBuf
+ REG_HBIN_DATA_OFFSET
);
392 CmiCreateDefaultBinCell(BinCell
);
394 // The whole block is free
395 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
397 // Add free blocks so we don't need to expand
398 // the file for a while
399 for (i
= 1; i
< 50; i
++)
401 // Block offset of this bin
402 BinCell
->BlockOffset
= i
* REG_BLOCK_SIZE
;
404 FileOffset
.u
.HighPart
= 0;
405 FileOffset
.u
.LowPart
= (i
+ 1) * REG_BLOCK_SIZE
;
407 Status
= NtWriteFile(FileHandle
,
416 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
417 if (!NT_SUCCESS(Status
))
431 CmiCreateNewRegFile(HANDLE FileHandle
)
433 IO_STATUS_BLOCK IoStatusBlock
;
434 PCELL_HEADER FreeCell
;
435 PHIVE_HEADER HiveHeader
;
436 PKEY_CELL RootKeyCell
;
441 Buffer
= (PCHAR
) ExAllocatePool(NonPagedPool
, 2 * REG_BLOCK_SIZE
);
443 return STATUS_INSUFFICIENT_RESOURCES
;
445 HiveHeader
= (PHIVE_HEADER
)Buffer
;
446 BinCell
= (PHBIN
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
);
447 RootKeyCell
= (PKEY_CELL
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
);
448 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
450 CmiCreateDefaultHiveHeader(HiveHeader
);
451 CmiCreateDefaultBinCell(BinCell
);
452 CmiCreateDefaultRootKeyCell(RootKeyCell
);
455 BinCell
->BlockOffset
= 0;
457 /* Offset to root key block */
458 HiveHeader
->RootKeyCell
= REG_HBIN_DATA_OFFSET
;
460 /* The rest of the block is free */
461 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
463 Status
= NtWriteFile(FileHandle
,
475 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
477 if (!NT_SUCCESS(Status
))
483 if (NT_SUCCESS(Status
))
485 CmiPopulateHive(FileHandle
);
489 Status
= NtFlushBuffersFile(FileHandle
,
498 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive
)
500 OBJECT_ATTRIBUTES ObjectAttributes
;
501 FILE_STANDARD_INFORMATION fsi
;
502 IO_STATUS_BLOCK IoStatusBlock
;
503 HANDLE HiveHandle
= INVALID_HANDLE_VALUE
;
504 HANDLE LogHandle
= INVALID_HANDLE_VALUE
;
505 PHIVE_HEADER HiveHeader
= NULL
;
506 PHIVE_HEADER LogHeader
= NULL
;
507 LARGE_INTEGER FileOffset
;
511 RTL_BITMAP BlockBitMap
;
514 DPRINT("CmiCheckAndFixHive() called\n");
516 /* Try to open the hive file */
517 InitializeObjectAttributes(&ObjectAttributes
,
518 &RegistryHive
->HiveFileName
,
523 Status
= NtCreateFile(&HiveHandle
,
524 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
528 FILE_ATTRIBUTE_NORMAL
,
531 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
534 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
536 return(STATUS_SUCCESS
);
538 if (!NT_SUCCESS(Status
))
540 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
544 /* Try to open the log file */
545 InitializeObjectAttributes(&ObjectAttributes
,
546 &RegistryHive
->LogFileName
,
551 Status
= NtCreateFile(&LogHandle
,
552 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
556 FILE_ATTRIBUTE_NORMAL
,
559 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
562 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
564 LogHandle
= INVALID_HANDLE_VALUE
;
566 else if (!NT_SUCCESS(Status
))
568 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
573 /* Allocate hive header */
574 HiveHeader
= ExAllocatePool(PagedPool
,
575 sizeof(HIVE_HEADER
));
576 if (HiveHeader
== NULL
)
578 DPRINT("ExAllocatePool() failed\n");
579 Status
= STATUS_INSUFFICIENT_RESOURCES
;
583 /* Read hive base block */
584 FileOffset
.QuadPart
= 0ULL;
585 Status
= NtReadFile(HiveHandle
,
594 if (!NT_SUCCESS(Status
))
596 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
600 if (LogHandle
== INVALID_HANDLE_VALUE
)
602 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
603 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
605 /* There is no way to fix the hive without log file - BSOD! */
606 DPRINT("Hive header inconsistent and no log file available!\n");
607 KeBugCheck(CONFIG_LIST_FAILED
);
610 Status
= STATUS_SUCCESS
;
615 /* Allocate hive header */
616 LogHeader
= ExAllocatePool(PagedPool
,
617 sizeof(HIVE_HEADER
));
618 if (LogHeader
== NULL
)
620 DPRINT("ExAllocatePool() failed\n");
621 Status
= STATUS_INSUFFICIENT_RESOURCES
;
625 /* Read log file header */
626 FileOffset
.QuadPart
= 0ULL;
627 Status
= NtReadFile(LogHandle
,
636 if (!NT_SUCCESS(Status
))
638 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
642 /* Check log file header integrity */
643 if (LogHeader
->Checksum
!= CmiCalcChecksum((PULONG
)LogHeader
) ||
644 LogHeader
->UpdateCounter1
!= LogHeader
->UpdateCounter2
)
646 if (HiveHeader
->Checksum
!= CmiCalcChecksum((PULONG
)HiveHeader
) ||
647 HiveHeader
->UpdateCounter1
!= HiveHeader
->UpdateCounter2
)
649 DPRINT("Hive file and log file are inconsistent!\n");
650 KeBugCheck(CONFIG_LIST_FAILED
);
653 /* Log file damaged but hive is okay */
654 Status
= STATUS_SUCCESS
;
658 if (HiveHeader
->UpdateCounter1
== HiveHeader
->UpdateCounter2
&&
659 HiveHeader
->UpdateCounter1
== LogHeader
->UpdateCounter1
)
661 /* Hive and log file are up-to-date */
662 Status
= STATUS_SUCCESS
;
667 * Hive needs an update!
671 Status
= NtQueryInformationFile(LogHandle
,
675 FileStandardInformation
);
676 if (!NT_SUCCESS(Status
))
678 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
681 FileSize
= fsi
.EndOfFile
.u
.LowPart
;
683 /* Calculate bitmap and block size */
684 BitmapSize
= ROUND_UP((FileSize
/ 4096) - 1, sizeof(ULONG
) * 8) / 8;
685 BufferSize
= sizeof(HIVE_HEADER
) +
688 BufferSize
= ROUND_UP(BufferSize
, 4096);
690 /* Reallocate log header block */
691 ExFreePool(LogHeader
);
692 LogHeader
= ExAllocatePool(PagedPool
,
694 if (LogHeader
== NULL
)
696 DPRINT("ExAllocatePool() failed\n");
697 Status
= STATUS_INSUFFICIENT_RESOURCES
;
701 /* Read log file header */
702 FileOffset
.QuadPart
= 0ULL;
703 Status
= NtReadFile(LogHandle
,
712 if (!NT_SUCCESS(Status
))
714 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
718 /* Initialize bitmap */
719 RtlInitializeBitMap(&BlockBitMap
,
720 (PVOID
)((ULONG
)LogHeader
+ 4096 + sizeof(ULONG
)),
723 /* FIXME: Update dirty blocks */
726 /* FIXME: Update hive header */
729 Status
= STATUS_SUCCESS
;
733 /* Clean up the mess */
735 if (HiveHeader
!= NULL
)
736 ExFreePool(HiveHeader
);
738 if (LogHeader
!= NULL
)
739 ExFreePool(LogHeader
);
741 if (LogHandle
!= INVALID_HANDLE_VALUE
)
752 CmiInitNonVolatileRegistryHive(PREGISTRY_HIVE RegistryHive
,
756 OBJECT_ATTRIBUTES ObjectAttributes
;
757 FILE_STANDARD_INFORMATION fsi
;
758 PCELL_HEADER FreeBlock
;
759 LARGE_INTEGER FileOffset
;
760 BLOCK_OFFSET BlockOffset
;
761 ULONG CreateDisposition
;
762 IO_STATUS_BLOCK IoSB
;
771 DPRINT1("CmiInitNonVolatileRegistryHive(%p, %S, %d) - Entered.\n", RegistryHive
, Filename
, CreateNew
);
773 /* Duplicate Filename */
774 Status
= RtlCreateUnicodeString(&RegistryHive
->HiveFileName
,
776 if (!NT_SUCCESS(Status
))
778 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status
);
782 /* Create log file name */
783 RegistryHive
->LogFileName
.Length
= (wcslen(Filename
) + 4) * sizeof(WCHAR
);
784 RegistryHive
->LogFileName
.MaximumLength
= RegistryHive
->LogFileName
.Length
+ sizeof(WCHAR
);
785 RegistryHive
->LogFileName
.Buffer
= ExAllocatePool(NonPagedPool
,
786 RegistryHive
->LogFileName
.MaximumLength
);
787 if (RegistryHive
->LogFileName
.Buffer
== NULL
)
789 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
790 DPRINT("ExAllocatePool() failed\n");
791 return(STATUS_INSUFFICIENT_RESOURCES
);
793 wcscpy(RegistryHive
->LogFileName
.Buffer
,
795 wcscat(RegistryHive
->LogFileName
.Buffer
,
799 /* Check and eventually fix a hive */
800 Status
= CmiCheckAndFixHive(RegistryHive
);
801 if (!NT_SUCCESS(Status
))
803 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
804 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
805 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status
);
810 InitializeObjectAttributes(&ObjectAttributes
,
811 &RegistryHive
->HiveFileName
,
818 * This is a workaround to prevent a BSOD because of missing registry hives.
819 * The workaround is only useful for developers. An implementation for the
820 * ordinary user must bail out on missing registry hives because they are
821 * essential to booting and configuring the OS.
824 if (CreateNew
== TRUE
)
825 CreateDisposition
= FILE_OPEN_IF
;
827 CreateDisposition
= FILE_OPEN
;
829 CreateDisposition
= FILE_OPEN_IF
;
831 Status
= NtCreateFile(&FileHandle
,
836 FILE_ATTRIBUTE_NORMAL
,
839 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
842 if (!NT_SUCCESS(Status
))
844 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
845 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
846 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
850 /* Note: Another workaround! See the note above! */
852 if ((CreateNew
) && (IoSB
.Information
== FILE_CREATED
))
854 if (IoSB
.Information
!= FILE_OPENED
)
856 Status
= CmiCreateNewRegFile(FileHandle
);
857 if (!NT_SUCCESS(Status
))
859 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status
);
861 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
862 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
867 /* Read hive header */
868 FileOffset
.u
.HighPart
= 0;
869 FileOffset
.u
.LowPart
= 0;
870 DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle
, sizeof(HIVE_HEADER
), RegistryHive
->HiveHeader
);
871 Status
= NtReadFile(FileHandle
,
876 RegistryHive
->HiveHeader
,
880 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
881 if (!NT_SUCCESS(Status
))
883 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
885 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
886 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
890 /* Read update counter */
891 RegistryHive
->UpdateCounter
= RegistryHive
->HiveHeader
->UpdateCounter1
;
893 Status
= NtQueryInformationFile(FileHandle
,
897 FileStandardInformation
);
898 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
899 if (!NT_SUCCESS(Status
))
901 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
903 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
904 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
908 RegistryHive
->FileSize
= fsi
.EndOfFile
.u
.LowPart
;
910 // assert(RegistryHive->FileSize);
911 if (RegistryHive
->FileSize
== 0)
913 DPRINT("CmiInitPermanentRegistryHive() - Failed, zero length hive file.\n");
915 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
916 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
917 return STATUS_INSUFFICIENT_RESOURCES
;
920 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ 4096) - 1;
922 DPRINT("Space needed for block list describing hive: 0x%x\n",
923 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
925 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
926 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
928 if (RegistryHive
->BlockList
== NULL
)
930 ExFreePool(RegistryHive
->BlockList
);
932 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
933 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
934 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 6.\n");
935 return STATUS_INSUFFICIENT_RESOURCES
;
938 RegistryHive
->BlockList
[0] = ExAllocatePool(PagedPool
,
939 RegistryHive
->FileSize
- 4096);
941 RtlZeroMemory(RegistryHive
->BlockList
[0], RegistryHive
->FileSize
- 4096);
944 if (RegistryHive
->BlockList
[0] == NULL
)
946 ExFreePool(RegistryHive
->BlockList
);
948 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
949 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
950 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 8.\n");
951 return STATUS_INSUFFICIENT_RESOURCES
;
954 FileOffset
.u
.HighPart
= 0;
955 FileOffset
.u
.LowPart
= 4096;
957 DPRINT(" Attempting to NtReadFile(%d) for %d bytes into %p\n",
958 FileHandle
, RegistryHive
->FileSize
- 4096, (PVOID
)RegistryHive
->BlockList
[0]);
959 Status
= NtReadFile(FileHandle
,
964 (PVOID
) RegistryHive
->BlockList
[0],
965 RegistryHive
->FileSize
- 4096,
969 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
973 RegistryHive
->FreeListSize
= 0;
974 RegistryHive
->FreeListMax
= 0;
975 RegistryHive
->FreeList
= NULL
;
978 for (i
= 0; i
< RegistryHive
->BlockListSize
; i
++)
980 RegistryHive
->BlockList
[i
] = (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[0]) + BlockOffset
);
981 tmpBin
= (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[i
]));
982 if (tmpBin
->BlockId
!= REG_BIN_ID
)
984 DPRINT("Bad BlockId %x, offset %x\n", tmpBin
->BlockId
, BlockOffset
);
986 return STATUS_INSUFFICIENT_RESOURCES
;
989 assertmsg((tmpBin
->BlockSize
% 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin
->BlockSize
));
991 if (tmpBin
->BlockSize
> 4096)
993 for (j
= 1; j
< tmpBin
->BlockSize
/ 4096; j
++)
995 RegistryHive
->BlockList
[i
+ j
] = RegistryHive
->BlockList
[i
];
1000 /* Search free blocks and add to list */
1001 FreeOffset
= REG_HBIN_DATA_OFFSET
;
1002 while (FreeOffset
< tmpBin
->BlockSize
)
1004 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) RegistryHive
->BlockList
[i
] + FreeOffset
);
1005 if (FreeBlock
->CellSize
> 0)
1007 Status
= CmiAddFree(RegistryHive
,
1009 RegistryHive
->BlockList
[i
]->BlockOffset
+ FreeOffset
,
1012 if (!NT_SUCCESS(Status
))
1018 FreeOffset
+= FreeBlock
->CellSize
;
1022 FreeOffset
-= FreeBlock
->CellSize
;
1025 BlockOffset
+= tmpBin
->BlockSize
;
1029 * Create block bitmap and clear all bits
1031 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
1032 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1033 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
1034 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
1036 /* Allocate bitmap */
1037 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
1039 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
1043 /* Initialize bitmap */
1044 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
1045 RegistryHive
->HiveDirty
= FALSE
;
1047 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S, %d) - Finished.\n",
1048 RegistryHive
, Filename
, CreateNew
);
1050 return(STATUS_SUCCESS
);
1055 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive
)
1057 PKEY_CELL RootKeyCell
;
1059 RegistryHive
->Flags
|= HIVE_VOLATILE
;
1061 CmiCreateDefaultHiveHeader(RegistryHive
->HiveHeader
);
1063 RootKeyCell
= (PKEY_CELL
) ExAllocatePool(NonPagedPool
, sizeof(KEY_CELL
));
1065 if (RootKeyCell
== NULL
)
1066 return STATUS_INSUFFICIENT_RESOURCES
;
1068 CmiCreateDefaultRootKeyCell(RootKeyCell
);
1070 RegistryHive
->HiveHeader
->RootKeyCell
= (BLOCK_OFFSET
) RootKeyCell
;
1072 return STATUS_SUCCESS
;
1077 CmiCreateRegistryHive(PWSTR Filename
,
1078 PREGISTRY_HIVE
*RegistryHive
,
1081 PREGISTRY_HIVE Hive
;
1084 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename
);
1086 *RegistryHive
= NULL
;
1088 Hive
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_HIVE
));
1090 return(STATUS_INSUFFICIENT_RESOURCES
);
1092 DPRINT("Hive %x\n", Hive
);
1094 RtlZeroMemory(Hive
, sizeof(REGISTRY_HIVE
));
1096 Hive
->HiveHeader
= (PHIVE_HEADER
)
1097 ExAllocatePool(NonPagedPool
, sizeof(HIVE_HEADER
));
1099 if (Hive
->HiveHeader
== NULL
)
1102 return(STATUS_INSUFFICIENT_RESOURCES
);
1105 if (Filename
!= NULL
)
1107 Status
= CmiInitNonVolatileRegistryHive(Hive
, Filename
, CreateNew
);
1111 Status
= CmiInitVolatileRegistryHive(Hive
);
1114 if (!NT_SUCCESS(Status
))
1116 ExFreePool(Hive
->HiveHeader
);
1121 ExInitializeResourceLite(&Hive
->HiveResource
);
1123 /* Acquire hive list lock exclusively */
1124 ExAcquireResourceExclusiveLite(&CmiHiveListLock
, TRUE
);
1126 /* Add the new hive to the hive list */
1127 InsertHeadList(&CmiHiveListHead
, &Hive
->HiveList
);
1129 /* Release hive list lock */
1130 ExReleaseResourceLite(&CmiHiveListLock
);
1132 VERIFY_REGISTRY_HIVE(Hive
);
1134 *RegistryHive
= Hive
;
1136 DPRINT("CmiCreateRegistryHive(Filename %S) - Finished.\n", Filename
);
1138 return(STATUS_SUCCESS
);
1143 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
1145 /* Acquire hive list lock exclusively */
1146 ExAcquireResourceExclusiveLite(&CmiHiveListLock
, TRUE
);
1148 /* Remove hive from hive list */
1149 RemoveEntryList(&RegistryHive
->HiveList
);
1151 /* Release hive list lock */
1152 ExReleaseResourceLite(&CmiHiveListLock
);
1155 /* FIXME: Remove attached keys and values */
1158 /* Release hive header */
1159 ExFreePool(RegistryHive
->HiveHeader
);
1162 ExFreePool(RegistryHive
);
1164 return(STATUS_SUCCESS
);
1169 CmiCalcChecksum(PULONG Buffer
)
1174 for (i
= 0; i
< 127; i
++)
1182 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
1184 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1185 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1186 OBJECT_ATTRIBUTES ObjectAttributes
;
1187 IO_STATUS_BLOCK IoStatusBlock
;
1189 LARGE_INTEGER FileOffset
;
1199 DPRINT("CmiStartLogUpdate() called\n");
1201 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1202 BufferSize
= sizeof(HIVE_HEADER
) +
1205 BufferSize
= ROUND_UP(BufferSize
, 4096);
1207 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1209 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1212 DPRINT("ExAllocatePool() failed\n");
1213 return(STATUS_INSUFFICIENT_RESOURCES
);
1216 /* Open log file for writing */
1217 InitializeObjectAttributes(&ObjectAttributes
,
1218 &RegistryHive
->LogFileName
,
1223 Status
= NtCreateFile(&FileHandle
,
1228 FILE_ATTRIBUTE_NORMAL
,
1231 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1234 if (!NT_SUCCESS(Status
))
1236 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1241 /* Update firt update counter and checksum */
1242 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1243 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1245 /* Copy hive header */
1246 RtlCopyMemory(Buffer
,
1247 RegistryHive
->HiveHeader
,
1248 sizeof(HIVE_HEADER
));
1249 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1256 RegistryHive
->DirtyBitMap
.Buffer
,
1259 /* Write hive block and block bitmap */
1260 FileOffset
.QuadPart
= 0ULL;
1261 Status
= NtWriteFile(FileHandle
,
1270 if (!NT_SUCCESS(Status
))
1272 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1273 NtClose(FileHandle
);
1279 /* Write dirty blocks */
1280 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1284 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1287 if (BlockIndex
== (ULONG
)-1)
1289 DPRINT("No more set bits\n");
1290 Status
= STATUS_SUCCESS
;
1294 DPRINT("Block %lu is dirty\n", BlockIndex
);
1296 BlockOffset
= RegistryHive
->BlockList
[BlockIndex
]->BlockOffset
;
1297 DPRINT("Block offset %lx\n", BlockOffset
);
1299 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
] + ((BlockIndex
* 4096) - BlockOffset
);
1300 DPRINT("BlockPtr %p\n", BlockPtr
);
1302 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1304 /* Write hive block */
1305 Status
= NtWriteFile(FileHandle
,
1314 if (!NT_SUCCESS(Status
))
1316 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1317 NtClose(FileHandle
);
1322 FileOffset
.QuadPart
+= 4096ULL;
1325 /* Truncate log file */
1326 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1327 Status
= NtSetInformationFile(FileHandle
,
1330 sizeof(FILE_END_OF_FILE_INFORMATION
),
1331 FileEndOfFileInformation
);
1332 if (!NT_SUCCESS(Status
))
1334 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1335 NtClose(FileHandle
);
1339 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1340 Status
= NtSetInformationFile(FileHandle
,
1342 &FileAllocationInfo
,
1343 sizeof(FILE_ALLOCATION_INFORMATION
),
1344 FileAllocationInformation
);
1345 if (!NT_SUCCESS(Status
))
1347 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1348 NtClose(FileHandle
);
1352 /* Flush the log file */
1353 Status
= NtFlushBuffersFile(FileHandle
,
1355 if (!NT_SUCCESS(Status
))
1357 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1360 NtClose(FileHandle
);
1367 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1369 OBJECT_ATTRIBUTES ObjectAttributes
;
1370 IO_STATUS_BLOCK IoStatusBlock
;
1372 LARGE_INTEGER FileOffset
;
1379 DPRINT("CmiFinishLogUpdate() called\n");
1381 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1382 BufferSize
= sizeof(HIVE_HEADER
) +
1385 BufferSize
= ROUND_UP(BufferSize
, 4096);
1387 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1389 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1392 DPRINT("ExAllocatePool() failed\n");
1393 return(STATUS_INSUFFICIENT_RESOURCES
);
1396 /* Open log file for writing */
1397 InitializeObjectAttributes(&ObjectAttributes
,
1398 &RegistryHive
->LogFileName
,
1403 Status
= NtCreateFile(&FileHandle
,
1408 FILE_ATTRIBUTE_NORMAL
,
1411 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1414 if (!NT_SUCCESS(Status
))
1416 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1421 /* Update first and second update counter and checksum */
1422 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1423 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1424 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1426 /* Copy hive header */
1427 RtlCopyMemory(Buffer
,
1428 RegistryHive
->HiveHeader
,
1429 sizeof(HIVE_HEADER
));
1430 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1432 /* Write empty block bitmap */
1440 /* Write hive block and block bitmap */
1441 FileOffset
.QuadPart
= 0ULL;
1442 Status
= NtWriteFile(FileHandle
,
1451 if (!NT_SUCCESS(Status
))
1453 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1454 NtClose(FileHandle
);
1461 /* Flush the log file */
1462 Status
= NtFlushBuffersFile(FileHandle
,
1464 if (!NT_SUCCESS(Status
))
1466 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1469 NtClose(FileHandle
);
1476 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1478 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1479 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1480 OBJECT_ATTRIBUTES ObjectAttributes
;
1481 IO_STATUS_BLOCK IoStatusBlock
;
1487 DPRINT("CmiFinishLogUpdate() called\n");
1489 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1490 BufferSize
= sizeof(HIVE_HEADER
) +
1493 BufferSize
= ROUND_UP(BufferSize
, 4096);
1495 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1497 /* Open log file for writing */
1498 InitializeObjectAttributes(&ObjectAttributes
,
1499 &RegistryHive
->LogFileName
,
1504 Status
= NtCreateFile(&FileHandle
,
1509 FILE_ATTRIBUTE_NORMAL
,
1512 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1515 if (!NT_SUCCESS(Status
))
1517 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1521 /* Truncate log file */
1522 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1523 Status
= NtSetInformationFile(FileHandle
,
1526 sizeof(FILE_END_OF_FILE_INFORMATION
),
1527 FileEndOfFileInformation
);
1528 if (!NT_SUCCESS(Status
))
1530 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1531 NtClose(FileHandle
);
1535 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1536 Status
= NtSetInformationFile(FileHandle
,
1538 &FileAllocationInfo
,
1539 sizeof(FILE_ALLOCATION_INFORMATION
),
1540 FileAllocationInformation
);
1541 if (!NT_SUCCESS(Status
))
1543 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status
);
1544 NtClose(FileHandle
);
1548 /* Flush the log file */
1549 Status
= NtFlushBuffersFile(FileHandle
,
1551 if (!NT_SUCCESS(Status
))
1553 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1556 NtClose(FileHandle
);
1563 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1565 OBJECT_ATTRIBUTES ObjectAttributes
;
1566 IO_STATUS_BLOCK IoStatusBlock
;
1568 LARGE_INTEGER FileOffset
;
1574 DPRINT("CmiStartHiveUpdate() called\n");
1576 /* Open hive for writing */
1577 InitializeObjectAttributes(&ObjectAttributes
,
1578 &RegistryHive
->HiveFileName
,
1583 Status
= NtCreateFile(&FileHandle
,
1588 FILE_ATTRIBUTE_NORMAL
,
1591 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1594 if (!NT_SUCCESS(Status
))
1596 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1600 /* Update firt update counter and checksum */
1601 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1602 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1604 /* Write hive block */
1605 FileOffset
.QuadPart
= 0ULL;
1606 Status
= NtWriteFile(FileHandle
,
1611 RegistryHive
->HiveHeader
,
1612 sizeof(HIVE_HEADER
),
1615 if (!NT_SUCCESS(Status
))
1617 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1618 NtClose(FileHandle
);
1625 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1628 if (BlockIndex
== (ULONG
)-1)
1630 DPRINT("No more set bits\n");
1631 Status
= STATUS_SUCCESS
;
1635 DPRINT("Block %lu is dirty\n", BlockIndex
);
1637 BlockOffset
= RegistryHive
->BlockList
[BlockIndex
]->BlockOffset
;
1638 DPRINT("Block offset %lx\n", BlockOffset
);
1640 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
] + ((BlockIndex
* 4096) - BlockOffset
);
1641 DPRINT("BlockPtr %p\n", BlockPtr
);
1643 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096ULL;
1644 DPRINT("File offset %I64x\n", FileOffset
.QuadPart
);
1647 /* Write hive block */
1648 Status
= NtWriteFile(FileHandle
,
1657 if (!NT_SUCCESS(Status
))
1659 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1660 NtClose(FileHandle
);
1667 Status
= NtFlushBuffersFile(FileHandle
,
1669 if (!NT_SUCCESS(Status
))
1671 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1674 NtClose(FileHandle
);
1681 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1683 OBJECT_ATTRIBUTES ObjectAttributes
;
1684 IO_STATUS_BLOCK IoStatusBlock
;
1685 LARGE_INTEGER FileOffset
;
1689 DPRINT("CmiFinishHiveUpdate() called\n");
1691 InitializeObjectAttributes(&ObjectAttributes
,
1692 &RegistryHive
->HiveFileName
,
1697 Status
= NtCreateFile(&FileHandle
,
1702 FILE_ATTRIBUTE_NORMAL
,
1705 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1708 if (!NT_SUCCESS(Status
))
1710 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1714 /* Update second update counter and checksum */
1715 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1716 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1717 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1719 /* Write hive block */
1720 FileOffset
.QuadPart
= 0ULL;
1721 Status
= NtWriteFile(FileHandle
,
1726 RegistryHive
->HiveHeader
,
1727 sizeof(HIVE_HEADER
),
1730 if (!NT_SUCCESS(Status
))
1732 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1733 NtClose(FileHandle
);
1737 Status
= NtFlushBuffersFile(FileHandle
,
1739 if (!NT_SUCCESS(Status
))
1741 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1744 NtClose(FileHandle
);
1751 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1755 DPRINT("CmiFlushRegistryHive() called\n");
1757 if (RegistryHive
->HiveDirty
== FALSE
)
1759 return(STATUS_SUCCESS
);
1762 DPRINT("Hive '%wZ' is dirty\n",
1763 &RegistryHive
->HiveFileName
);
1764 DPRINT("Log file: '%wZ'\n",
1765 &RegistryHive
->LogFileName
);
1767 /* Update hive header modification time */
1768 NtQuerySystemTime((PTIME
)&RegistryHive
->HiveHeader
->DateModified
);
1770 /* Start log update */
1771 Status
= CmiStartLogUpdate(RegistryHive
);
1772 if (!NT_SUCCESS(Status
))
1774 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1778 /* Finish log update */
1779 Status
= CmiFinishLogUpdate(RegistryHive
);
1780 if (!NT_SUCCESS(Status
))
1782 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1786 /* Start hive update */
1787 Status
= CmiStartHiveUpdate(RegistryHive
);
1788 if (!NT_SUCCESS(Status
))
1790 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1794 /* Finish the hive update */
1795 Status
= CmiFinishHiveUpdate(RegistryHive
);
1796 if (!NT_SUCCESS(Status
))
1798 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
1802 /* Cleanup log update */
1803 Status
= CmiCleanupLogUpdate(RegistryHive
);
1804 if (!NT_SUCCESS(Status
))
1806 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1810 /* Increment hive update counter */
1811 RegistryHive
->UpdateCounter
++;
1813 /* Clear dirty bitmap and dirty flag */
1814 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
1815 RegistryHive
->HiveDirty
= FALSE
;
1817 DPRINT("CmiFlushRegistryHive() done\n");
1819 return(STATUS_SUCCESS
);
1824 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive
,
1827 PHASH_TABLE_CELL HashBlock
;
1828 PKEY_CELL CurSubKeyCell
;
1832 VERIFY_KEY_CELL(KeyCell
);
1835 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1836 if (HashBlock
== NULL
)
1841 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1843 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
1845 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1846 HashBlock
->Table
[i
].KeyOffset
,
1848 if (MaxName
< CurSubKeyCell
->NameSize
)
1850 MaxName
= CurSubKeyCell
->NameSize
;
1852 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1856 CmiReleaseBlock(RegistryHive
, HashBlock
);
1863 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive
,
1866 PHASH_TABLE_CELL HashBlock
;
1867 PKEY_CELL CurSubKeyCell
;
1871 VERIFY_KEY_CELL(KeyCell
);
1874 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1875 if (HashBlock
== NULL
)
1880 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1882 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
1884 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1885 HashBlock
->Table
[i
].KeyOffset
,
1887 if (MaxClass
< CurSubKeyCell
->ClassSize
)
1889 MaxClass
= CurSubKeyCell
->ClassSize
;
1891 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1895 CmiReleaseBlock(RegistryHive
, HashBlock
);
1902 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
1905 PVALUE_LIST_CELL ValueListCell
;
1906 PVALUE_CELL CurValueCell
;
1910 VERIFY_KEY_CELL(KeyCell
);
1912 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1914 if (ValueListCell
== NULL
)
1919 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1921 CurValueCell
= CmiGetBlock(RegistryHive
,
1922 ValueListCell
->Values
[i
],
1924 if (CurValueCell
!= NULL
&&
1925 MaxValueName
< CurValueCell
->NameSize
)
1927 MaxValueName
= CurValueCell
->NameSize
;
1929 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1932 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1934 return MaxValueName
;
1939 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
1942 PVALUE_LIST_CELL ValueListCell
;
1943 PVALUE_CELL CurValueCell
;
1947 VERIFY_KEY_CELL(KeyCell
);
1949 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1951 if (ValueListCell
== NULL
)
1956 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1958 CurValueCell
= CmiGetBlock(RegistryHive
,
1959 ValueListCell
->Values
[i
],NULL
);
1960 if ((CurValueCell
!= NULL
) &&
1961 (MaxValueData
< (CurValueCell
->DataSize
& LONG_MAX
)))
1963 MaxValueData
= CurValueCell
->DataSize
& LONG_MAX
;
1965 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1968 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1970 return MaxValueData
;
1975 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
1976 IN PKEY_CELL KeyCell
,
1977 OUT PKEY_CELL
*SubKeyCell
,
1978 OUT BLOCK_OFFSET
*BlockOffset
,
1980 IN ACCESS_MASK DesiredAccess
,
1981 IN ULONG Attributes
)
1983 PHASH_TABLE_CELL HashBlock
;
1984 PKEY_CELL CurSubKeyCell
;
1988 VERIFY_KEY_CELL(KeyCell
);
1990 //DPRINT("Scanning for sub key %s\n", KeyName);
1992 assert(RegistryHive
);
1994 KeyLength
= strlen(KeyName
);
1996 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1998 if (HashBlock
== NULL
)
2000 return STATUS_SUCCESS
;
2003 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
)
2004 && (i
< HashBlock
->HashTableSize
); i
++)
2006 if (Attributes
& OBJ_CASE_INSENSITIVE
)
2008 if ((HashBlock
->Table
[i
].KeyOffset
!= 0) &&
2009 (HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1) &&
2010 (_strnicmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4) == 0))
2012 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
2013 HashBlock
->Table
[i
].KeyOffset
,
2015 if ((CurSubKeyCell
->NameSize
== KeyLength
)
2016 && (_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
) == 0))
2018 *SubKeyCell
= CurSubKeyCell
;
2019 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2024 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
2030 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
2031 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
2032 !strncmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4))
2034 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
2035 HashBlock
->Table
[i
].KeyOffset
,NULL
);
2036 if (CurSubKeyCell
->NameSize
== KeyLength
2037 && !_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
))
2039 *SubKeyCell
= CurSubKeyCell
;
2040 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
2045 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
2051 CmiReleaseBlock(RegistryHive
, HashBlock
);
2053 return STATUS_SUCCESS
;
2058 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
2061 PWSTR NewSubKeyName
,
2062 USHORT NewSubKeyNameSize
,
2064 PUNICODE_STRING Class
,
2065 ULONG CreateOptions
)
2067 PHASH_TABLE_CELL NewHashBlock
;
2068 PHASH_TABLE_CELL HashBlock
;
2069 BLOCK_OFFSET NKBOffset
;
2070 PKEY_CELL NewKeyCell
;
2076 KeyCell
= Parent
->KeyCell
;
2078 VERIFY_KEY_CELL(KeyCell
);
2080 if (NewSubKeyName
[0] == L
'\\')
2083 NameSize
= NewSubKeyNameSize
/ 2 - 1;
2087 NameSize
= NewSubKeyNameSize
/ 2;
2089 Status
= STATUS_SUCCESS
;
2091 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
2092 Status
= CmiAllocateBlock(RegistryHive
,
2093 (PVOID
) &NewKeyCell
,
2097 if (NewKeyCell
== NULL
)
2099 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2103 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
2104 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
2105 ZwQuerySystemTime((PTIME
) &NewKeyCell
->LastWriteTime
);
2106 NewKeyCell
->ParentKeyOffset
= -1;
2107 NewKeyCell
->NumberOfSubKeys
= 0;
2108 NewKeyCell
->HashTableOffset
= -1;
2109 NewKeyCell
->NumberOfValues
= 0;
2110 NewKeyCell
->ValuesOffset
= -1;
2111 NewKeyCell
->SecurityKeyOffset
= -1;
2112 NewKeyCell
->NameSize
= NameSize
;
2113 wcstombs(NewKeyCell
->Name
, NewSubKeyName
, NameSize
);
2114 NewKeyCell
->ClassNameOffset
= -1;
2116 VERIFY_KEY_CELL(NewKeyCell
);
2122 NewKeyCell
->ClassSize
= Class
->Length
+ sizeof(WCHAR
);
2123 Status
= CmiAllocateBlock(RegistryHive
,
2125 NewKeyCell
->ClassSize
,
2126 &NewKeyCell
->ClassNameOffset
);
2127 wcsncpy((PWSTR
) pClass
->Data
, Class
->Buffer
, Class
->Length
);
2128 ((PWSTR
) (pClass
->Data
))[Class
->Length
] = 0;
2132 if (!NT_SUCCESS(Status
))
2137 SubKey
->KeyCell
= NewKeyCell
;
2138 SubKey
->BlockOffset
= NKBOffset
;
2140 /* Don't modify hash table if key is volatile and parent is not */
2141 if (IsVolatileHive(RegistryHive
) && (!IsVolatileHive(Parent
->RegistryHive
)))
2146 if (KeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
2148 Status
= CmiAllocateHashTableBlock(RegistryHive
,
2150 &KeyCell
->HashTableOffset
,
2151 REG_INIT_HASH_TABLE_SIZE
);
2152 if (!NT_SUCCESS(Status
))
2159 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
2160 if (((KeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
2162 BLOCK_OFFSET HTOffset
;
2164 /* Reallocate the hash table block */
2165 Status
= CmiAllocateHashTableBlock(RegistryHive
,
2168 HashBlock
->HashTableSize
+
2169 REG_EXTEND_HASH_TABLE_SIZE
);
2170 if (!NT_SUCCESS(Status
))
2175 RtlZeroMemory(&NewHashBlock
->Table
[0],
2176 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2177 RtlCopyMemory(&NewHashBlock
->Table
[0],
2178 &HashBlock
->Table
[0],
2179 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2180 CmiDestroyBlock(RegistryHive
,
2182 KeyCell
->HashTableOffset
);
2183 KeyCell
->HashTableOffset
= HTOffset
;
2184 HashBlock
= NewHashBlock
;
2188 Status
= CmiAddKeyToHashTable(RegistryHive
,
2192 if (NT_SUCCESS(Status
))
2194 KeyCell
->NumberOfSubKeys
++;
2202 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
2203 PKEY_OBJECT ParentKey
,
2206 PHASH_TABLE_CELL HashBlock
;
2207 PVALUE_LIST_CELL ValueList
;
2208 PVALUE_CELL ValueCell
;
2209 PDATA_CELL DataCell
;
2212 DPRINT("CmiRemoveSubKey() called\n");
2214 /* Remove all values */
2215 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
2217 /* Get pointer to the value list cell */
2218 ValueList
= CmiGetBlock(RegistryHive
,
2219 SubKey
->KeyCell
->ValuesOffset
,
2221 if (ValueList
!= NULL
)
2223 /* Enumerate all values */
2224 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
2226 /* Get pointer to value cell */
2227 ValueCell
= CmiGetBlock(RegistryHive
,
2228 ValueList
->Values
[i
],
2230 if (ValueCell
!= NULL
)
2232 if (ValueCell
->DataSize
> 4)
2234 DataCell
= CmiGetBlock(RegistryHive
,
2235 ValueCell
->DataOffset
,
2237 if (DataCell
!= NULL
)
2239 /* Destroy data cell */
2240 CmiDestroyBlock(RegistryHive
,
2242 ValueCell
->DataOffset
);
2246 /* Destroy value cell */
2247 CmiDestroyBlock(RegistryHive
,
2249 ValueList
->Values
[i
]);
2254 /* Destroy value list cell */
2255 CmiDestroyBlock(RegistryHive
,
2257 SubKey
->KeyCell
->ValuesOffset
);
2259 SubKey
->KeyCell
->NumberOfValues
= 0;
2260 SubKey
->KeyCell
->ValuesOffset
= -1;
2263 /* Remove the key from the parent key's hash block */
2264 if (ParentKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2266 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
)
2267 HashBlock
= CmiGetBlock(RegistryHive
,
2268 ParentKey
->KeyCell
->HashTableOffset
,
2270 DPRINT("ParentKey HashBlock %p\n", HashBlock
)
2271 if (HashBlock
!= NULL
)
2273 CmiRemoveKeyFromHashTable(RegistryHive
,
2275 SubKey
->BlockOffset
);
2276 CmiMarkBlockDirty(RegistryHive
,
2277 ParentKey
->KeyCell
->HashTableOffset
);
2281 /* Remove the key's hash block */
2282 if (SubKey
->KeyCell
->HashTableOffset
!= (BLOCK_OFFSET
) -1)
2284 DPRINT("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
)
2285 HashBlock
= CmiGetBlock(RegistryHive
,
2286 SubKey
->KeyCell
->HashTableOffset
,
2288 DPRINT("SubKey HashBlock %p\n", HashBlock
)
2289 if (HashBlock
!= NULL
)
2291 CmiDestroyBlock(RegistryHive
,
2293 SubKey
->KeyCell
->HashTableOffset
);
2294 SubKey
->KeyCell
->HashTableOffset
= -1;
2298 /* Decrement the number of the parent key's sub keys */
2299 if (ParentKey
!= NULL
)
2301 DPRINT("ParentKey %p\n", ParentKey
)
2302 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2304 /* Remove the parent key's hash table */
2305 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2307 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
)
2308 HashBlock
= CmiGetBlock(RegistryHive
,
2309 ParentKey
->KeyCell
->HashTableOffset
,
2311 DPRINT("ParentKey HashBlock %p\n", HashBlock
)
2312 if (HashBlock
!= NULL
)
2314 CmiDestroyBlock(RegistryHive
,
2316 ParentKey
->KeyCell
->HashTableOffset
);
2317 ParentKey
->KeyCell
->HashTableOffset
= -1;
2321 NtQuerySystemTime((PTIME
)&ParentKey
->KeyCell
->LastWriteTime
);
2322 CmiMarkBlockDirty(RegistryHive
,
2323 ParentKey
->BlockOffset
);
2326 /* Destroy key cell */
2327 CmiDestroyBlock(RegistryHive
,
2329 SubKey
->BlockOffset
);
2330 SubKey
->BlockOffset
= -1;
2331 SubKey
->KeyCell
= NULL
;
2333 return(STATUS_SUCCESS
);
2338 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2339 IN PKEY_CELL KeyCell
,
2340 IN PUNICODE_STRING ValueName
,
2341 OUT PVALUE_CELL
*ValueCell
,
2342 OUT BLOCK_OFFSET
*VBOffset
)
2344 PVALUE_LIST_CELL ValueListCell
;
2345 PVALUE_CELL CurValueCell
;
2348 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2352 if (ValueListCell
== NULL
)
2354 DPRINT("ValueListCell is NULL\n");
2355 return STATUS_SUCCESS
;
2358 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2360 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2362 CurValueCell
= CmiGetBlock(RegistryHive
,
2363 ValueListCell
->Values
[i
],
2366 if ((CurValueCell
!= NULL
) &&
2367 CmiComparePackedNames(ValueName
,
2369 CurValueCell
->NameSize
,
2370 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
2372 *ValueCell
= CurValueCell
;
2374 *VBOffset
= ValueListCell
->Values
[i
];
2375 //DPRINT("Found value %s\n", ValueName);
2378 CmiReleaseBlock(RegistryHive
, CurValueCell
);
2381 CmiReleaseBlock(RegistryHive
, ValueListCell
);
2383 return STATUS_SUCCESS
;
2388 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2389 IN PKEY_CELL KeyCell
,
2391 OUT PVALUE_CELL
*ValueCell
)
2393 PVALUE_LIST_CELL ValueListCell
;
2394 PVALUE_CELL CurValueCell
;
2396 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2400 if (ValueListCell
== NULL
)
2402 return STATUS_NO_MORE_ENTRIES
;
2405 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2407 if (Index
>= KeyCell
->NumberOfValues
)
2409 return STATUS_NO_MORE_ENTRIES
;
2412 CurValueCell
= CmiGetBlock(RegistryHive
,
2413 ValueListCell
->Values
[Index
],
2416 if (CurValueCell
!= NULL
)
2418 *ValueCell
= CurValueCell
;
2421 CmiReleaseBlock(RegistryHive
, CurValueCell
);
2422 CmiReleaseBlock(RegistryHive
, ValueListCell
);
2424 return STATUS_SUCCESS
;
2429 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2430 IN PKEY_CELL KeyCell
,
2431 IN PUNICODE_STRING ValueName
,
2432 OUT PVALUE_CELL
*pValueCell
,
2433 OUT BLOCK_OFFSET
*pVBOffset
)
2435 PVALUE_LIST_CELL NewValueListCell
;
2436 PVALUE_LIST_CELL ValueListCell
;
2437 PVALUE_CELL NewValueCell
;
2438 BLOCK_OFFSET VLBOffset
;
2439 BLOCK_OFFSET VBOffset
;
2442 Status
= CmiAllocateValueCell(RegistryHive
,
2446 *pVBOffset
= VBOffset
;
2448 if (!NT_SUCCESS(Status
))
2453 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2455 if (ValueListCell
== NULL
)
2457 Status
= CmiAllocateBlock(RegistryHive
,
2458 (PVOID
) &ValueListCell
,
2459 sizeof(BLOCK_OFFSET
) * 3,
2462 if (!NT_SUCCESS(Status
))
2464 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2467 KeyCell
->ValuesOffset
= VLBOffset
;
2469 else if (KeyCell
->NumberOfValues
>=
2470 (((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - 4) / sizeof(BLOCK_OFFSET
)))
2472 Status
= CmiAllocateBlock(RegistryHive
,
2473 (PVOID
) &NewValueListCell
,
2474 (KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
) *
2475 sizeof(BLOCK_OFFSET
),
2477 if (!NT_SUCCESS(Status
))
2479 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2483 RtlCopyMemory(&NewValueListCell
->Values
[0],
2484 &ValueListCell
->Values
[0],
2485 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2486 CmiDestroyBlock(RegistryHive
, ValueListCell
, KeyCell
->ValuesOffset
);
2487 KeyCell
->ValuesOffset
= VLBOffset
;
2488 ValueListCell
= NewValueListCell
;
2491 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2492 KeyCell
->NumberOfValues
,
2493 (ULONG
)ABS_VALUE(ValueListCell
->CellSize
),
2494 ((ULONG
)ABS_VALUE(ValueListCell
->CellSize
) - 4) / sizeof(BLOCK_OFFSET
),
2495 ((ULONG
)ABS_VALUS(ValueListCell
->CellSize
) - 4) / sizeof(BLOCK_OFFSET
));
2497 ValueListCell
->Values
[KeyCell
->NumberOfValues
] = VBOffset
;
2498 KeyCell
->NumberOfValues
++;
2499 CmiReleaseBlock(RegistryHive
, ValueListCell
);
2500 CmiReleaseBlock(RegistryHive
, NewValueCell
);
2501 *pValueCell
= NewValueCell
;
2503 return STATUS_SUCCESS
;
2508 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2509 IN PKEY_CELL KeyCell
,
2510 IN BLOCK_OFFSET KeyCellOffset
,
2511 IN PUNICODE_STRING ValueName
)
2513 PVALUE_LIST_CELL ValueListCell
;
2514 PVALUE_CELL CurValueCell
;
2517 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2519 if (ValueListCell
== NULL
)
2521 return STATUS_SUCCESS
;
2524 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2526 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2528 CurValueCell
= CmiGetBlock(RegistryHive
, ValueListCell
->Values
[i
], NULL
);
2530 if ((CurValueCell
!= NULL
) &&
2531 CmiComparePackedNames(ValueName
,
2533 CurValueCell
->NameSize
,
2534 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
2536 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->Values
[i
]);
2538 if ((KeyCell
->NumberOfValues
- 1) < i
)
2540 RtlCopyMemory(&ValueListCell
->Values
[i
],
2541 &ValueListCell
->Values
[i
+ 1],
2542 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2546 RtlZeroMemory(&ValueListCell
->Values
[i
], sizeof(BLOCK_OFFSET
));
2549 KeyCell
->NumberOfValues
-= 1;
2552 CmiReleaseBlock(RegistryHive
, CurValueCell
);
2555 CmiReleaseBlock(RegistryHive
, ValueListCell
);
2557 if (KeyCell
->NumberOfValues
== 0)
2559 CmiDestroyBlock(RegistryHive
,
2561 KeyCell
->ValuesOffset
);
2565 CmiMarkBlockDirty(RegistryHive
,
2566 KeyCell
->ValuesOffset
);
2569 CmiMarkBlockDirty(RegistryHive
,
2572 return STATUS_SUCCESS
;
2577 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive
,
2578 OUT PHASH_TABLE_CELL
*HashBlock
,
2579 OUT BLOCK_OFFSET
*HBOffset
,
2580 IN ULONG HashTableSize
)
2582 PHASH_TABLE_CELL NewHashBlock
;
2586 Status
= STATUS_SUCCESS
;
2588 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
2589 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
2590 Status
= CmiAllocateBlock(RegistryHive
,
2591 (PVOID
*) &NewHashBlock
,
2595 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
2597 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2601 NewHashBlock
->Id
= REG_HASH_TABLE_BLOCK_ID
;
2602 NewHashBlock
->HashTableSize
= HashTableSize
;
2603 *HashBlock
= NewHashBlock
;
2611 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
2612 PHASH_TABLE_CELL HashBlock
,
2615 BLOCK_OFFSET KeyOffset
;
2618 if (HashBlock
== NULL
)
2621 if (IsVolatileHive(RegistryHive
))
2623 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
2627 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
2628 KeyCell
= CmiGetBlock(RegistryHive
, KeyOffset
, NULL
);
2630 CmiLockBlock(RegistryHive
, KeyCell
);
2637 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
2638 PHASH_TABLE_CELL HashBlock
,
2639 PKEY_CELL NewKeyCell
,
2640 BLOCK_OFFSET NKBOffset
)
2644 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2646 if (HashBlock
->Table
[i
].KeyOffset
== 0)
2648 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
2649 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
, NewKeyCell
->Name
, 4);
2650 return STATUS_SUCCESS
;
2654 return STATUS_UNSUCCESSFUL
;
2659 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
2660 PHASH_TABLE_CELL HashBlock
,
2661 BLOCK_OFFSET NKBOffset
)
2665 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2667 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
2669 HashBlock
->Table
[i
].KeyOffset
= 0;
2670 RtlZeroMemory(&HashBlock
->Table
[i
].HashValue
, 4);
2671 return STATUS_SUCCESS
;
2675 return STATUS_UNSUCCESSFUL
;
2680 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
2681 PVALUE_CELL
*ValueCell
,
2682 BLOCK_OFFSET
*VBOffset
,
2683 IN PUNICODE_STRING ValueName
)
2685 PVALUE_CELL NewValueCell
;
2691 Status
= STATUS_SUCCESS
;
2693 NameSize
= CmiGetPackedNameLength(ValueName
,
2696 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
2698 Status
= CmiAllocateBlock(RegistryHive
,
2699 (PVOID
*) &NewValueCell
,
2700 sizeof(VALUE_CELL
) + NameSize
,
2702 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
2704 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2708 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
2709 NewValueCell
->NameSize
= NameSize
;
2712 /* Pack the value name */
2713 for (i
= 0; i
< NameSize
; i
++)
2714 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
2715 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
2719 /* Copy the value name */
2720 RtlCopyMemory(NewValueCell
->Name
,
2723 NewValueCell
->Flags
= 0;
2725 NewValueCell
->DataType
= 0;
2726 NewValueCell
->DataSize
= 0;
2727 NewValueCell
->DataOffset
= 0xffffffff;
2728 *ValueCell
= NewValueCell
;
2736 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
2737 PVALUE_CELL ValueCell
,
2738 BLOCK_OFFSET VBOffset
)
2744 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell
, VBOffset
);
2746 VERIFY_VALUE_CELL(ValueCell
);
2748 /* Destroy the data cell */
2749 if (ValueCell
->DataSize
> 4)
2751 pBlock
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, &pBin
);
2752 Status
= CmiDestroyBlock(RegistryHive
, pBlock
, ValueCell
->DataOffset
);
2753 if (!NT_SUCCESS(Status
))
2758 /* Update time of heap */
2759 if (IsPermanentHive(RegistryHive
))
2760 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2763 /* Destroy the value cell */
2764 Status
= CmiDestroyBlock(RegistryHive
, ValueCell
, VBOffset
);
2766 /* Update time of heap */
2767 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, VBOffset
, &pBin
))
2769 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2777 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
2779 BLOCK_OFFSET
*NewBlockOffset
)
2781 PCELL_HEADER tmpBlock
;
2782 PHBIN
* tmpBlockList
;
2785 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
2788 return STATUS_INSUFFICIENT_RESOURCES
;
2791 tmpBin
->BlockId
= REG_BIN_ID
;
2792 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
2793 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
2794 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
2795 tmpBin
->Unused1
= 0;
2796 ZwQuerySystemTime((PTIME
) &tmpBin
->DateModified
);
2797 tmpBin
->Unused2
= 0;
2799 /* Increase size of list of blocks */
2800 tmpBlockList
= ExAllocatePool(NonPagedPool
,
2801 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
2802 if (tmpBlockList
== NULL
)
2805 return STATUS_INSUFFICIENT_RESOURCES
;
2808 if (RegistryHive
->BlockListSize
> 0)
2810 memcpy(tmpBlockList
,
2811 RegistryHive
->BlockList
,
2812 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
2813 ExFreePool(RegistryHive
->BlockList
);
2816 RegistryHive
->BlockList
= tmpBlockList
;
2817 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
++] = tmpBin
;
2819 /* Initialize a free block in this heap : */
2820 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
2821 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
2823 /* Grow bitmap if necessary */
2824 if (IsVolatileHive(RegistryHive
) &&
2825 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
2827 PULONG BitmapBuffer
;
2830 DPRINT1("Grow hive bitmap\n");
2832 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
2833 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
2834 DPRINT1("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
2835 DPRINT1("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
2836 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
2838 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
2839 RtlCopyMemory(BitmapBuffer
,
2840 RegistryHive
->DirtyBitMap
.Buffer
,
2841 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
2842 ExFreePool(RegistryHive
->DirtyBitMap
.Buffer
);
2843 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
2848 *NewBlock
= (PVOID
) tmpBlock
;
2851 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
2853 /* FIXME: set first dword to block_offset of another free bloc */
2855 /* Mark new bin dirty */
2856 CmiMarkBinDirty(RegistryHive
,
2857 tmpBin
->BlockOffset
);
2859 return STATUS_SUCCESS
;
2864 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive
,
2867 BLOCK_OFFSET
* pBlockOffset
)
2869 PCELL_HEADER NewBlock
;
2873 Status
= STATUS_SUCCESS
;
2875 /* Round to 16 bytes multiple */
2876 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
2878 /* Handle volatile hives first */
2879 if (IsVolatileHive(RegistryHive
))
2881 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
2883 if (NewBlock
== NULL
)
2885 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2889 RtlZeroMemory(NewBlock
, BlockSize
);
2890 NewBlock
->CellSize
= BlockSize
;
2891 CmiLockBlock(RegistryHive
, NewBlock
);
2894 *pBlockOffset
= (BLOCK_OFFSET
) NewBlock
;
2901 /* first search in free blocks */
2903 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
2905 if (RegistryHive
->FreeList
[i
]->CellSize
>= BlockSize
)
2909 NewBlock
= RegistryHive
->FreeList
[i
];
2911 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
2913 /* Update time of heap */
2914 Temp
= CmiGetBlock(RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
2918 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2919 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
2922 if ((i
+ 1) < RegistryHive
->FreeListSize
)
2924 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
2925 &RegistryHive
->FreeList
[i
+ 1],
2926 sizeof(RegistryHive
->FreeList
[0])
2927 * (RegistryHive
->FreeListSize
- i
- 1));
2928 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
2929 &RegistryHive
->FreeListOffset
[i
+ 1],
2930 sizeof(RegistryHive
->FreeListOffset
[0])
2931 * (RegistryHive
->FreeListSize
- i
- 1));
2933 RegistryHive
->FreeListSize
--;
2938 /* Need to extend hive file : */
2939 if (NewBlock
== NULL
)
2941 /* Add a new block */
2942 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewBlock
, pBlockOffset
);
2945 if (NT_SUCCESS(Status
))
2949 /* Split the block in two parts */
2950 if (NewBlock
->CellSize
> BlockSize
)
2952 NewBlock
= (PCELL_HEADER
) ((ULONG_PTR
) NewBlock
+BlockSize
);
2953 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- BlockSize
;
2954 CmiAddFree(RegistryHive
,
2956 *pBlockOffset
+ BlockSize
,
2958 CmiMarkBlockDirty(RegistryHive
,
2959 *pBlockOffset
+ BlockSize
);
2961 else if (NewBlock
->CellSize
< BlockSize
)
2963 return(STATUS_UNSUCCESSFUL
);
2966 RtlZeroMemory(*Block
, BlockSize
);
2967 ((PCELL_HEADER
) (*Block
))->CellSize
= -BlockSize
;
2968 CmiLockBlock(RegistryHive
, *Block
);
2977 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive
,
2979 BLOCK_OFFSET Offset
)
2984 Status
= STATUS_SUCCESS
;
2986 if (IsVolatileHive(RegistryHive
))
2988 CmiReleaseBlock(RegistryHive
, Block
);
2993 PCELL_HEADER pFree
= Block
;
2995 if (pFree
->CellSize
< 0)
2996 pFree
->CellSize
= -pFree
->CellSize
;
2998 /* Clear block (except the block size) */
2999 RtlZeroMemory(((PVOID
)pFree
) + sizeof(ULONG
),
3000 pFree
->CellSize
- sizeof(ULONG
));
3002 /* add block to the list of free blocks */
3003 CmiAddFree(RegistryHive
, Block
, Offset
, TRUE
);
3004 CmiReleaseBlock(RegistryHive
, Block
);
3006 /* Update time of heap */
3007 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, Offset
,&pBin
))
3008 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
3010 CmiMarkBlockDirty(RegistryHive
, Offset
);
3012 /* FIXME: Set first dword to block_offset of another free block ? */
3013 /* FIXME: Concatenate with previous and next block if free */
3021 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
3022 PCELL_HEADER FreeBlock
,
3023 BLOCK_OFFSET FreeOffset
)
3025 BLOCK_OFFSET BlockOffset
;
3026 BLOCK_OFFSET BinOffset
;
3032 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3033 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
3035 CmiGetBlock(RegistryHive
,
3038 DPRINT("Bin %p\n", Bin
);
3042 BinOffset
= Bin
->BlockOffset
;
3043 BinSize
= Bin
->BlockSize
;
3044 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
3046 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
3048 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
3049 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
3050 if (BlockOffset
> BinOffset
&&
3051 BlockOffset
< BinOffset
+ BinSize
)
3053 DPRINT("Free block: Offset %lx Size %lx\n",
3054 BlockOffset
, BlockSize
);
3056 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
3057 (BlockOffset
+ BlockSize
== FreeOffset
) &&
3058 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
3060 DPRINT("Merge current block with previous and next block\n");
3062 RegistryHive
->FreeList
[i
]->CellSize
+=
3063 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
3065 FreeBlock
->CellSize
= 0;
3066 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
3069 if ((i
+ 2) < RegistryHive
->FreeListSize
)
3071 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
3072 &RegistryHive
->FreeListOffset
[i
+ 2],
3073 sizeof(RegistryHive
->FreeListOffset
[0])
3074 * (RegistryHive
->FreeListSize
- i
- 2));
3076 RegistryHive
->FreeListSize
--;
3078 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3082 else if (BlockOffset
+ BlockSize
== FreeOffset
)
3084 DPRINT("Merge current block with previous block\n");
3086 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
3087 FreeBlock
->CellSize
= 0;
3089 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
3093 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
3095 DPRINT("Merge current block with next block\n");
3097 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
3098 RegistryHive
->FreeList
[i
]->CellSize
= 0;
3099 RegistryHive
->FreeList
[i
] = FreeBlock
;
3100 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
3102 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
3114 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
3115 PCELL_HEADER FreeBlock
,
3116 BLOCK_OFFSET FreeOffset
,
3117 BOOLEAN MergeFreeBlocks
)
3119 PCELL_HEADER
*tmpList
;
3120 BLOCK_OFFSET
*tmpListOffset
;
3125 assert(RegistryHive
);
3128 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3129 FreeBlock
, FreeOffset
);
3131 /* Merge free blocks */
3132 if (MergeFreeBlocks
== TRUE
)
3134 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
3135 return(STATUS_SUCCESS
);
3138 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
3140 tmpList
= ExAllocatePool(PagedPool
,
3141 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
3142 if (tmpList
== NULL
)
3143 return STATUS_INSUFFICIENT_RESOURCES
;
3145 tmpListOffset
= ExAllocatePool(PagedPool
,
3146 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
+ 32));
3148 if (tmpListOffset
== NULL
)
3150 ExFreePool(tmpList
);
3151 return STATUS_INSUFFICIENT_RESOURCES
;
3154 if (RegistryHive
->FreeListMax
)
3156 RtlMoveMemory(tmpList
,
3157 RegistryHive
->FreeList
,
3158 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
3159 RtlMoveMemory(tmpListOffset
,
3160 RegistryHive
->FreeListOffset
,
3161 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
));
3162 ExFreePool(RegistryHive
->FreeList
);
3163 ExFreePool(RegistryHive
->FreeListOffset
);
3165 RegistryHive
->FreeList
= tmpList
;
3166 RegistryHive
->FreeListOffset
= tmpListOffset
;
3167 RegistryHive
->FreeListMax
+= 32;
3170 /* Add new offset to free list, maintaining list in ascending order */
3171 if ((RegistryHive
->FreeListSize
== 0)
3172 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
3174 /* Add to end of list */
3175 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
3176 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
3178 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
3180 /* Add to begin of list */
3181 RtlMoveMemory(&RegistryHive
->FreeList
[1],
3182 &RegistryHive
->FreeList
[0],
3183 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
3184 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
3185 &RegistryHive
->FreeListOffset
[0],
3186 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
3187 RegistryHive
->FreeList
[0] = FreeBlock
;
3188 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
3189 RegistryHive
->FreeListSize
++;
3193 /* Search where to insert */
3195 maxInd
= RegistryHive
->FreeListSize
- 1;
3196 while ((maxInd
- minInd
) > 1)
3198 medInd
= (minInd
+ maxInd
) / 2;
3199 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
3205 /* Insert before maxInd */
3206 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
3207 &RegistryHive
->FreeList
[maxInd
],
3208 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
3209 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
3210 &RegistryHive
->FreeListOffset
[maxInd
],
3211 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
3212 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
3213 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
3214 RegistryHive
->FreeListSize
++;
3217 return STATUS_SUCCESS
;
3222 CmiGetBlock(PREGISTRY_HIVE RegistryHive
,
3223 BLOCK_OFFSET BlockOffset
,
3229 if ((BlockOffset
== 0) || (BlockOffset
== (ULONG_PTR
) -1))
3232 if (IsVolatileHive(RegistryHive
))
3234 return (PVOID
) BlockOffset
;
3240 pBin
= RegistryHive
->BlockList
[BlockOffset
/ 4096];
3243 return((PVOID
)((ULONG_PTR
)pBin
+ (BlockOffset
- pBin
->BlockOffset
)));
3249 CmiLockBlock(PREGISTRY_HIVE RegistryHive
,
3252 if (IsPermanentHive(RegistryHive
))
3254 /* FIXME: Implement */
3260 CmiReleaseBlock(PREGISTRY_HIVE RegistryHive
,
3263 if (IsPermanentHive(RegistryHive
))
3265 /* FIXME: Implement */
3271 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3272 BLOCK_OFFSET BlockOffset
)
3279 if (IsVolatileHive(RegistryHive
))
3282 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3284 BlockNumber
= (ULONG
)BlockOffset
/ 4096;
3286 Cell
= CmiGetBlock(RegistryHive
,
3290 CellSize
= Cell
->CellSize
;
3292 CellSize
= -CellSize
;
3294 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, 4096) - ROUND_DOWN(BlockOffset
, 4096)) / 4096;
3296 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3299 (Cell
->CellSize
< 0) ? "used" : "free",
3302 RegistryHive
->HiveDirty
= TRUE
;
3303 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3310 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3311 BLOCK_OFFSET BinOffset
)
3317 if (IsVolatileHive(RegistryHive
))
3320 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3322 BlockNumber
= (ULONG
)BinOffset
/ 4096;
3324 Bin
= RegistryHive
->BlockList
[BlockNumber
];
3326 BlockCount
= Bin
->BlockSize
/ 4096;
3328 DPRINT(" BlockNumber %lu Size %lu BlockCount %lu\n",
3333 RegistryHive
->HiveDirty
= TRUE
;
3334 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3341 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3342 OUT PBOOLEAN Packable
)
3346 if (Packable
!= NULL
)
3349 for (i
= 0; i
< Name
->Length
; i
++)
3351 if (Name
->Buffer
[i
] > 0xFF)
3353 if (Packable
!= NULL
)
3355 return(Name
->Length
);
3359 return(Name
->Length
/ sizeof(WCHAR
));
3364 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3365 IN PCHAR NameBuffer
,
3366 IN USHORT NameBufferSize
,
3367 IN BOOLEAN NamePacked
)
3372 if (NamePacked
== TRUE
)
3374 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3377 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3379 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3385 if (Name
->Length
!= NameBufferSize
)
3388 UNameBuffer
= (PWCHAR
)NameBuffer
;
3390 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3392 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3402 CmiCopyPackedName(PWCHAR NameBuffer
,
3403 PCHAR PackedNameBuffer
,
3404 ULONG PackedNameSize
)
3408 for (i
= 0; i
< PackedNameSize
; i
++)
3409 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];