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
13 #include <internal/debug.h>
17 BOOLEAN CmiDoVerify
= FALSE
;
20 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header
)
23 RtlZeroMemory(Header
, sizeof(HIVE_HEADER
));
24 Header
->BlockId
= REG_HIVE_ID
;
25 Header
->DateModified
.dwLowDateTime
= 0;
26 Header
->DateModified
.dwHighDateTime
= 0;
33 Header
->RootKeyCell
= 0;
34 Header
->BlockSize
= REG_BLOCK_SIZE
;
41 CmiCreateDefaultBinCell(PHBIN BinCell
)
44 RtlZeroMemory(BinCell
, sizeof(HBIN
));
45 BinCell
->BlockId
= REG_BIN_ID
;
46 BinCell
->DateModified
.dwLowDateTime
= 0;
47 BinCell
->DateModified
.dwHighDateTime
= 0;
48 BinCell
->BlockSize
= REG_BLOCK_SIZE
;
53 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
)
56 RtlZeroMemory(RootKeyCell
, sizeof(KEY_CELL
));
57 RootKeyCell
->CellSize
= -sizeof(KEY_CELL
);
58 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
59 RootKeyCell
->Type
= REG_ROOT_KEY_CELL_TYPE
;
60 ZwQuerySystemTime((PLARGE_INTEGER
) &RootKeyCell
->LastWriteTime
);
61 RootKeyCell
->ParentKeyOffset
= 0;
62 RootKeyCell
->NumberOfSubKeys
= 0;
63 RootKeyCell
->HashTableOffset
= -1;
64 RootKeyCell
->NumberOfValues
= 0;
65 RootKeyCell
->ValuesOffset
= -1;
66 RootKeyCell
->SecurityKeyOffset
= 0;
67 RootKeyCell
->ClassNameOffset
= -1;
68 RootKeyCell
->NameSize
= 0;
69 RootKeyCell
->ClassSize
= 0;
74 CmiVerifyBinCell(PHBIN BinCell
)
81 if (BinCell
->BlockId
!= REG_BIN_ID
)
83 DbgPrint("BlockId is %.08x (should be %.08x)\n",
84 BinCell
->BlockId
, REG_BIN_ID
);
85 assert(BinCell
->BlockId
== REG_BIN_ID
);
88 //BinCell->DateModified.dwLowDateTime
90 //BinCell->DateModified.dwHighDateTime
93 if (BinCell
->BlockSize
!= REG_BLOCK_SIZE
)
95 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
96 BinCell
->BlockSize
, REG_BLOCK_SIZE
);
97 assert(BinCell
->BlockSize
== REG_BLOCK_SIZE
);
105 CmiVerifyKeyCell(PKEY_CELL KeyCell
)
112 if (KeyCell
->CellSize
== 0)
114 DbgPrint("CellSize is %d (must not be 0)\n",
116 assert(KeyCell
->CellSize
!= 0);
119 if (KeyCell
->Id
!= REG_KEY_CELL_ID
)
121 DbgPrint("Id is %.08x (should be %.08x)\n",
122 KeyCell
->Id
, REG_KEY_CELL_ID
);
123 assert(KeyCell
->Id
== REG_KEY_CELL_ID
);
126 if ((KeyCell
->Type
!= REG_KEY_CELL_TYPE
)
127 && (KeyCell
->Type
!= REG_ROOT_KEY_CELL_TYPE
))
129 DbgPrint("Type is %.08x (should be %.08x or %.08x)\n",
130 KeyCell
->Type
, REG_KEY_CELL_TYPE
, REG_ROOT_KEY_CELL_TYPE
);
134 //KeyCell->LastWriteTime;
136 if (KeyCell
->ParentKeyOffset
< 0)
138 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
139 KeyCell
->ParentKeyOffset
);
140 assert(KeyCell
->ParentKeyOffset
>= 0);
143 if (KeyCell
->NumberOfSubKeys
< 0)
145 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
146 KeyCell
->NumberOfSubKeys
);
147 assert(KeyCell
->NumberOfSubKeys
>= 0);
150 //KeyCell->HashTableOffset;
152 if (KeyCell
->NumberOfValues
< 0)
154 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
155 KeyCell
->NumberOfValues
);
156 assert(KeyCell
->NumberOfValues
>= 0);
159 //KeyCell->ValuesOffset = -1;
161 if (KeyCell
->SecurityKeyOffset
< 0)
163 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
164 KeyCell
->SecurityKeyOffset
);
165 assert(KeyCell
->SecurityKeyOffset
>= 0);
168 //KeyCell->ClassNameOffset = -1;
179 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell
)
184 CmiVerifyKeyCell(RootKeyCell
);
186 if (RootKeyCell
->Type
!= REG_ROOT_KEY_CELL_TYPE
)
188 DbgPrint("Type is %.08x (should be %.08x)\n",
189 RootKeyCell
->Type
, REG_ROOT_KEY_CELL_TYPE
);
190 assert(RootKeyCell
->Type
== REG_ROOT_KEY_CELL_TYPE
);
198 CmiVerifyValueCell(PVALUE_CELL ValueCell
)
205 if (ValueCell
->CellSize
== 0)
207 DbgPrint("CellSize is %d (must not be 0)\n",
208 ValueCell
->CellSize
);
209 assert(ValueCell
->CellSize
!= 0);
212 if (ValueCell
->Id
!= REG_VALUE_CELL_ID
)
214 DbgPrint("Id is %.08x (should be %.08x)\n",
215 ValueCell
->Id
, REG_VALUE_CELL_ID
);
216 assert(ValueCell
->Id
== REG_VALUE_CELL_ID
);
219 //ValueCell->NameSize;
220 //ValueCell->LONG DataSize;
221 //ValueCell->DataOffset;
222 //ValueCell->ULONG DataType;
223 //ValueCell->USHORT Flags;
224 //ValueCell->USHORT Unused1;
225 //ValueCell->UCHAR Name[0];
231 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell
)
236 if (ValueListCell
->CellSize
== 0)
238 DbgPrint("CellSize is %d (must not be 0)\n",
239 ValueListCell
->CellSize
);
240 assert(ValueListCell
->CellSize
!= 0);
248 CmiVerifyKeyObject(PKEY_OBJECT KeyObject
)
253 if (KeyObject
->RegistryHive
== NULL
)
255 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
256 KeyObject
->RegistryHive
);
257 assert(KeyObject
->RegistryHive
!= NULL
);
260 if (KeyObject
->KeyCell
== NULL
)
262 DbgPrint("KeyCell is NULL (must not be NULL)\n",
264 assert(KeyObject
->KeyCell
!= NULL
);
267 if (KeyObject
->ParentKey
== NULL
)
269 DbgPrint("ParentKey is NULL (must not be NULL)\n",
270 KeyObject
->ParentKey
);
271 assert(KeyObject
->ParentKey
!= NULL
);
279 CmiVerifyHiveHeader(PHIVE_HEADER Header
)
284 if (Header
->BlockId
!= REG_HIVE_ID
)
286 DbgPrint("BlockId is %.08x (must be %.08x)\n",
289 assert(Header
->BlockId
== REG_HIVE_ID
);
292 if (Header
->Unused3
!= 1)
294 DbgPrint("Unused3 is %.08x (must be 1)\n",
296 assert(Header
->Unused3
== 1);
299 if (Header
->Unused4
!= 3)
301 DbgPrint("Unused4 is %.08x (must be 3)\n",
303 assert(Header
->Unused4
== 3);
306 if (Header
->Unused5
!= 0)
308 DbgPrint("Unused5 is %.08x (must be 0)\n",
310 assert(Header
->Unused5
== 0);
313 if (Header
->Unused6
!= 1)
315 DbgPrint("Unused6 is %.08x (must be 1)\n",
317 assert(Header
->Unused6
== 1);
320 if (Header
->Unused7
!= 1)
322 DbgPrint("Unused7 is %.08x (must be 1)\n",
324 assert(Header
->Unused7
== 1);
332 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive
)
337 CmiVerifyHiveHeader(RegistryHive
->HiveHeader
);
344 CmiPopulateHive(HANDLE FileHandle
)
346 IO_STATUS_BLOCK IoStatusBlock
;
347 LARGE_INTEGER FileOffset
;
348 PCELL_HEADER FreeCell
;
354 tBuf
= (PCHAR
) ExAllocatePool(NonPagedPool
, REG_BLOCK_SIZE
);
356 return STATUS_INSUFFICIENT_RESOURCES
;
358 BinCell
= (PHBIN
) tBuf
;
359 FreeCell
= (PCELL_HEADER
) (tBuf
+ REG_HBIN_DATA_OFFSET
);
361 CmiCreateDefaultBinCell(BinCell
);
363 // The whole block is free
364 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
366 // Add free blocks so we don't need to expand
367 // the file for a while
368 for (i
= 0; i
< 50; i
++)
370 // Block offset of this bin
371 BinCell
->BlockOffset
= (2 + i
) * REG_BLOCK_SIZE
;
373 FileOffset
.u
.HighPart
= 0;
374 FileOffset
.u
.LowPart
= (2 + i
) * REG_BLOCK_SIZE
;
376 Status
= ZwWriteFile(FileHandle
,
385 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
386 if (!NT_SUCCESS(Status
))
400 CmiCreateNewRegFile(HANDLE FileHandle
)
402 IO_STATUS_BLOCK IoStatusBlock
;
403 PCELL_HEADER FreeCell
;
404 PHIVE_HEADER HiveHeader
;
405 PKEY_CELL RootKeyCell
;
410 tBuf
= (PCHAR
) ExAllocatePool(NonPagedPool
, 2 * REG_BLOCK_SIZE
);
412 return STATUS_INSUFFICIENT_RESOURCES
;
414 HiveHeader
= (PHIVE_HEADER
) tBuf
;
415 BinCell
= (PHBIN
) ((ULONG_PTR
) tBuf
+ REG_BLOCK_SIZE
);
416 RootKeyCell
= (PKEY_CELL
) ((ULONG_PTR
) tBuf
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
);
417 FreeCell
= (PCELL_HEADER
) ((ULONG_PTR
) tBuf
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
419 CmiCreateDefaultHiveHeader(HiveHeader
);
420 CmiCreateDefaultBinCell(BinCell
);
421 CmiCreateDefaultRootKeyCell(RootKeyCell
);
424 BinCell
->BlockOffset
= 0;
426 // Offset to root key block
427 HiveHeader
->RootKeyCell
= REG_HBIN_DATA_OFFSET
;
429 // The rest of the block is free
430 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
432 Status
= ZwWriteFile(FileHandle
,
444 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
447 if (NT_SUCCESS(Status
))
449 CmiPopulateHive(FileHandle
);
458 CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive
,
462 OBJECT_ATTRIBUTES ObjectAttributes
;
463 FILE_STANDARD_INFORMATION fsi
;
464 PCELL_HEADER FreeBlock
;
465 LARGE_INTEGER FileOffset
;
466 BLOCK_OFFSET BlockOffset
;
467 ULONG CreateDisposition
;
468 IO_STATUS_BLOCK IoSB
;
476 /* Duplicate Filename */
477 Status
= RtlCreateUnicodeString(&RegistryHive
->Filename
, Filename
);
478 if (!NT_SUCCESS(Status
))
481 InitializeObjectAttributes(&ObjectAttributes
,
482 &RegistryHive
->Filename
,
488 CreateDisposition
= FILE_OPEN_IF
;
490 CreateDisposition
= FILE_OPEN
;
492 Status
= NtCreateFile(&FileHandle
,
497 FILE_ATTRIBUTE_NORMAL
,
500 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
504 if ((CreateNew
) && (IoSB
.Information
== FILE_CREATED
))
506 Status
= CmiCreateNewRegFile(FileHandle
);
509 if (!NT_SUCCESS(Status
))
511 RtlFreeUnicodeString(&RegistryHive
->Filename
);
515 Status
= ObReferenceObjectByHandle(FileHandle
,
519 (PVOID
*) &RegistryHive
->FileObject
,
522 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
524 if (!NT_SUCCESS(Status
))
527 RtlFreeUnicodeString(&RegistryHive
->Filename
);
531 FileOffset
.u
.HighPart
= 0;
532 FileOffset
.u
.LowPart
= 0;
533 Status
= ZwReadFile(FileHandle
,
538 RegistryHive
->HiveHeader
,
543 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
545 if (!NT_SUCCESS(Status
))
547 ObDereferenceObject(RegistryHive
->FileObject
);
548 RtlFreeUnicodeString(&RegistryHive
->Filename
);
552 Status
= ZwQueryInformationFile(FileHandle
,
556 FileStandardInformation
);
558 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
560 if (!NT_SUCCESS(Status
))
562 ObDereferenceObject(RegistryHive
->FileObject
);
563 RtlFreeUnicodeString(&RegistryHive
->Filename
);
567 /* We have a reference to the file object so we don't need the handle anymore */
571 RegistryHive
->FileSize
= fsi
.EndOfFile
.u
.LowPart
;
572 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ 4096) - 1;
574 DPRINT("Space needed for block list describing hive: 0x%x\n",
575 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
577 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
578 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
580 if (RegistryHive
->BlockList
== NULL
)
582 ExFreePool(RegistryHive
->BlockList
);
583 ObDereferenceObject(RegistryHive
->FileObject
);
584 RtlFreeUnicodeString(&RegistryHive
->Filename
);
585 return STATUS_INSUFFICIENT_RESOURCES
;
589 /* Map hive into cache memory (readonly) (skip the base block) */
590 FileOffset
.u
.HighPart
= 0;
591 FileOffset
.u
.LowPart
= 4096;
592 Success
= CcMapData(RegistryHive
->FileObject
, /* File object */
593 &FileOffset
, /* File offset */
594 RegistryHive
->FileSize
- 4096, /* Region length */
595 TRUE
, /* Wait if needed */
596 &RegistryHive
->Bcb
, /* OUT: Buffer Control Block */
597 (PVOID
*) &RegistryHive
->BlockList
[0]); /* OUT: Mapped data pointer */
599 assertmsg(Success
, ("Success: %d\n", Success
));
603 ExFreePool(RegistryHive
->BlockList
);
604 ObDereferenceObject(RegistryHive
->FileObject
);
605 RtlFreeUnicodeString(&RegistryHive
->Filename
);
611 RegistryHive
->BlockList
[0] = ExAllocatePool(PagedPool
,
612 RegistryHive
->FileSize
- 4096);
614 if (RegistryHive
->BlockList
[0] == NULL
)
616 ExFreePool(RegistryHive
->BlockList
);
617 ObDereferenceObject(RegistryHive
->FileObject
);
618 RtlFreeUnicodeString(&RegistryHive
->Filename
);
619 return STATUS_INSUFFICIENT_RESOURCES
;
622 FileOffset
.u
.HighPart
= 0;
623 FileOffset
.u
.LowPart
= 4096;
625 Status
= ZwReadFile(FileHandle
,
630 (PVOID
) RegistryHive
->BlockList
[0],
631 RegistryHive
->FileSize
- 4096,
635 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
639 RegistryHive
->FreeListSize
= 0;
640 RegistryHive
->FreeListMax
= 0;
641 RegistryHive
->FreeList
= NULL
;
644 for (i
= 0; i
< RegistryHive
->BlockListSize
; i
++)
646 RegistryHive
->BlockList
[i
] = (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[0]) + BlockOffset
);
647 tmpBin
= (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[i
]));
648 if (tmpBin
->BlockId
!= REG_BIN_ID
)
650 DPRINT("Bad BlockId %x, offset %x\n", tmpBin
->BlockId
, BlockOffset
);
654 assertmsg((tmpBin
->BlockSize
% 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin
->BlockSize
));
656 if (tmpBin
->BlockSize
> 4096)
658 for (j
= 1; j
< tmpBin
->BlockSize
/ 4096; j
++)
660 RegistryHive
->BlockList
[i
+ j
] = RegistryHive
->BlockList
[i
];
665 /* Search free blocks and add to list */
666 FreeOffset
= REG_HBIN_DATA_OFFSET
;
667 while (FreeOffset
< tmpBin
->BlockSize
)
669 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) RegistryHive
->BlockList
[i
] + FreeOffset
);
670 if (FreeBlock
->CellSize
> 0)
672 Status
= CmiAddFree(RegistryHive
,
674 RegistryHive
->BlockList
[i
]->BlockOffset
+ FreeOffset
);
676 if (!NT_SUCCESS(Status
))
682 FreeOffset
+= FreeBlock
->CellSize
;
686 FreeOffset
-= FreeBlock
->CellSize
;
689 BlockOffset
+= tmpBin
->BlockSize
;
692 return STATUS_SUCCESS
;
697 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive
)
699 PKEY_CELL RootKeyCell
;
701 RegistryHive
->Flags
|= HIVE_VOLATILE
;
703 CmiCreateDefaultHiveHeader(RegistryHive
->HiveHeader
);
705 RootKeyCell
= (PKEY_CELL
) ExAllocatePool(NonPagedPool
, sizeof(KEY_CELL
));
707 if (RootKeyCell
== NULL
)
708 return STATUS_INSUFFICIENT_RESOURCES
;
710 CmiCreateDefaultRootKeyCell(RootKeyCell
);
712 RegistryHive
->HiveHeader
->RootKeyCell
= (BLOCK_OFFSET
) RootKeyCell
;
714 return STATUS_SUCCESS
;
719 CmiCreateRegistryHive(PWSTR Filename
,
720 PREGISTRY_HIVE
*RegistryHive
,
726 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename
);
728 *RegistryHive
= NULL
;
730 Hive
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_HIVE
));
732 return STATUS_INSUFFICIENT_RESOURCES
;
734 DPRINT("Hive %x\n", Hive
);
736 RtlZeroMemory(Hive
, sizeof(REGISTRY_HIVE
));
738 Hive
->HiveHeader
= (PHIVE_HEADER
)
739 ExAllocatePool(NonPagedPool
, sizeof(HIVE_HEADER
));
741 if (Hive
->HiveHeader
== NULL
)
744 return STATUS_INSUFFICIENT_RESOURCES
;
747 if (Filename
!= NULL
)
749 Status
= CmiInitPermanentRegistryHive(Hive
, Filename
, CreateNew
);
753 Status
= CmiInitVolatileRegistryHive(Hive
);
756 if (!NT_SUCCESS(Status
))
758 ExFreePool(Hive
->HiveHeader
);
763 KeInitializeSemaphore(&Hive
->RegSem
, 1, 1);
764 VERIFY_REGISTRY_HIVE(Hive
);
766 *RegistryHive
= Hive
;
768 return(STATUS_SUCCESS
);
773 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive
,
776 PHASH_TABLE_CELL HashBlock
;
777 PKEY_CELL CurSubKeyCell
;
781 VERIFY_KEY_CELL(KeyCell
);
784 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
785 if (HashBlock
== NULL
)
790 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
792 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
794 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
795 HashBlock
->Table
[i
].KeyOffset
,
797 if (MaxName
< CurSubKeyCell
->NameSize
)
799 MaxName
= CurSubKeyCell
->NameSize
;
801 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
805 CmiReleaseBlock(RegistryHive
, HashBlock
);
812 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive
,
815 PHASH_TABLE_CELL HashBlock
;
816 PKEY_CELL CurSubKeyCell
;
820 VERIFY_KEY_CELL(KeyCell
);
823 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
824 if (HashBlock
== NULL
)
829 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
831 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
833 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
834 HashBlock
->Table
[i
].KeyOffset
,
836 if (MaxClass
< CurSubKeyCell
->ClassSize
)
838 MaxClass
= CurSubKeyCell
->ClassSize
;
840 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
844 CmiReleaseBlock(RegistryHive
, HashBlock
);
851 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
854 PVALUE_LIST_CELL ValueListCell
;
855 PVALUE_CELL CurValueCell
;
859 VERIFY_KEY_CELL(KeyCell
);
861 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
863 if (ValueListCell
== NULL
)
868 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
870 CurValueCell
= CmiGetBlock(RegistryHive
,
871 ValueListCell
->Values
[i
],
873 if (CurValueCell
!= NULL
&&
874 MaxValueName
< CurValueCell
->NameSize
)
876 MaxValueName
= CurValueCell
->NameSize
;
878 CmiReleaseBlock(RegistryHive
, CurValueCell
);
881 CmiReleaseBlock(RegistryHive
, ValueListCell
);
888 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
891 PVALUE_LIST_CELL ValueListCell
;
892 PVALUE_CELL CurValueCell
;
896 VERIFY_KEY_CELL(KeyCell
);
898 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
900 if (ValueListCell
== NULL
)
905 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
907 CurValueCell
= CmiGetBlock(RegistryHive
,
908 ValueListCell
->Values
[i
],NULL
);
909 if ((CurValueCell
!= NULL
) &&
910 (MaxValueData
< (CurValueCell
->DataSize
& LONG_MAX
)))
912 MaxValueData
= CurValueCell
->DataSize
& LONG_MAX
;
914 CmiReleaseBlock(RegistryHive
, CurValueCell
);
917 CmiReleaseBlock(RegistryHive
, ValueListCell
);
924 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
925 IN PKEY_CELL KeyCell
,
926 OUT PKEY_CELL
*SubKeyCell
,
927 OUT BLOCK_OFFSET
*BlockOffset
,
929 IN ACCESS_MASK DesiredAccess
,
932 PHASH_TABLE_CELL HashBlock
;
933 PKEY_CELL CurSubKeyCell
;
937 VERIFY_KEY_CELL(KeyCell
);
939 DPRINT("Scanning for sub key %s\n", KeyName
);
941 assert(RegistryHive
);
943 KeyLength
= strlen(KeyName
);
945 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
947 if (HashBlock
== NULL
)
949 return STATUS_SUCCESS
;
952 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
)
953 && (i
< HashBlock
->HashTableSize
); i
++)
955 if (Attributes
& OBJ_CASE_INSENSITIVE
)
957 if ((HashBlock
->Table
[i
].KeyOffset
!= 0) &&
958 (HashBlock
->Table
[i
].KeyOffset
!= -1) &&
959 (_strnicmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4) == 0))
961 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
962 HashBlock
->Table
[i
].KeyOffset
,
964 if ((CurSubKeyCell
->NameSize
== KeyLength
)
965 && (_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
) == 0))
967 *SubKeyCell
= CurSubKeyCell
;
968 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
973 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
979 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
980 HashBlock
->Table
[i
].KeyOffset
!= -1 &&
981 !strncmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4))
983 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
984 HashBlock
->Table
[i
].KeyOffset
,NULL
);
985 if (CurSubKeyCell
->NameSize
== KeyLength
986 && !_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
))
988 *SubKeyCell
= CurSubKeyCell
;
989 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
994 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1000 CmiReleaseBlock(RegistryHive
, HashBlock
);
1002 return STATUS_SUCCESS
;
1007 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
1010 PWSTR NewSubKeyName
,
1011 USHORT NewSubKeyNameSize
,
1013 PUNICODE_STRING Class
,
1014 ULONG CreateOptions
)
1016 PHASH_TABLE_CELL NewHashBlock
;
1017 PHASH_TABLE_CELL HashBlock
;
1018 BLOCK_OFFSET NKBOffset
;
1019 PKEY_CELL NewKeyCell
;
1025 KeyCell
= Parent
->KeyCell
;
1027 VERIFY_KEY_CELL(KeyCell
);
1029 if (NewSubKeyName
[0] == L
'\\')
1032 NameSize
= NewSubKeyNameSize
/ 2 - 1;
1036 NameSize
= NewSubKeyNameSize
/ 2;
1038 Status
= STATUS_SUCCESS
;
1040 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
1041 Status
= CmiAllocateBlock(RegistryHive
,
1042 (PVOID
) &NewKeyCell
,
1046 if (NewKeyCell
== NULL
)
1048 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1052 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
1053 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
1054 ZwQuerySystemTime((PLARGE_INTEGER
) &NewKeyCell
->LastWriteTime
);
1055 NewKeyCell
->ParentKeyOffset
= -1;
1056 NewKeyCell
->NumberOfSubKeys
= 0;
1057 NewKeyCell
->HashTableOffset
= -1;
1058 NewKeyCell
->NumberOfValues
= 0;
1059 NewKeyCell
->ValuesOffset
= -1;
1060 NewKeyCell
->SecurityKeyOffset
= -1;
1061 NewKeyCell
->NameSize
= NameSize
;
1062 wcstombs(NewKeyCell
->Name
, NewSubKeyName
, NameSize
);
1063 NewKeyCell
->ClassNameOffset
= -1;
1065 VERIFY_KEY_CELL(NewKeyCell
);
1071 NewKeyCell
->ClassSize
= Class
->Length
+ sizeof(WCHAR
);
1072 Status
= CmiAllocateBlock(RegistryHive
,
1074 NewKeyCell
->ClassSize
,
1075 &NewKeyCell
->ClassNameOffset
);
1076 wcsncpy((PWSTR
) pClass
->Data
, Class
->Buffer
, Class
->Length
);
1077 ((PWSTR
) (pClass
->Data
))[Class
->Length
] = 0;
1081 if (!NT_SUCCESS(Status
))
1086 SubKey
->KeyCell
= NewKeyCell
;
1087 SubKey
->BlockOffset
= NKBOffset
;
1089 /* Don't modify hash table if key is volatile and parent is not */
1090 if (IsVolatileHive(RegistryHive
) && (!IsVolatileHive(Parent
->RegistryHive
)))
1095 if (KeyCell
->HashTableOffset
== -1)
1097 Status
= CmiAllocateHashTableBlock(RegistryHive
,
1099 &KeyCell
->HashTableOffset
,
1100 REG_INIT_HASH_TABLE_SIZE
);
1102 if (!NT_SUCCESS(Status
))
1109 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1110 if (((KeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
1112 BLOCK_OFFSET HTOffset
;
1114 /* Reallocate the hash table block */
1115 Status
= CmiAllocateHashTableBlock(RegistryHive
,
1118 HashBlock
->HashTableSize
+
1119 REG_EXTEND_HASH_TABLE_SIZE
);
1121 if (!NT_SUCCESS(Status
))
1126 RtlZeroMemory(&NewHashBlock
->Table
[0],
1127 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
1128 RtlCopyMemory(&NewHashBlock
->Table
[0],
1129 &HashBlock
->Table
[0],
1130 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
1131 CmiDestroyBlock(RegistryHive
, HashBlock
, KeyCell
->HashTableOffset
);
1132 KeyCell
->HashTableOffset
= HTOffset
;
1133 HashBlock
= NewHashBlock
;
1137 Status
= CmiAddKeyToHashTable(RegistryHive
, HashBlock
, NewKeyCell
, NKBOffset
);
1138 if (NT_SUCCESS(Status
))
1140 KeyCell
->NumberOfSubKeys
++;
1148 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
1149 IN PKEY_CELL KeyCell
,
1151 OUT PVALUE_CELL
*ValueCell
,
1152 OUT BLOCK_OFFSET
*VBOffset
)
1154 PVALUE_LIST_CELL ValueListCell
;
1155 PVALUE_CELL CurValueCell
;
1159 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1163 if (ValueListCell
== NULL
)
1165 DPRINT("ValueListCell is NULL\n");
1166 return STATUS_SUCCESS
;
1169 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1171 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1173 CurValueCell
= CmiGetBlock(RegistryHive
,
1174 ValueListCell
->Values
[i
],
1176 /* FIXME: perhaps we must not ignore case if NtCreateKey has not been */
1177 /* called with OBJ_CASE_INSENSITIVE flag ? */
1178 Length
= strlen(ValueName
);
1179 if ((CurValueCell
!= NULL
) &&
1180 (CurValueCell
->NameSize
== Length
) &&
1181 (_strnicmp(CurValueCell
->Name
, ValueName
, Length
) == 0))
1183 *ValueCell
= CurValueCell
;
1185 *VBOffset
= ValueListCell
->Values
[i
];
1186 DPRINT("Found value %s\n", ValueName
);
1189 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1192 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1194 return STATUS_SUCCESS
;
1199 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
1200 IN PKEY_CELL KeyCell
,
1202 OUT PVALUE_CELL
*ValueCell
)
1204 PVALUE_LIST_CELL ValueListCell
;
1205 PVALUE_CELL CurValueCell
;
1207 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1211 if (ValueListCell
== NULL
)
1213 return STATUS_NO_MORE_ENTRIES
;
1216 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1218 if (Index
>= KeyCell
->NumberOfValues
)
1220 return STATUS_NO_MORE_ENTRIES
;
1223 CurValueCell
= CmiGetBlock(RegistryHive
,
1224 ValueListCell
->Values
[Index
],
1227 if (CurValueCell
!= NULL
)
1229 *ValueCell
= CurValueCell
;
1232 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1233 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1235 return STATUS_SUCCESS
;
1240 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
1241 IN PKEY_CELL KeyCell
,
1242 IN PCHAR ValueNameBuf
,
1243 OUT PVALUE_CELL
*pValueCell
,
1244 OUT BLOCK_OFFSET
*pVBOffset
)
1246 PVALUE_LIST_CELL NewValueListCell
;
1247 PVALUE_LIST_CELL ValueListCell
;
1248 PVALUE_CELL NewValueCell
;
1249 BLOCK_OFFSET VLBOffset
;
1250 BLOCK_OFFSET VBOffset
;
1253 Status
= CmiAllocateValueCell(RegistryHive
,
1257 *pVBOffset
= VBOffset
;
1259 if (!NT_SUCCESS(Status
))
1264 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1266 if (ValueListCell
== NULL
)
1268 Status
= CmiAllocateBlock(RegistryHive
,
1269 (PVOID
) &ValueListCell
,
1270 sizeof(BLOCK_OFFSET
) * 3,
1273 if (!NT_SUCCESS(Status
))
1275 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
1278 KeyCell
->ValuesOffset
= VLBOffset
;
1280 else if ((KeyCell
->NumberOfValues
1281 >= ((LONG
) (ValueListCell
->CellSize
- 4)) / (LONG
) sizeof(BLOCK_OFFSET
)))
1283 Status
= CmiAllocateBlock(RegistryHive
,
1284 (PVOID
) &NewValueListCell
,
1285 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
),
1288 if (!NT_SUCCESS(Status
))
1290 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
1294 RtlCopyMemory(&NewValueListCell
->Values
[0],
1295 &ValueListCell
->Values
[0],
1296 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
1297 CmiDestroyBlock(RegistryHive
, ValueListCell
, KeyCell
->ValuesOffset
);
1298 KeyCell
->ValuesOffset
= VLBOffset
;
1299 ValueListCell
= NewValueListCell
;
1302 DPRINT("KeyCell->NumberOfValues %d, ValueListCell->CellSize %d (%d %x)\n",
1303 KeyCell
->NumberOfValues
, ValueListCell
->CellSize
,
1304 -(ValueListCell
->CellSize
- 4) / sizeof(BLOCK_OFFSET
),
1305 -(ValueListCell
->CellSize
- 4) / sizeof(BLOCK_OFFSET
));
1307 ValueListCell
->Values
[KeyCell
->NumberOfValues
] = VBOffset
;
1308 KeyCell
->NumberOfValues
++;
1309 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1310 CmiReleaseBlock(RegistryHive
, NewValueCell
);
1311 *pValueCell
= NewValueCell
;
1313 return STATUS_SUCCESS
;
1318 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
1319 IN PKEY_CELL KeyCell
,
1322 PVALUE_LIST_CELL ValueListCell
;
1323 PVALUE_CELL CurValueCell
;
1326 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1328 if (ValueListCell
== NULL
)
1330 return STATUS_SUCCESS
;
1333 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1335 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1337 CurValueCell
= CmiGetBlock(RegistryHive
, ValueListCell
->Values
[i
], NULL
);
1338 if ((CurValueCell
!= NULL
) &&
1339 (CurValueCell
->NameSize
== strlen(ValueName
)) &&
1340 (memcmp(CurValueCell
->Name
, ValueName
, strlen(ValueName
)) == 0))
1342 if ((KeyCell
->NumberOfValues
- 1) < i
)
1344 RtlCopyMemory(&ValueListCell
->Values
[i
],
1345 &ValueListCell
->Values
[i
+ 1],
1346 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
1350 RtlZeroMemory(&ValueListCell
->Values
[i
], sizeof(BLOCK_OFFSET
));
1353 KeyCell
->NumberOfValues
-= 1;
1354 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->Values
[i
]);
1357 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1360 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1362 return STATUS_SUCCESS
;
1367 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive
,
1368 OUT PHASH_TABLE_CELL
*HashBlock
,
1369 OUT BLOCK_OFFSET
*HBOffset
,
1370 IN ULONG HashTableSize
)
1372 PHASH_TABLE_CELL NewHashBlock
;
1376 Status
= STATUS_SUCCESS
;
1378 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
1379 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
1380 Status
= CmiAllocateBlock(RegistryHive
,
1381 (PVOID
*) &NewHashBlock
,
1385 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
1387 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1391 NewHashBlock
->Id
= REG_HASH_TABLE_BLOCK_ID
;
1392 NewHashBlock
->HashTableSize
= HashTableSize
;
1393 *HashBlock
= NewHashBlock
;
1401 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
1402 PHASH_TABLE_CELL HashBlock
,
1405 BLOCK_OFFSET KeyOffset
;
1408 if (HashBlock
== NULL
)
1411 if (IsVolatileHive(RegistryHive
))
1413 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
1417 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
1418 KeyCell
= CmiGetBlock(RegistryHive
, KeyOffset
, NULL
);
1420 CmiLockBlock(RegistryHive
, KeyCell
);
1427 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
1428 PHASH_TABLE_CELL HashBlock
,
1429 PKEY_CELL NewKeyCell
,
1430 BLOCK_OFFSET NKBOffset
)
1434 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1436 if (HashBlock
->Table
[i
].KeyOffset
== 0)
1438 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
1439 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
, NewKeyCell
->Name
, 4);
1440 return STATUS_SUCCESS
;
1444 return STATUS_UNSUCCESSFUL
;
1449 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
1450 PVALUE_CELL
*ValueCell
,
1451 BLOCK_OFFSET
*VBOffset
,
1452 IN PCHAR ValueNameBuf
)
1454 PVALUE_CELL NewValueCell
;
1458 Status
= STATUS_SUCCESS
;
1460 NewValueSize
= sizeof(VALUE_CELL
) + strlen(ValueNameBuf
);
1461 Status
= CmiAllocateBlock(RegistryHive
,
1462 (PVOID
*) &NewValueCell
,
1466 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
1468 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1472 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
1473 NewValueCell
->NameSize
= strlen(ValueNameBuf
);
1474 memcpy(NewValueCell
->Name
, ValueNameBuf
, strlen(ValueNameBuf
));
1475 NewValueCell
->DataType
= 0;
1476 NewValueCell
->DataSize
= 0;
1477 NewValueCell
->DataOffset
= 0xffffffff;
1478 *ValueCell
= NewValueCell
;
1486 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
1487 PVALUE_CELL ValueCell
,
1488 BLOCK_OFFSET VBOffset
)
1494 VERIFY_VALUE_CELL(ValueCell
);
1496 /* First, release datas: */
1497 if (ValueCell
->DataSize
> 0)
1499 pBlock
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, &pBin
);
1500 Status
= CmiDestroyBlock(RegistryHive
, pBlock
, ValueCell
->DataOffset
);
1501 if (!NT_SUCCESS(Status
))
1506 /* Update time of heap */
1507 if (IsPermanentHive(RegistryHive
))
1508 ZwQuerySystemTime((PLARGE_INTEGER
) &pBin
->DateModified
);
1511 Status
= CmiDestroyBlock(RegistryHive
, ValueCell
, VBOffset
);
1513 /* Update time of heap */
1514 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, VBOffset
, &pBin
))
1516 ZwQuerySystemTime((PLARGE_INTEGER
) &pBin
->DateModified
);
1524 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
1526 BLOCK_OFFSET
*NewBlockOffset
)
1528 PCELL_HEADER tmpBlock
;
1529 PHBIN
* tmpBlockList
;
1532 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
1535 return STATUS_INSUFFICIENT_RESOURCES
;
1538 tmpBin
->BlockId
= REG_BIN_ID
;
1539 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
1540 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
1541 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
1542 tmpBin
->Unused1
= 0;
1543 ZwQuerySystemTime((PLARGE_INTEGER
) &tmpBin
->DateModified
);
1544 tmpBin
->Unused2
= 0;
1546 /* Increase size of list of blocks */
1547 tmpBlockList
= ExAllocatePool(NonPagedPool
,
1548 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
1549 if (tmpBlockList
== NULL
)
1552 return STATUS_INSUFFICIENT_RESOURCES
;
1555 if (RegistryHive
->BlockListSize
> 0)
1557 memcpy(tmpBlockList
,
1558 RegistryHive
->BlockList
,
1559 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
1560 ExFreePool(RegistryHive
->BlockList
);
1563 RegistryHive
->BlockList
= tmpBlockList
;
1564 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
++] = tmpBin
;
1566 /* Initialize a free block in this heap : */
1567 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
1568 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
1569 *NewBlock
= (PVOID
) tmpBlock
;
1572 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
1574 /* FIXME: set first dword to block_offset of another free bloc */
1576 return STATUS_SUCCESS
;
1581 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive
,
1584 BLOCK_OFFSET
* pBlockOffset
)
1586 PCELL_HEADER NewBlock
;
1590 Status
= STATUS_SUCCESS
;
1592 /* Round to 16 bytes multiple */
1593 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
1595 /* Handle volatile hives first */
1596 if (IsVolatileHive(RegistryHive
))
1598 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
1600 if (NewBlock
== NULL
)
1602 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1606 RtlZeroMemory(NewBlock
, BlockSize
);
1607 NewBlock
->CellSize
= BlockSize
;
1608 CmiLockBlock(RegistryHive
, NewBlock
);
1611 *pBlockOffset
= (BLOCK_OFFSET
) NewBlock
;
1618 /* first search in free blocks */
1620 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
1622 if (RegistryHive
->FreeList
[i
]->CellSize
>= BlockSize
)
1625 NewBlock
= RegistryHive
->FreeList
[i
];
1628 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
1630 /* Update time of heap */
1631 Temp
= CmiGetBlock(RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
1634 ZwQuerySystemTime((PLARGE_INTEGER
) &pBin
->DateModified
);
1636 if ((i
+ 1) < RegistryHive
->FreeListSize
)
1638 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
1639 &RegistryHive
->FreeList
[i
+ 1],
1640 sizeof(RegistryHive
->FreeList
[0])
1641 * (RegistryHive
->FreeListSize
- i
- 1));
1642 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
1643 &RegistryHive
->FreeListOffset
[i
+ 1],
1644 sizeof(RegistryHive
->FreeListOffset
[0])
1645 * (RegistryHive
->FreeListSize
- i
- 1));
1647 RegistryHive
->FreeListSize
--;
1652 /* Need to extend hive file : */
1653 if (NewBlock
== NULL
)
1655 /* Add a new block */
1656 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewBlock
, pBlockOffset
);
1659 if (NT_SUCCESS(Status
))
1663 /* Split the block in two parts */
1664 if (NewBlock
->CellSize
> BlockSize
)
1666 NewBlock
= (PCELL_HEADER
) ((ULONG_PTR
) NewBlock
+BlockSize
);
1667 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- BlockSize
;
1668 CmiAddFree(RegistryHive
, NewBlock
, *pBlockOffset
+ BlockSize
);
1670 else if (NewBlock
->CellSize
< BlockSize
)
1672 return STATUS_UNSUCCESSFUL
;
1674 RtlZeroMemory(*Block
, BlockSize
);
1675 ((PCELL_HEADER
) (*Block
))->CellSize
= -BlockSize
;
1676 CmiLockBlock(RegistryHive
, *Block
);
1684 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive
,
1686 BLOCK_OFFSET Offset
)
1691 Status
= STATUS_SUCCESS
;
1693 if (IsVolatileHive(RegistryHive
))
1695 CmiReleaseBlock(RegistryHive
, Block
);
1700 PCELL_HEADER pFree
= Block
;
1702 if (pFree
->CellSize
< 0)
1703 pFree
->CellSize
= -pFree
->CellSize
;
1705 CmiAddFree(RegistryHive
, Block
, Offset
);
1706 CmiReleaseBlock(RegistryHive
, Block
);
1708 /* Update time of heap */
1709 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, Offset
,&pBin
))
1710 ZwQuerySystemTime((PLARGE_INTEGER
) &pBin
->DateModified
);
1712 /* FIXME: Set first dword to block_offset of another free block ? */
1713 /* FIXME: Concatenate with previous and next block if free */
1721 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
1722 PCELL_HEADER FreeBlock
,
1723 BLOCK_OFFSET FreeOffset
)
1725 PCELL_HEADER
*tmpList
;
1726 BLOCK_OFFSET
*tmpListOffset
;
1731 assert(RegistryHive
);
1734 DPRINT("FreeBlock %.08x FreeOffset %.08x\n",
1735 FreeBlock
, FreeOffset
);
1737 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
1740 tmpList
= ExAllocatePool(PagedPool
,
1741 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
1744 if (tmpList
== NULL
)
1745 return STATUS_INSUFFICIENT_RESOURCES
;
1748 tmpListOffset
= ExAllocatePool(PagedPool
,
1749 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
+ 32));
1752 if (tmpListOffset
== NULL
)
1754 ExFreePool(tmpList
);
1755 return STATUS_INSUFFICIENT_RESOURCES
;
1759 if (RegistryHive
->FreeListMax
)
1762 RtlMoveMemory(tmpList
, RegistryHive
->FreeList
,
1763 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
1765 RtlMoveMemory(tmpListOffset
, RegistryHive
->FreeListOffset
,
1766 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
));
1768 ExFreePool(RegistryHive
->FreeList
);
1770 ExFreePool(RegistryHive
->FreeListOffset
);
1774 RegistryHive
->FreeList
= tmpList
;
1775 RegistryHive
->FreeListOffset
= tmpListOffset
;
1776 RegistryHive
->FreeListMax
+= 32;
1781 /* Add new offset to free list, maintaining list in ascending order */
1782 if ((RegistryHive
->FreeListSize
== 0)
1783 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
1786 /* Add to end of list */
1787 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
1788 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
1790 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
1793 /* Add to begin of list */
1794 RtlMoveMemory(&RegistryHive
->FreeList
[1],
1795 &RegistryHive
->FreeList
[0],
1796 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
1797 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
1798 &RegistryHive
->FreeListOffset
[0],
1799 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
1800 RegistryHive
->FreeList
[0] = FreeBlock
;
1801 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
1802 RegistryHive
->FreeListSize
++;
1807 /* Search where to insert */
1809 maxInd
= RegistryHive
->FreeListSize
- 1;
1810 while ((maxInd
- minInd
) > 1)
1812 medInd
= (minInd
+ maxInd
) / 2;
1813 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
1819 /* Insert before maxInd */
1820 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
1821 &RegistryHive
->FreeList
[maxInd
],
1822 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
1823 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
1824 &RegistryHive
->FreeListOffset
[maxInd
],
1825 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
1826 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
1827 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
1828 RegistryHive
->FreeListSize
++;
1832 return STATUS_SUCCESS
;
1837 CmiGetBlock(PREGISTRY_HIVE RegistryHive
,
1838 BLOCK_OFFSET BlockOffset
,
1844 if ((BlockOffset
== 0) || (BlockOffset
== -1))
1847 if (IsVolatileHive(RegistryHive
))
1849 return (PVOID
) BlockOffset
;
1855 pBin
= RegistryHive
->BlockList
[BlockOffset
/ 4096];
1858 return ((PVOID
) ((ULONG_PTR
) pBin
+ (BlockOffset
- pBin
->BlockOffset
)));
1864 CmiPrepareForWrite(PREGISTRY_HIVE RegistryHive
,
1867 if (IsVolatileHive(RegistryHive
))
1869 /* No need to do anything special for volatile hives */
1880 CmiLockBlock(PREGISTRY_HIVE RegistryHive
,
1883 if (IsPermanentHive(RegistryHive
))
1885 /* FIXME: Implement */
1891 CmiReleaseBlock(PREGISTRY_HIVE RegistryHive
,
1894 if (IsPermanentHive(RegistryHive
))
1896 /* FIXME: Implement */