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>
22 #include <internal/debug.h>
29 BOOLEAN CmiDoVerify
= FALSE
;
32 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header
)
35 RtlZeroMemory(Header
, sizeof(HIVE_HEADER
));
36 Header
->BlockId
= REG_HIVE_ID
;
37 Header
->DateModified
.dwLowDateTime
= 0;
38 Header
->DateModified
.dwHighDateTime
= 0;
45 Header
->RootKeyCell
= 0;
46 Header
->BlockSize
= REG_BLOCK_SIZE
;
53 CmiCreateDefaultBinCell(PHBIN BinCell
)
56 RtlZeroMemory(BinCell
, sizeof(HBIN
));
57 BinCell
->BlockId
= REG_BIN_ID
;
58 BinCell
->DateModified
.dwLowDateTime
= 0;
59 BinCell
->DateModified
.dwHighDateTime
= 0;
60 BinCell
->BlockSize
= REG_BLOCK_SIZE
;
65 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
)
68 RtlZeroMemory(RootKeyCell
, sizeof(KEY_CELL
));
70 RootKeyCell
->CellSize
= -(LONG
)sizeof(KEY_CELL
);
72 RootKeyCell
->CellSize
= -sizeof(KEY_CELL
);
74 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
75 RootKeyCell
->Type
= REG_ROOT_KEY_CELL_TYPE
;
76 ZwQuerySystemTime((PTIME
) &RootKeyCell
->LastWriteTime
);
77 RootKeyCell
->ParentKeyOffset
= 0;
78 RootKeyCell
->NumberOfSubKeys
= 0;
79 RootKeyCell
->HashTableOffset
= -1;
80 RootKeyCell
->NumberOfValues
= 0;
81 RootKeyCell
->ValuesOffset
= -1;
82 RootKeyCell
->SecurityKeyOffset
= 0;
83 RootKeyCell
->ClassNameOffset
= -1;
84 RootKeyCell
->NameSize
= 0;
85 RootKeyCell
->ClassSize
= 0;
90 CmiVerifyBinCell(PHBIN BinCell
)
97 if (BinCell
->BlockId
!= REG_BIN_ID
)
99 DbgPrint("BlockId is %.08x (should be %.08x)\n",
100 BinCell
->BlockId
, REG_BIN_ID
);
101 assert(BinCell
->BlockId
== REG_BIN_ID
);
104 //BinCell->DateModified.dwLowDateTime
106 //BinCell->DateModified.dwHighDateTime
109 if (BinCell
->BlockSize
!= REG_BLOCK_SIZE
)
111 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
112 BinCell
->BlockSize
, REG_BLOCK_SIZE
);
113 assert(BinCell
->BlockSize
== REG_BLOCK_SIZE
);
121 CmiVerifyKeyCell(PKEY_CELL KeyCell
)
128 if (KeyCell
->CellSize
== 0)
130 DbgPrint("CellSize is %d (must not be 0)\n",
132 assert(KeyCell
->CellSize
!= 0);
135 if (KeyCell
->Id
!= REG_KEY_CELL_ID
)
137 DbgPrint("Id is %.08x (should be %.08x)\n",
138 KeyCell
->Id
, REG_KEY_CELL_ID
);
139 assert(KeyCell
->Id
== REG_KEY_CELL_ID
);
142 if ((KeyCell
->Type
!= REG_KEY_CELL_TYPE
)
143 && (KeyCell
->Type
!= REG_ROOT_KEY_CELL_TYPE
))
145 DbgPrint("Type is %.08x (should be %.08x or %.08x)\n",
146 KeyCell
->Type
, REG_KEY_CELL_TYPE
, REG_ROOT_KEY_CELL_TYPE
);
150 //KeyCell->LastWriteTime;
152 if (KeyCell
->ParentKeyOffset
< 0)
154 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
155 KeyCell
->ParentKeyOffset
);
156 assert(KeyCell
->ParentKeyOffset
>= 0);
159 if (KeyCell
->NumberOfSubKeys
< 0)
161 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
162 KeyCell
->NumberOfSubKeys
);
163 assert(KeyCell
->NumberOfSubKeys
>= 0);
166 //KeyCell->HashTableOffset;
168 if (KeyCell
->NumberOfValues
< 0)
170 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
171 KeyCell
->NumberOfValues
);
172 assert(KeyCell
->NumberOfValues
>= 0);
175 //KeyCell->ValuesOffset = -1;
177 if (KeyCell
->SecurityKeyOffset
< 0)
179 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
180 KeyCell
->SecurityKeyOffset
);
181 assert(KeyCell
->SecurityKeyOffset
>= 0);
184 //KeyCell->ClassNameOffset = -1;
195 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell
)
200 CmiVerifyKeyCell(RootKeyCell
);
202 if (RootKeyCell
->Type
!= REG_ROOT_KEY_CELL_TYPE
)
204 DbgPrint("Type is %.08x (should be %.08x)\n",
205 RootKeyCell
->Type
, REG_ROOT_KEY_CELL_TYPE
);
206 assert(RootKeyCell
->Type
== REG_ROOT_KEY_CELL_TYPE
);
214 CmiVerifyValueCell(PVALUE_CELL ValueCell
)
221 if (ValueCell
->CellSize
== 0)
223 DbgPrint("CellSize is %d (must not be 0)\n",
224 ValueCell
->CellSize
);
225 assert(ValueCell
->CellSize
!= 0);
228 if (ValueCell
->Id
!= REG_VALUE_CELL_ID
)
230 DbgPrint("Id is %.08x (should be %.08x)\n",
231 ValueCell
->Id
, REG_VALUE_CELL_ID
);
232 assert(ValueCell
->Id
== REG_VALUE_CELL_ID
);
235 //ValueCell->NameSize;
236 //ValueCell->LONG DataSize;
237 //ValueCell->DataOffset;
238 //ValueCell->ULONG DataType;
239 //ValueCell->USHORT Flags;
240 //ValueCell->USHORT Unused1;
241 //ValueCell->UCHAR Name[0];
247 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell
)
252 if (ValueListCell
->CellSize
== 0)
254 DbgPrint("CellSize is %d (must not be 0)\n",
255 ValueListCell
->CellSize
);
256 assert(ValueListCell
->CellSize
!= 0);
264 CmiVerifyKeyObject(PKEY_OBJECT KeyObject
)
269 if (KeyObject
->RegistryHive
== NULL
)
271 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
272 KeyObject
->RegistryHive
);
273 assert(KeyObject
->RegistryHive
!= NULL
);
276 if (KeyObject
->KeyCell
== NULL
)
278 DbgPrint("KeyCell is NULL (must not be NULL)\n",
280 assert(KeyObject
->KeyCell
!= NULL
);
283 if (KeyObject
->ParentKey
== NULL
)
285 DbgPrint("ParentKey is NULL (must not be NULL)\n",
286 KeyObject
->ParentKey
);
287 assert(KeyObject
->ParentKey
!= NULL
);
295 CmiVerifyHiveHeader(PHIVE_HEADER Header
)
300 if (Header
->BlockId
!= REG_HIVE_ID
)
302 DbgPrint("BlockId is %.08x (must be %.08x)\n",
305 assert(Header
->BlockId
== REG_HIVE_ID
);
308 if (Header
->Unused3
!= 1)
310 DbgPrint("Unused3 is %.08x (must be 1)\n",
312 assert(Header
->Unused3
== 1);
315 if (Header
->Unused4
!= 3)
317 DbgPrint("Unused4 is %.08x (must be 3)\n",
319 assert(Header
->Unused4
== 3);
322 if (Header
->Unused5
!= 0)
324 DbgPrint("Unused5 is %.08x (must be 0)\n",
326 assert(Header
->Unused5
== 0);
329 if (Header
->Unused6
!= 1)
331 DbgPrint("Unused6 is %.08x (must be 1)\n",
333 assert(Header
->Unused6
== 1);
336 if (Header
->Unused7
!= 1)
338 DbgPrint("Unused7 is %.08x (must be 1)\n",
340 assert(Header
->Unused7
== 1);
348 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive
)
353 CmiVerifyHiveHeader(RegistryHive
->HiveHeader
);
360 CmiPopulateHive(HANDLE FileHandle
)
362 IO_STATUS_BLOCK IoStatusBlock
;
363 LARGE_INTEGER FileOffset
;
364 PCELL_HEADER FreeCell
;
370 tBuf
= (PCHAR
) ExAllocatePool(NonPagedPool
, REG_BLOCK_SIZE
);
372 return STATUS_INSUFFICIENT_RESOURCES
;
374 BinCell
= (PHBIN
) tBuf
;
375 FreeCell
= (PCELL_HEADER
) (tBuf
+ REG_HBIN_DATA_OFFSET
);
377 CmiCreateDefaultBinCell(BinCell
);
379 // The whole block is free
380 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
382 // Add free blocks so we don't need to expand
383 // the file for a while
384 for (i
= 0; i
< 50; i
++)
386 // Block offset of this bin
387 BinCell
->BlockOffset
= (2 + i
) * REG_BLOCK_SIZE
;
389 FileOffset
.u
.HighPart
= 0;
390 FileOffset
.u
.LowPart
= (2 + i
) * REG_BLOCK_SIZE
;
392 Status
= ZwWriteFile(FileHandle
,
401 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
402 if (!NT_SUCCESS(Status
))
416 CmiCreateNewRegFile(HANDLE FileHandle
)
418 IO_STATUS_BLOCK IoStatusBlock
;
419 PCELL_HEADER FreeCell
;
420 PHIVE_HEADER HiveHeader
;
421 PKEY_CELL RootKeyCell
;
426 tBuf
= (PCHAR
) ExAllocatePool(NonPagedPool
, 2 * REG_BLOCK_SIZE
);
428 return STATUS_INSUFFICIENT_RESOURCES
;
430 HiveHeader
= (PHIVE_HEADER
) tBuf
;
431 BinCell
= (PHBIN
) ((ULONG_PTR
) tBuf
+ REG_BLOCK_SIZE
);
432 RootKeyCell
= (PKEY_CELL
) ((ULONG_PTR
) tBuf
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
);
433 FreeCell
= (PCELL_HEADER
) ((ULONG_PTR
) tBuf
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
435 CmiCreateDefaultHiveHeader(HiveHeader
);
436 CmiCreateDefaultBinCell(BinCell
);
437 CmiCreateDefaultRootKeyCell(RootKeyCell
);
440 BinCell
->BlockOffset
= 0;
442 // Offset to root key block
443 HiveHeader
->RootKeyCell
= REG_HBIN_DATA_OFFSET
;
445 // The rest of the block is free
446 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
448 Status
= ZwWriteFile(FileHandle
,
460 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
463 if (NT_SUCCESS(Status
))
465 CmiPopulateHive(FileHandle
);
474 CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive
,
478 OBJECT_ATTRIBUTES ObjectAttributes
;
479 FILE_STANDARD_INFORMATION fsi
;
480 PCELL_HEADER FreeBlock
;
481 LARGE_INTEGER FileOffset
;
482 BLOCK_OFFSET BlockOffset
;
483 ULONG CreateDisposition
;
484 IO_STATUS_BLOCK IoSB
;
492 IO_STATUS_BLOCK Iosb
;
494 DPRINT("CmiInitPermanentRegistryHive(%p, %S, %d) - Entered.\n", RegistryHive
, Filename
, CreateNew
);
496 /* Duplicate Filename */
497 Status
= RtlCreateUnicodeString(&RegistryHive
->Filename
, Filename
);
498 if (!NT_SUCCESS(Status
)) {
499 DPRINT("CmiInitPermanentRegistryHive() - Failed 1.\n");
503 InitializeObjectAttributes(&ObjectAttributes
,
504 &RegistryHive
->Filename
,
510 CreateDisposition
= FILE_OPEN_IF
;
512 CreateDisposition
= FILE_OPEN
;
514 Status
= NtCreateFile(&FileHandle
,
519 FILE_ATTRIBUTE_NORMAL
,
522 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
526 if ((CreateNew
) && (IoSB
.Information
== FILE_CREATED
))
528 Status
= CmiCreateNewRegFile(FileHandle
);
531 if (!NT_SUCCESS(Status
))
533 RtlFreeUnicodeString(&RegistryHive
->Filename
);
534 DPRINT("CmiCreateNewRegFile() - Failed with status %x.\n", Status
);
538 Status
= ObReferenceObjectByHandle(FileHandle
,
542 (PVOID
*) &RegistryHive
->FileObject
,
545 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
547 if (!NT_SUCCESS(Status
))
550 RtlFreeUnicodeString(&RegistryHive
->Filename
);
551 DPRINT("CmiInitPermanentRegistryHive() - ObReferenceObjectByHandle Failed with status %x.\n", Status
);
555 FileOffset
.u
.HighPart
= 0;
556 FileOffset
.u
.LowPart
= 0;
557 DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle
, sizeof(HIVE_HEADER
), RegistryHive
->HiveHeader
);
558 Status
= ZwReadFile(FileHandle
,
564 RegistryHive
->HiveHeader
,
569 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
571 if (!NT_SUCCESS(Status
))
573 ObDereferenceObject(RegistryHive
->FileObject
);
574 RtlFreeUnicodeString(&RegistryHive
->Filename
);
575 DPRINT("CmiInitPermanentRegistryHive() - Failed 4.\n");
579 Status
= ZwQueryInformationFile(FileHandle
,
583 FileStandardInformation
);
585 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
587 if (!NT_SUCCESS(Status
))
589 ObDereferenceObject(RegistryHive
->FileObject
);
590 RtlFreeUnicodeString(&RegistryHive
->Filename
);
591 DPRINT("CmiInitPermanentRegistryHive() - Failed 5.\n");
596 /* We have a reference to the file object so we don't need the handle anymore */
600 RegistryHive
->FileSize
= fsi
.EndOfFile
.u
.LowPart
;
602 // assert(RegistryHive->FileSize);
603 if (RegistryHive
->FileSize
) {
604 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ 4096) - 1;
606 ObDereferenceObject(RegistryHive
->FileObject
);
607 RtlFreeUnicodeString(&RegistryHive
->Filename
);
608 DPRINT("CmiInitPermanentRegistryHive() - Failed, zero length hive file.\n");
609 return STATUS_INSUFFICIENT_RESOURCES
;
612 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ 4096) - 1;
615 DPRINT("Space needed for block list describing hive: 0x%x\n",
616 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
618 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
619 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
621 if (RegistryHive
->BlockList
== NULL
)
623 ExFreePool(RegistryHive
->BlockList
);
624 ObDereferenceObject(RegistryHive
->FileObject
);
625 RtlFreeUnicodeString(&RegistryHive
->Filename
);
626 DPRINT("CmiInitPermanentRegistryHive() - Failed 6.\n");
627 return STATUS_INSUFFICIENT_RESOURCES
;
631 /* Map hive into cache memory (readonly) (skip the base block) */
632 FileOffset
.u
.HighPart
= 0;
633 FileOffset
.u
.LowPart
= 4096;
634 Success
= CcMapData(RegistryHive
->FileObject
, /* File object */
635 &FileOffset
, /* File offset */
636 RegistryHive
->FileSize
- 4096, /* Region length */
637 TRUE
, /* Wait if needed */
638 &RegistryHive
->Bcb
, /* OUT: Buffer Control Block */
639 (PVOID
*) &RegistryHive
->BlockList
[0]); /* OUT: Mapped data pointer */
641 assertmsg(Success
, ("Success: %d\n", Success
));
645 ExFreePool(RegistryHive
->BlockList
);
646 ObDereferenceObject(RegistryHive
->FileObject
);
647 RtlFreeUnicodeString(&RegistryHive
->Filename
);
648 DPRINT("CmiInitPermanentRegistryHive() - Failed 7.\n");
654 RegistryHive
->BlockList
[0] = ExAllocatePool(PagedPool
,
655 RegistryHive
->FileSize
- 4096);
657 RtlZeroMemory(RegistryHive
->BlockList
[0], RegistryHive
->FileSize
- 4096);
660 if (RegistryHive
->BlockList
[0] == NULL
)
662 ExFreePool(RegistryHive
->BlockList
);
663 ObDereferenceObject(RegistryHive
->FileObject
);
664 RtlFreeUnicodeString(&RegistryHive
->Filename
);
665 DPRINT("CmiInitPermanentRegistryHive() - Failed 8.\n");
666 return STATUS_INSUFFICIENT_RESOURCES
;
669 FileOffset
.u
.HighPart
= 0;
670 FileOffset
.u
.LowPart
= 4096;
672 DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle
, RegistryHive
->FileSize
- 4096, (PVOID
)RegistryHive
->BlockList
[0]);
673 Status
= ZwReadFile(FileHandle
,
679 (PVOID
) RegistryHive
->BlockList
[0],
680 RegistryHive
->FileSize
- 4096,
684 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
688 RegistryHive
->FreeListSize
= 0;
689 RegistryHive
->FreeListMax
= 0;
690 RegistryHive
->FreeList
= NULL
;
693 for (i
= 0; i
< RegistryHive
->BlockListSize
; i
++)
695 RegistryHive
->BlockList
[i
] = (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[0]) + BlockOffset
);
696 tmpBin
= (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[i
]));
697 if (tmpBin
->BlockId
!= REG_BIN_ID
)
699 DPRINT("Bad BlockId %x, offset %x\n", tmpBin
->BlockId
, BlockOffset
);
701 return STATUS_INSUFFICIENT_RESOURCES
;
704 assertmsg((tmpBin
->BlockSize
% 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin
->BlockSize
));
706 if (tmpBin
->BlockSize
> 4096)
708 for (j
= 1; j
< tmpBin
->BlockSize
/ 4096; j
++)
710 RegistryHive
->BlockList
[i
+ j
] = RegistryHive
->BlockList
[i
];
715 /* Search free blocks and add to list */
716 FreeOffset
= REG_HBIN_DATA_OFFSET
;
717 while (FreeOffset
< tmpBin
->BlockSize
)
719 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) RegistryHive
->BlockList
[i
] + FreeOffset
);
720 if (FreeBlock
->CellSize
> 0)
722 Status
= CmiAddFree(RegistryHive
,
724 RegistryHive
->BlockList
[i
]->BlockOffset
+ FreeOffset
);
726 if (!NT_SUCCESS(Status
))
732 FreeOffset
+= FreeBlock
->CellSize
;
736 FreeOffset
-= FreeBlock
->CellSize
;
739 BlockOffset
+= tmpBin
->BlockSize
;
742 DPRINT("CmiInitPermanentRegistryHive(%p, %S, %d) - Finished.\n", RegistryHive
, Filename
, CreateNew
);
744 return STATUS_SUCCESS
;
749 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive
)
751 PKEY_CELL RootKeyCell
;
753 RegistryHive
->Flags
|= HIVE_VOLATILE
;
755 CmiCreateDefaultHiveHeader(RegistryHive
->HiveHeader
);
757 RootKeyCell
= (PKEY_CELL
) ExAllocatePool(NonPagedPool
, sizeof(KEY_CELL
));
759 if (RootKeyCell
== NULL
)
760 return STATUS_INSUFFICIENT_RESOURCES
;
762 CmiCreateDefaultRootKeyCell(RootKeyCell
);
764 RegistryHive
->HiveHeader
->RootKeyCell
= (BLOCK_OFFSET
) RootKeyCell
;
766 return STATUS_SUCCESS
;
771 CmiCreateRegistryHive(PWSTR Filename
,
772 PREGISTRY_HIVE
*RegistryHive
,
778 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename
);
780 *RegistryHive
= NULL
;
782 Hive
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_HIVE
));
784 return STATUS_INSUFFICIENT_RESOURCES
;
786 DPRINT("Hive %x\n", Hive
);
788 RtlZeroMemory(Hive
, sizeof(REGISTRY_HIVE
));
790 Hive
->HiveHeader
= (PHIVE_HEADER
)
791 ExAllocatePool(NonPagedPool
, sizeof(HIVE_HEADER
));
793 if (Hive
->HiveHeader
== NULL
)
796 return STATUS_INSUFFICIENT_RESOURCES
;
799 if (Filename
!= NULL
)
801 Status
= CmiInitPermanentRegistryHive(Hive
, Filename
, CreateNew
);
805 Status
= CmiInitVolatileRegistryHive(Hive
);
808 if (!NT_SUCCESS(Status
))
810 ExFreePool(Hive
->HiveHeader
);
815 KeInitializeSemaphore(&Hive
->RegSem
, 1, 1);
817 VERIFY_REGISTRY_HIVE(Hive
);
819 *RegistryHive
= Hive
;
821 DPRINT("CmiCreateRegistryHive(Filename %S) - Finished.\n", Filename
);
823 return(STATUS_SUCCESS
);
828 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive
,
831 PHASH_TABLE_CELL HashBlock
;
832 PKEY_CELL CurSubKeyCell
;
836 VERIFY_KEY_CELL(KeyCell
);
839 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
840 if (HashBlock
== NULL
)
845 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
847 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
849 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
850 HashBlock
->Table
[i
].KeyOffset
,
852 if (MaxName
< CurSubKeyCell
->NameSize
)
854 MaxName
= CurSubKeyCell
->NameSize
;
856 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
860 CmiReleaseBlock(RegistryHive
, HashBlock
);
867 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive
,
870 PHASH_TABLE_CELL HashBlock
;
871 PKEY_CELL CurSubKeyCell
;
875 VERIFY_KEY_CELL(KeyCell
);
878 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
879 if (HashBlock
== NULL
)
884 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
886 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
888 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
889 HashBlock
->Table
[i
].KeyOffset
,
891 if (MaxClass
< CurSubKeyCell
->ClassSize
)
893 MaxClass
= CurSubKeyCell
->ClassSize
;
895 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
899 CmiReleaseBlock(RegistryHive
, HashBlock
);
906 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
909 PVALUE_LIST_CELL ValueListCell
;
910 PVALUE_CELL CurValueCell
;
914 VERIFY_KEY_CELL(KeyCell
);
916 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
918 if (ValueListCell
== NULL
)
923 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
925 CurValueCell
= CmiGetBlock(RegistryHive
,
926 ValueListCell
->Values
[i
],
928 if (CurValueCell
!= NULL
&&
929 MaxValueName
< CurValueCell
->NameSize
)
931 MaxValueName
= CurValueCell
->NameSize
;
933 CmiReleaseBlock(RegistryHive
, CurValueCell
);
936 CmiReleaseBlock(RegistryHive
, ValueListCell
);
943 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
946 PVALUE_LIST_CELL ValueListCell
;
947 PVALUE_CELL CurValueCell
;
951 VERIFY_KEY_CELL(KeyCell
);
953 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
955 if (ValueListCell
== NULL
)
960 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
962 CurValueCell
= CmiGetBlock(RegistryHive
,
963 ValueListCell
->Values
[i
],NULL
);
964 if ((CurValueCell
!= NULL
) &&
965 (MaxValueData
< (CurValueCell
->DataSize
& LONG_MAX
)))
967 MaxValueData
= CurValueCell
->DataSize
& LONG_MAX
;
969 CmiReleaseBlock(RegistryHive
, CurValueCell
);
972 CmiReleaseBlock(RegistryHive
, ValueListCell
);
979 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
980 IN PKEY_CELL KeyCell
,
981 OUT PKEY_CELL
*SubKeyCell
,
982 OUT BLOCK_OFFSET
*BlockOffset
,
984 IN ACCESS_MASK DesiredAccess
,
987 PHASH_TABLE_CELL HashBlock
;
988 PKEY_CELL CurSubKeyCell
;
992 VERIFY_KEY_CELL(KeyCell
);
994 //DPRINT("Scanning for sub key %s\n", KeyName);
996 assert(RegistryHive
);
998 KeyLength
= strlen(KeyName
);
1000 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1002 if (HashBlock
== NULL
)
1004 return STATUS_SUCCESS
;
1007 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
)
1008 && (i
< HashBlock
->HashTableSize
); i
++)
1010 if (Attributes
& OBJ_CASE_INSENSITIVE
)
1012 if ((HashBlock
->Table
[i
].KeyOffset
!= 0) &&
1013 (HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1) &&
1014 (_strnicmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4) == 0))
1016 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1017 HashBlock
->Table
[i
].KeyOffset
,
1019 if ((CurSubKeyCell
->NameSize
== KeyLength
)
1020 && (_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
) == 0))
1022 *SubKeyCell
= CurSubKeyCell
;
1023 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
1028 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1034 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
1035 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
1036 !strncmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4))
1038 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1039 HashBlock
->Table
[i
].KeyOffset
,NULL
);
1040 if (CurSubKeyCell
->NameSize
== KeyLength
1041 && !_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
))
1043 *SubKeyCell
= CurSubKeyCell
;
1044 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
1049 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1055 CmiReleaseBlock(RegistryHive
, HashBlock
);
1057 return STATUS_SUCCESS
;
1062 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
1065 PWSTR NewSubKeyName
,
1066 USHORT NewSubKeyNameSize
,
1068 PUNICODE_STRING Class
,
1069 ULONG CreateOptions
)
1071 PHASH_TABLE_CELL NewHashBlock
;
1072 PHASH_TABLE_CELL HashBlock
;
1073 BLOCK_OFFSET NKBOffset
;
1074 PKEY_CELL NewKeyCell
;
1080 KeyCell
= Parent
->KeyCell
;
1082 VERIFY_KEY_CELL(KeyCell
);
1084 if (NewSubKeyName
[0] == L
'\\')
1087 NameSize
= NewSubKeyNameSize
/ 2 - 1;
1091 NameSize
= NewSubKeyNameSize
/ 2;
1093 Status
= STATUS_SUCCESS
;
1095 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
1096 Status
= CmiAllocateBlock(RegistryHive
,
1097 (PVOID
) &NewKeyCell
,
1101 if (NewKeyCell
== NULL
)
1103 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1107 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
1108 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
1109 ZwQuerySystemTime((PTIME
) &NewKeyCell
->LastWriteTime
);
1110 NewKeyCell
->ParentKeyOffset
= -1;
1111 NewKeyCell
->NumberOfSubKeys
= 0;
1112 NewKeyCell
->HashTableOffset
= -1;
1113 NewKeyCell
->NumberOfValues
= 0;
1114 NewKeyCell
->ValuesOffset
= -1;
1115 NewKeyCell
->SecurityKeyOffset
= -1;
1116 NewKeyCell
->NameSize
= NameSize
;
1117 wcstombs(NewKeyCell
->Name
, NewSubKeyName
, NameSize
);
1118 NewKeyCell
->ClassNameOffset
= -1;
1120 VERIFY_KEY_CELL(NewKeyCell
);
1126 NewKeyCell
->ClassSize
= Class
->Length
+ sizeof(WCHAR
);
1127 Status
= CmiAllocateBlock(RegistryHive
,
1129 NewKeyCell
->ClassSize
,
1130 &NewKeyCell
->ClassNameOffset
);
1131 wcsncpy((PWSTR
) pClass
->Data
, Class
->Buffer
, Class
->Length
);
1132 ((PWSTR
) (pClass
->Data
))[Class
->Length
] = 0;
1136 if (!NT_SUCCESS(Status
))
1141 SubKey
->KeyCell
= NewKeyCell
;
1142 SubKey
->BlockOffset
= NKBOffset
;
1144 /* Don't modify hash table if key is volatile and parent is not */
1145 if (IsVolatileHive(RegistryHive
) && (!IsVolatileHive(Parent
->RegistryHive
)))
1150 if (KeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
1152 Status
= CmiAllocateHashTableBlock(RegistryHive
,
1154 &KeyCell
->HashTableOffset
,
1155 REG_INIT_HASH_TABLE_SIZE
);
1157 if (!NT_SUCCESS(Status
))
1164 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1165 if (((KeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
1167 BLOCK_OFFSET HTOffset
;
1169 /* Reallocate the hash table block */
1170 Status
= CmiAllocateHashTableBlock(RegistryHive
,
1173 HashBlock
->HashTableSize
+
1174 REG_EXTEND_HASH_TABLE_SIZE
);
1176 if (!NT_SUCCESS(Status
))
1181 RtlZeroMemory(&NewHashBlock
->Table
[0],
1182 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
1183 RtlCopyMemory(&NewHashBlock
->Table
[0],
1184 &HashBlock
->Table
[0],
1185 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
1186 CmiDestroyBlock(RegistryHive
, HashBlock
, KeyCell
->HashTableOffset
);
1187 KeyCell
->HashTableOffset
= HTOffset
;
1188 HashBlock
= NewHashBlock
;
1192 Status
= CmiAddKeyToHashTable(RegistryHive
, HashBlock
, NewKeyCell
, NKBOffset
);
1193 if (NT_SUCCESS(Status
))
1195 KeyCell
->NumberOfSubKeys
++;
1203 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
1204 IN PKEY_CELL KeyCell
,
1206 OUT PVALUE_CELL
*ValueCell
,
1207 OUT BLOCK_OFFSET
*VBOffset
)
1209 PVALUE_LIST_CELL ValueListCell
;
1210 PVALUE_CELL CurValueCell
;
1214 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1218 if (ValueListCell
== NULL
)
1220 DPRINT("ValueListCell is NULL\n");
1221 return STATUS_SUCCESS
;
1224 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1226 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1228 CurValueCell
= CmiGetBlock(RegistryHive
,
1229 ValueListCell
->Values
[i
],
1231 /* FIXME: perhaps we must not ignore case if NtCreateKey has not been */
1232 /* called with OBJ_CASE_INSENSITIVE flag ? */
1233 Length
= strlen(ValueName
);
1234 if ((CurValueCell
!= NULL
) &&
1235 (CurValueCell
->NameSize
== Length
) &&
1236 (_strnicmp(CurValueCell
->Name
, ValueName
, Length
) == 0))
1238 *ValueCell
= CurValueCell
;
1240 *VBOffset
= ValueListCell
->Values
[i
];
1241 //DPRINT("Found value %s\n", ValueName);
1244 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1247 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1249 return STATUS_SUCCESS
;
1254 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
1255 IN PKEY_CELL KeyCell
,
1257 OUT PVALUE_CELL
*ValueCell
)
1259 PVALUE_LIST_CELL ValueListCell
;
1260 PVALUE_CELL CurValueCell
;
1262 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1266 if (ValueListCell
== NULL
)
1268 return STATUS_NO_MORE_ENTRIES
;
1271 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1273 if (Index
>= KeyCell
->NumberOfValues
)
1275 return STATUS_NO_MORE_ENTRIES
;
1278 CurValueCell
= CmiGetBlock(RegistryHive
,
1279 ValueListCell
->Values
[Index
],
1282 if (CurValueCell
!= NULL
)
1284 *ValueCell
= CurValueCell
;
1287 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1288 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1290 return STATUS_SUCCESS
;
1295 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
1296 IN PKEY_CELL KeyCell
,
1297 IN PCHAR ValueNameBuf
,
1298 OUT PVALUE_CELL
*pValueCell
,
1299 OUT BLOCK_OFFSET
*pVBOffset
)
1301 PVALUE_LIST_CELL NewValueListCell
;
1302 PVALUE_LIST_CELL ValueListCell
;
1303 PVALUE_CELL NewValueCell
;
1304 BLOCK_OFFSET VLBOffset
;
1305 BLOCK_OFFSET VBOffset
;
1308 Status
= CmiAllocateValueCell(RegistryHive
,
1312 *pVBOffset
= VBOffset
;
1314 if (!NT_SUCCESS(Status
))
1319 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1321 if (ValueListCell
== NULL
)
1323 Status
= CmiAllocateBlock(RegistryHive
,
1324 (PVOID
) &ValueListCell
,
1325 sizeof(BLOCK_OFFSET
) * 3,
1328 if (!NT_SUCCESS(Status
))
1330 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
1333 KeyCell
->ValuesOffset
= VLBOffset
;
1335 else if ((KeyCell
->NumberOfValues
1336 >= (ULONG
) ((LONG
) (ValueListCell
->CellSize
- 4)) / (LONG
) sizeof(BLOCK_OFFSET
)))
1338 Status
= CmiAllocateBlock(RegistryHive
,
1339 (PVOID
) &NewValueListCell
,
1340 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
),
1343 if (!NT_SUCCESS(Status
))
1345 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
1349 RtlCopyMemory(&NewValueListCell
->Values
[0],
1350 &ValueListCell
->Values
[0],
1351 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
1352 CmiDestroyBlock(RegistryHive
, ValueListCell
, KeyCell
->ValuesOffset
);
1353 KeyCell
->ValuesOffset
= VLBOffset
;
1354 ValueListCell
= NewValueListCell
;
1357 DPRINT("KeyCell->NumberOfValues %d, ValueListCell->CellSize %d (%d %x)\n",
1358 KeyCell
->NumberOfValues
, ValueListCell
->CellSize
,
1359 -(ValueListCell
->CellSize
- 4) / sizeof(BLOCK_OFFSET
),
1360 -(ValueListCell
->CellSize
- 4) / sizeof(BLOCK_OFFSET
));
1362 ValueListCell
->Values
[KeyCell
->NumberOfValues
] = VBOffset
;
1363 KeyCell
->NumberOfValues
++;
1364 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1365 CmiReleaseBlock(RegistryHive
, NewValueCell
);
1366 *pValueCell
= NewValueCell
;
1368 return STATUS_SUCCESS
;
1373 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
1374 IN PKEY_CELL KeyCell
,
1377 PVALUE_LIST_CELL ValueListCell
;
1378 PVALUE_CELL CurValueCell
;
1381 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1383 if (ValueListCell
== NULL
)
1385 return STATUS_SUCCESS
;
1388 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1390 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1392 CurValueCell
= CmiGetBlock(RegistryHive
, ValueListCell
->Values
[i
], NULL
);
1393 if ((CurValueCell
!= NULL
) &&
1394 (CurValueCell
->NameSize
== strlen(ValueName
)) &&
1395 (memcmp(CurValueCell
->Name
, ValueName
, strlen(ValueName
)) == 0))
1397 if ((KeyCell
->NumberOfValues
- 1) < i
)
1399 RtlCopyMemory(&ValueListCell
->Values
[i
],
1400 &ValueListCell
->Values
[i
+ 1],
1401 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
1405 RtlZeroMemory(&ValueListCell
->Values
[i
], sizeof(BLOCK_OFFSET
));
1408 KeyCell
->NumberOfValues
-= 1;
1409 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->Values
[i
]);
1412 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1415 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1417 return STATUS_SUCCESS
;
1422 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive
,
1423 OUT PHASH_TABLE_CELL
*HashBlock
,
1424 OUT BLOCK_OFFSET
*HBOffset
,
1425 IN ULONG HashTableSize
)
1427 PHASH_TABLE_CELL NewHashBlock
;
1431 Status
= STATUS_SUCCESS
;
1433 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
1434 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
1435 Status
= CmiAllocateBlock(RegistryHive
,
1436 (PVOID
*) &NewHashBlock
,
1440 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
1442 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1446 NewHashBlock
->Id
= REG_HASH_TABLE_BLOCK_ID
;
1447 NewHashBlock
->HashTableSize
= HashTableSize
;
1448 *HashBlock
= NewHashBlock
;
1456 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
1457 PHASH_TABLE_CELL HashBlock
,
1460 BLOCK_OFFSET KeyOffset
;
1463 if (HashBlock
== NULL
)
1466 if (IsVolatileHive(RegistryHive
))
1468 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
1472 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
1473 KeyCell
= CmiGetBlock(RegistryHive
, KeyOffset
, NULL
);
1475 CmiLockBlock(RegistryHive
, KeyCell
);
1482 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
1483 PHASH_TABLE_CELL HashBlock
,
1484 PKEY_CELL NewKeyCell
,
1485 BLOCK_OFFSET NKBOffset
)
1489 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1491 if (HashBlock
->Table
[i
].KeyOffset
== 0)
1493 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
1494 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
, NewKeyCell
->Name
, 4);
1495 return STATUS_SUCCESS
;
1499 return STATUS_UNSUCCESSFUL
;
1504 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
1505 PVALUE_CELL
*ValueCell
,
1506 BLOCK_OFFSET
*VBOffset
,
1507 IN PCHAR ValueNameBuf
)
1509 PVALUE_CELL NewValueCell
;
1513 Status
= STATUS_SUCCESS
;
1515 NewValueSize
= sizeof(VALUE_CELL
) + strlen(ValueNameBuf
);
1516 Status
= CmiAllocateBlock(RegistryHive
,
1517 (PVOID
*) &NewValueCell
,
1521 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
1523 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1527 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
1528 NewValueCell
->NameSize
= strlen(ValueNameBuf
);
1529 memcpy(NewValueCell
->Name
, ValueNameBuf
, strlen(ValueNameBuf
));
1530 NewValueCell
->DataType
= 0;
1531 NewValueCell
->DataSize
= 0;
1532 NewValueCell
->DataOffset
= 0xffffffff;
1533 *ValueCell
= NewValueCell
;
1541 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
1542 PVALUE_CELL ValueCell
,
1543 BLOCK_OFFSET VBOffset
)
1549 VERIFY_VALUE_CELL(ValueCell
);
1551 /* First, release datas: */
1552 if (ValueCell
->DataSize
> 0)
1554 pBlock
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, &pBin
);
1555 Status
= CmiDestroyBlock(RegistryHive
, pBlock
, ValueCell
->DataOffset
);
1556 if (!NT_SUCCESS(Status
))
1561 /* Update time of heap */
1562 if (IsPermanentHive(RegistryHive
))
1563 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
1566 Status
= CmiDestroyBlock(RegistryHive
, ValueCell
, VBOffset
);
1568 /* Update time of heap */
1569 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, VBOffset
, &pBin
))
1571 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
1579 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
1581 BLOCK_OFFSET
*NewBlockOffset
)
1583 PCELL_HEADER tmpBlock
;
1584 PHBIN
* tmpBlockList
;
1587 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
1590 return STATUS_INSUFFICIENT_RESOURCES
;
1593 tmpBin
->BlockId
= REG_BIN_ID
;
1594 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
1595 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
1596 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
1597 tmpBin
->Unused1
= 0;
1598 ZwQuerySystemTime((PTIME
) &tmpBin
->DateModified
);
1599 tmpBin
->Unused2
= 0;
1601 /* Increase size of list of blocks */
1602 tmpBlockList
= ExAllocatePool(NonPagedPool
,
1603 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
1604 if (tmpBlockList
== NULL
)
1607 return STATUS_INSUFFICIENT_RESOURCES
;
1610 if (RegistryHive
->BlockListSize
> 0)
1612 memcpy(tmpBlockList
,
1613 RegistryHive
->BlockList
,
1614 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
1615 ExFreePool(RegistryHive
->BlockList
);
1618 RegistryHive
->BlockList
= tmpBlockList
;
1619 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
++] = tmpBin
;
1621 /* Initialize a free block in this heap : */
1622 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
1623 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
1624 *NewBlock
= (PVOID
) tmpBlock
;
1627 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
1629 /* FIXME: set first dword to block_offset of another free bloc */
1631 return STATUS_SUCCESS
;
1636 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive
,
1639 BLOCK_OFFSET
* pBlockOffset
)
1641 PCELL_HEADER NewBlock
;
1645 Status
= STATUS_SUCCESS
;
1647 /* Round to 16 bytes multiple */
1648 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
1650 /* Handle volatile hives first */
1651 if (IsVolatileHive(RegistryHive
))
1653 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
1655 if (NewBlock
== NULL
)
1657 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1661 RtlZeroMemory(NewBlock
, BlockSize
);
1662 NewBlock
->CellSize
= BlockSize
;
1663 CmiLockBlock(RegistryHive
, NewBlock
);
1666 *pBlockOffset
= (BLOCK_OFFSET
) NewBlock
;
1673 /* first search in free blocks */
1675 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
1677 if (RegistryHive
->FreeList
[i
]->CellSize
>= BlockSize
)
1680 NewBlock
= RegistryHive
->FreeList
[i
];
1683 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
1685 /* Update time of heap */
1686 Temp
= CmiGetBlock(RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
1689 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
1691 if ((i
+ 1) < RegistryHive
->FreeListSize
)
1693 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
1694 &RegistryHive
->FreeList
[i
+ 1],
1695 sizeof(RegistryHive
->FreeList
[0])
1696 * (RegistryHive
->FreeListSize
- i
- 1));
1697 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
1698 &RegistryHive
->FreeListOffset
[i
+ 1],
1699 sizeof(RegistryHive
->FreeListOffset
[0])
1700 * (RegistryHive
->FreeListSize
- i
- 1));
1702 RegistryHive
->FreeListSize
--;
1707 /* Need to extend hive file : */
1708 if (NewBlock
== NULL
)
1710 /* Add a new block */
1711 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewBlock
, pBlockOffset
);
1714 if (NT_SUCCESS(Status
))
1718 /* Split the block in two parts */
1719 if (NewBlock
->CellSize
> BlockSize
)
1721 NewBlock
= (PCELL_HEADER
) ((ULONG_PTR
) NewBlock
+BlockSize
);
1722 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- BlockSize
;
1723 CmiAddFree(RegistryHive
, NewBlock
, *pBlockOffset
+ BlockSize
);
1725 else if (NewBlock
->CellSize
< BlockSize
)
1727 return STATUS_UNSUCCESSFUL
;
1729 RtlZeroMemory(*Block
, BlockSize
);
1730 ((PCELL_HEADER
) (*Block
))->CellSize
= -BlockSize
;
1731 CmiLockBlock(RegistryHive
, *Block
);
1739 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive
,
1741 BLOCK_OFFSET Offset
)
1746 Status
= STATUS_SUCCESS
;
1748 if (IsVolatileHive(RegistryHive
))
1750 CmiReleaseBlock(RegistryHive
, Block
);
1755 PCELL_HEADER pFree
= Block
;
1757 if (pFree
->CellSize
< 0)
1758 pFree
->CellSize
= -pFree
->CellSize
;
1760 CmiAddFree(RegistryHive
, Block
, Offset
);
1761 CmiReleaseBlock(RegistryHive
, Block
);
1763 /* Update time of heap */
1764 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, Offset
,&pBin
))
1765 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
1767 /* FIXME: Set first dword to block_offset of another free block ? */
1768 /* FIXME: Concatenate with previous and next block if free */
1776 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
1777 PCELL_HEADER FreeBlock
,
1778 BLOCK_OFFSET FreeOffset
)
1780 PCELL_HEADER
*tmpList
;
1781 BLOCK_OFFSET
*tmpListOffset
;
1786 assert(RegistryHive
);
1789 DPRINT("FreeBlock %.08x FreeOffset %.08x\n",
1790 FreeBlock
, FreeOffset
);
1792 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
1795 tmpList
= ExAllocatePool(PagedPool
,
1796 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
1799 if (tmpList
== NULL
)
1800 return STATUS_INSUFFICIENT_RESOURCES
;
1803 tmpListOffset
= ExAllocatePool(PagedPool
,
1804 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
+ 32));
1807 if (tmpListOffset
== NULL
)
1809 ExFreePool(tmpList
);
1810 return STATUS_INSUFFICIENT_RESOURCES
;
1814 if (RegistryHive
->FreeListMax
)
1817 RtlMoveMemory(tmpList
, RegistryHive
->FreeList
,
1818 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
1820 RtlMoveMemory(tmpListOffset
, RegistryHive
->FreeListOffset
,
1821 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
));
1823 ExFreePool(RegistryHive
->FreeList
);
1825 ExFreePool(RegistryHive
->FreeListOffset
);
1829 RegistryHive
->FreeList
= tmpList
;
1830 RegistryHive
->FreeListOffset
= tmpListOffset
;
1831 RegistryHive
->FreeListMax
+= 32;
1836 /* Add new offset to free list, maintaining list in ascending order */
1837 if ((RegistryHive
->FreeListSize
== 0)
1838 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
1841 /* Add to end of list */
1842 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
1843 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
1845 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
1848 /* Add to begin of list */
1849 RtlMoveMemory(&RegistryHive
->FreeList
[1],
1850 &RegistryHive
->FreeList
[0],
1851 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
1852 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
1853 &RegistryHive
->FreeListOffset
[0],
1854 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
1855 RegistryHive
->FreeList
[0] = FreeBlock
;
1856 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
1857 RegistryHive
->FreeListSize
++;
1862 /* Search where to insert */
1864 maxInd
= RegistryHive
->FreeListSize
- 1;
1865 while ((maxInd
- minInd
) > 1)
1867 medInd
= (minInd
+ maxInd
) / 2;
1868 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
1874 /* Insert before maxInd */
1875 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
1876 &RegistryHive
->FreeList
[maxInd
],
1877 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
1878 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
1879 &RegistryHive
->FreeListOffset
[maxInd
],
1880 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
1881 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
1882 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
1883 RegistryHive
->FreeListSize
++;
1887 return STATUS_SUCCESS
;
1892 CmiGetBlock(PREGISTRY_HIVE RegistryHive
,
1893 BLOCK_OFFSET BlockOffset
,
1899 if ((BlockOffset
== 0) || (BlockOffset
== (ULONG_PTR
) -1))
1902 if (IsVolatileHive(RegistryHive
))
1904 return (PVOID
) BlockOffset
;
1910 pBin
= RegistryHive
->BlockList
[BlockOffset
/ 4096];
1913 return ((PVOID
) ((ULONG_PTR
) pBin
+ (BlockOffset
- pBin
->BlockOffset
)));
1919 CmiPrepareForWrite(PREGISTRY_HIVE RegistryHive
,
1922 if (IsVolatileHive(RegistryHive
))
1924 /* No need to do anything special for volatile hives */
1935 CmiLockBlock(PREGISTRY_HIVE RegistryHive
,
1938 if (IsPermanentHive(RegistryHive
))
1940 /* FIXME: Implement */
1946 CmiReleaseBlock(PREGISTRY_HIVE RegistryHive
,
1949 if (IsPermanentHive(RegistryHive
))
1951 /* FIXME: Implement */