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
10 #include <ddk/ntifs.h>
12 #include <internal/ob.h>
15 #include <internal/pool.h>
16 #include <internal/registry.h>
19 #include <internal/debug.h>
25 BOOLEAN CmiDoVerify
= FALSE
;
28 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header
)
31 RtlZeroMemory(Header
, sizeof(HIVE_HEADER
));
32 Header
->BlockId
= REG_HIVE_ID
;
33 Header
->DateModified
.dwLowDateTime
= 0;
34 Header
->DateModified
.dwHighDateTime
= 0;
41 Header
->RootKeyCell
= 0;
42 Header
->BlockSize
= REG_BLOCK_SIZE
;
49 CmiCreateDefaultBinCell(PHBIN BinCell
)
52 RtlZeroMemory(BinCell
, sizeof(HBIN
));
53 BinCell
->BlockId
= REG_BIN_ID
;
54 BinCell
->DateModified
.dwLowDateTime
= 0;
55 BinCell
->DateModified
.dwHighDateTime
= 0;
56 BinCell
->BlockSize
= REG_BLOCK_SIZE
;
61 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
)
64 RtlZeroMemory(RootKeyCell
, sizeof(KEY_CELL
));
65 RootKeyCell
->CellSize
= -sizeof(KEY_CELL
);
66 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
67 RootKeyCell
->Type
= REG_ROOT_KEY_CELL_TYPE
;
68 ZwQuerySystemTime((PTIME
) &RootKeyCell
->LastWriteTime
);
69 RootKeyCell
->ParentKeyOffset
= 0;
70 RootKeyCell
->NumberOfSubKeys
= 0;
71 RootKeyCell
->HashTableOffset
= -1;
72 RootKeyCell
->NumberOfValues
= 0;
73 RootKeyCell
->ValuesOffset
= -1;
74 RootKeyCell
->SecurityKeyOffset
= 0;
75 RootKeyCell
->ClassNameOffset
= -1;
76 RootKeyCell
->NameSize
= 0;
77 RootKeyCell
->ClassSize
= 0;
82 CmiVerifyBinCell(PHBIN BinCell
)
89 if (BinCell
->BlockId
!= REG_BIN_ID
)
91 DbgPrint("BlockId is %.08x (should be %.08x)\n",
92 BinCell
->BlockId
, REG_BIN_ID
);
93 assert(BinCell
->BlockId
== REG_BIN_ID
);
96 //BinCell->DateModified.dwLowDateTime
98 //BinCell->DateModified.dwHighDateTime
101 if (BinCell
->BlockSize
!= REG_BLOCK_SIZE
)
103 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
104 BinCell
->BlockSize
, REG_BLOCK_SIZE
);
105 assert(BinCell
->BlockSize
== REG_BLOCK_SIZE
);
113 CmiVerifyKeyCell(PKEY_CELL KeyCell
)
120 if (KeyCell
->CellSize
== 0)
122 DbgPrint("CellSize is %d (must not be 0)\n",
124 assert(KeyCell
->CellSize
!= 0);
127 if (KeyCell
->Id
!= REG_KEY_CELL_ID
)
129 DbgPrint("Id is %.08x (should be %.08x)\n",
130 KeyCell
->Id
, REG_KEY_CELL_ID
);
131 assert(KeyCell
->Id
== REG_KEY_CELL_ID
);
134 if ((KeyCell
->Type
!= REG_KEY_CELL_TYPE
)
135 && (KeyCell
->Type
!= REG_ROOT_KEY_CELL_TYPE
))
137 DbgPrint("Type is %.08x (should be %.08x or %.08x)\n",
138 KeyCell
->Type
, REG_KEY_CELL_TYPE
, REG_ROOT_KEY_CELL_TYPE
);
142 //KeyCell->LastWriteTime;
144 if (KeyCell
->ParentKeyOffset
< 0)
146 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
147 KeyCell
->ParentKeyOffset
);
148 assert(KeyCell
->ParentKeyOffset
>= 0);
151 if (KeyCell
->NumberOfSubKeys
< 0)
153 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
154 KeyCell
->NumberOfSubKeys
);
155 assert(KeyCell
->NumberOfSubKeys
>= 0);
158 //KeyCell->HashTableOffset;
160 if (KeyCell
->NumberOfValues
< 0)
162 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
163 KeyCell
->NumberOfValues
);
164 assert(KeyCell
->NumberOfValues
>= 0);
167 //KeyCell->ValuesOffset = -1;
169 if (KeyCell
->SecurityKeyOffset
< 0)
171 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
172 KeyCell
->SecurityKeyOffset
);
173 assert(KeyCell
->SecurityKeyOffset
>= 0);
176 //KeyCell->ClassNameOffset = -1;
187 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell
)
192 CmiVerifyKeyCell(RootKeyCell
);
194 if (RootKeyCell
->Type
!= REG_ROOT_KEY_CELL_TYPE
)
196 DbgPrint("Type is %.08x (should be %.08x)\n",
197 RootKeyCell
->Type
, REG_ROOT_KEY_CELL_TYPE
);
198 assert(RootKeyCell
->Type
== REG_ROOT_KEY_CELL_TYPE
);
206 CmiVerifyValueCell(PVALUE_CELL ValueCell
)
213 if (ValueCell
->CellSize
== 0)
215 DbgPrint("CellSize is %d (must not be 0)\n",
216 ValueCell
->CellSize
);
217 assert(ValueCell
->CellSize
!= 0);
220 if (ValueCell
->Id
!= REG_VALUE_CELL_ID
)
222 DbgPrint("Id is %.08x (should be %.08x)\n",
223 ValueCell
->Id
, REG_VALUE_CELL_ID
);
224 assert(ValueCell
->Id
== REG_VALUE_CELL_ID
);
227 //ValueCell->NameSize;
228 //ValueCell->LONG DataSize;
229 //ValueCell->DataOffset;
230 //ValueCell->ULONG DataType;
231 //ValueCell->USHORT Flags;
232 //ValueCell->USHORT Unused1;
233 //ValueCell->UCHAR Name[0];
239 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell
)
244 if (ValueListCell
->CellSize
== 0)
246 DbgPrint("CellSize is %d (must not be 0)\n",
247 ValueListCell
->CellSize
);
248 assert(ValueListCell
->CellSize
!= 0);
256 CmiVerifyKeyObject(PKEY_OBJECT KeyObject
)
261 if (KeyObject
->RegistryHive
== NULL
)
263 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
264 KeyObject
->RegistryHive
);
265 assert(KeyObject
->RegistryHive
!= NULL
);
268 if (KeyObject
->KeyCell
== NULL
)
270 DbgPrint("KeyCell is NULL (must not be NULL)\n",
272 assert(KeyObject
->KeyCell
!= NULL
);
275 if (KeyObject
->ParentKey
== NULL
)
277 DbgPrint("ParentKey is NULL (must not be NULL)\n",
278 KeyObject
->ParentKey
);
279 assert(KeyObject
->ParentKey
!= NULL
);
287 CmiVerifyHiveHeader(PHIVE_HEADER Header
)
292 if (Header
->BlockId
!= REG_HIVE_ID
)
294 DbgPrint("BlockId is %.08x (must be %.08x)\n",
297 assert(Header
->BlockId
== REG_HIVE_ID
);
300 if (Header
->Unused3
!= 1)
302 DbgPrint("Unused3 is %.08x (must be 1)\n",
304 assert(Header
->Unused3
== 1);
307 if (Header
->Unused4
!= 3)
309 DbgPrint("Unused4 is %.08x (must be 3)\n",
311 assert(Header
->Unused4
== 3);
314 if (Header
->Unused5
!= 0)
316 DbgPrint("Unused5 is %.08x (must be 0)\n",
318 assert(Header
->Unused5
== 0);
321 if (Header
->Unused6
!= 1)
323 DbgPrint("Unused6 is %.08x (must be 1)\n",
325 assert(Header
->Unused6
== 1);
328 if (Header
->Unused7
!= 1)
330 DbgPrint("Unused7 is %.08x (must be 1)\n",
332 assert(Header
->Unused7
== 1);
340 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive
)
345 CmiVerifyHiveHeader(RegistryHive
->HiveHeader
);
352 CmiPopulateHive(HANDLE FileHandle
)
354 IO_STATUS_BLOCK IoStatusBlock
;
355 LARGE_INTEGER FileOffset
;
356 PCELL_HEADER FreeCell
;
362 tBuf
= (PCHAR
) ExAllocatePool(NonPagedPool
, REG_BLOCK_SIZE
);
364 return STATUS_INSUFFICIENT_RESOURCES
;
366 BinCell
= (PHBIN
) tBuf
;
367 FreeCell
= (PCELL_HEADER
) (tBuf
+ REG_HBIN_DATA_OFFSET
);
369 CmiCreateDefaultBinCell(BinCell
);
371 // The whole block is free
372 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
374 // Add free blocks so we don't need to expand
375 // the file for a while
376 for (i
= 0; i
< 50; i
++)
378 // Block offset of this bin
379 BinCell
->BlockOffset
= (2 + i
) * REG_BLOCK_SIZE
;
381 FileOffset
.u
.HighPart
= 0;
382 FileOffset
.u
.LowPart
= (2 + i
) * REG_BLOCK_SIZE
;
384 Status
= ZwWriteFile(FileHandle
,
393 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
394 if (!NT_SUCCESS(Status
))
408 CmiCreateNewRegFile(HANDLE FileHandle
)
410 IO_STATUS_BLOCK IoStatusBlock
;
411 PCELL_HEADER FreeCell
;
412 PHIVE_HEADER HiveHeader
;
413 PKEY_CELL RootKeyCell
;
418 tBuf
= (PCHAR
) ExAllocatePool(NonPagedPool
, 2 * REG_BLOCK_SIZE
);
420 return STATUS_INSUFFICIENT_RESOURCES
;
422 HiveHeader
= (PHIVE_HEADER
) tBuf
;
423 BinCell
= (PHBIN
) ((ULONG_PTR
) tBuf
+ REG_BLOCK_SIZE
);
424 RootKeyCell
= (PKEY_CELL
) ((ULONG_PTR
) tBuf
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
);
425 FreeCell
= (PCELL_HEADER
) ((ULONG_PTR
) tBuf
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
427 CmiCreateDefaultHiveHeader(HiveHeader
);
428 CmiCreateDefaultBinCell(BinCell
);
429 CmiCreateDefaultRootKeyCell(RootKeyCell
);
432 BinCell
->BlockOffset
= 0;
434 // Offset to root key block
435 HiveHeader
->RootKeyCell
= REG_HBIN_DATA_OFFSET
;
437 // The rest of the block is free
438 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
440 Status
= ZwWriteFile(FileHandle
,
452 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
455 if (NT_SUCCESS(Status
))
457 CmiPopulateHive(FileHandle
);
466 CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive
,
470 OBJECT_ATTRIBUTES ObjectAttributes
;
471 FILE_STANDARD_INFORMATION fsi
;
472 PCELL_HEADER FreeBlock
;
473 LARGE_INTEGER FileOffset
;
474 BLOCK_OFFSET BlockOffset
;
475 ULONG CreateDisposition
;
476 IO_STATUS_BLOCK IoSB
;
484 /* Duplicate Filename */
485 Status
= RtlCreateUnicodeString(&RegistryHive
->Filename
, Filename
);
486 if (!NT_SUCCESS(Status
))
489 InitializeObjectAttributes(&ObjectAttributes
,
490 &RegistryHive
->Filename
,
496 CreateDisposition
= FILE_OPEN_IF
;
498 CreateDisposition
= FILE_OPEN
;
500 Status
= NtCreateFile(&FileHandle
,
505 FILE_ATTRIBUTE_NORMAL
,
508 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
512 if ((CreateNew
) && (IoSB
.Information
== FILE_CREATED
))
514 Status
= CmiCreateNewRegFile(FileHandle
);
517 if (!NT_SUCCESS(Status
))
519 RtlFreeUnicodeString(&RegistryHive
->Filename
);
523 Status
= ObReferenceObjectByHandle(FileHandle
,
527 (PVOID
*) &RegistryHive
->FileObject
,
530 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
532 if (!NT_SUCCESS(Status
))
535 RtlFreeUnicodeString(&RegistryHive
->Filename
);
539 FileOffset
.u
.HighPart
= 0;
540 FileOffset
.u
.LowPart
= 0;
541 Status
= ZwReadFile(FileHandle
,
546 RegistryHive
->HiveHeader
,
551 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
553 if (!NT_SUCCESS(Status
))
555 ObDereferenceObject(RegistryHive
->FileObject
);
556 RtlFreeUnicodeString(&RegistryHive
->Filename
);
560 Status
= ZwQueryInformationFile(FileHandle
,
564 FileStandardInformation
);
566 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
568 if (!NT_SUCCESS(Status
))
570 ObDereferenceObject(RegistryHive
->FileObject
);
571 RtlFreeUnicodeString(&RegistryHive
->Filename
);
575 /* We have a reference to the file object so we don't need the handle anymore */
579 RegistryHive
->FileSize
= fsi
.EndOfFile
.u
.LowPart
;
580 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ 4096) - 1;
582 DPRINT("Space needed for block list describing hive: 0x%x\n",
583 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
585 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
586 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
588 if (RegistryHive
->BlockList
== NULL
)
590 ExFreePool(RegistryHive
->BlockList
);
591 ObDereferenceObject(RegistryHive
->FileObject
);
592 RtlFreeUnicodeString(&RegistryHive
->Filename
);
593 return STATUS_INSUFFICIENT_RESOURCES
;
597 /* Map hive into cache memory (readonly) (skip the base block) */
598 FileOffset
.u
.HighPart
= 0;
599 FileOffset
.u
.LowPart
= 4096;
600 Success
= CcMapData(RegistryHive
->FileObject
, /* File object */
601 &FileOffset
, /* File offset */
602 RegistryHive
->FileSize
- 4096, /* Region length */
603 TRUE
, /* Wait if needed */
604 &RegistryHive
->Bcb
, /* OUT: Buffer Control Block */
605 (PVOID
*) &RegistryHive
->BlockList
[0]); /* OUT: Mapped data pointer */
607 assertmsg(Success
, ("Success: %d\n", Success
));
611 ExFreePool(RegistryHive
->BlockList
);
612 ObDereferenceObject(RegistryHive
->FileObject
);
613 RtlFreeUnicodeString(&RegistryHive
->Filename
);
619 RegistryHive
->BlockList
[0] = ExAllocatePool(PagedPool
,
620 RegistryHive
->FileSize
- 4096);
622 if (RegistryHive
->BlockList
[0] == NULL
)
624 ExFreePool(RegistryHive
->BlockList
);
625 ObDereferenceObject(RegistryHive
->FileObject
);
626 RtlFreeUnicodeString(&RegistryHive
->Filename
);
627 return STATUS_INSUFFICIENT_RESOURCES
;
630 FileOffset
.u
.HighPart
= 0;
631 FileOffset
.u
.LowPart
= 4096;
633 Status
= ZwReadFile(FileHandle
,
638 (PVOID
) RegistryHive
->BlockList
[0],
639 RegistryHive
->FileSize
- 4096,
643 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
647 RegistryHive
->FreeListSize
= 0;
648 RegistryHive
->FreeListMax
= 0;
649 RegistryHive
->FreeList
= NULL
;
652 for (i
= 0; i
< RegistryHive
->BlockListSize
; i
++)
654 RegistryHive
->BlockList
[i
] = (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[0]) + BlockOffset
);
655 tmpBin
= (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[i
]));
656 if (tmpBin
->BlockId
!= REG_BIN_ID
)
658 DPRINT("Bad BlockId %x, offset %x\n", tmpBin
->BlockId
, BlockOffset
);
662 assertmsg((tmpBin
->BlockSize
% 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin
->BlockSize
));
664 if (tmpBin
->BlockSize
> 4096)
666 for (j
= 1; j
< tmpBin
->BlockSize
/ 4096; j
++)
668 RegistryHive
->BlockList
[i
+ j
] = RegistryHive
->BlockList
[i
];
673 /* Search free blocks and add to list */
674 FreeOffset
= REG_HBIN_DATA_OFFSET
;
675 while (FreeOffset
< tmpBin
->BlockSize
)
677 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) RegistryHive
->BlockList
[i
] + FreeOffset
);
678 if (FreeBlock
->CellSize
> 0)
680 Status
= CmiAddFree(RegistryHive
,
682 RegistryHive
->BlockList
[i
]->BlockOffset
+ FreeOffset
);
684 if (!NT_SUCCESS(Status
))
690 FreeOffset
+= FreeBlock
->CellSize
;
694 FreeOffset
-= FreeBlock
->CellSize
;
697 BlockOffset
+= tmpBin
->BlockSize
;
700 return STATUS_SUCCESS
;
705 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive
)
707 PKEY_CELL RootKeyCell
;
709 RegistryHive
->Flags
|= HIVE_VOLATILE
;
711 CmiCreateDefaultHiveHeader(RegistryHive
->HiveHeader
);
713 RootKeyCell
= (PKEY_CELL
) ExAllocatePool(NonPagedPool
, sizeof(KEY_CELL
));
715 if (RootKeyCell
== NULL
)
716 return STATUS_INSUFFICIENT_RESOURCES
;
718 CmiCreateDefaultRootKeyCell(RootKeyCell
);
720 RegistryHive
->HiveHeader
->RootKeyCell
= (BLOCK_OFFSET
) RootKeyCell
;
722 return STATUS_SUCCESS
;
727 CmiCreateRegistryHive(PWSTR Filename
,
728 PREGISTRY_HIVE
*RegistryHive
,
734 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename
);
736 *RegistryHive
= NULL
;
738 Hive
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_HIVE
));
740 return STATUS_INSUFFICIENT_RESOURCES
;
742 DPRINT("Hive %x\n", Hive
);
744 RtlZeroMemory(Hive
, sizeof(REGISTRY_HIVE
));
746 Hive
->HiveHeader
= (PHIVE_HEADER
)
747 ExAllocatePool(NonPagedPool
, sizeof(HIVE_HEADER
));
749 if (Hive
->HiveHeader
== NULL
)
752 return STATUS_INSUFFICIENT_RESOURCES
;
755 if (Filename
!= NULL
)
757 Status
= CmiInitPermanentRegistryHive(Hive
, Filename
, CreateNew
);
761 Status
= CmiInitVolatileRegistryHive(Hive
);
764 if (!NT_SUCCESS(Status
))
766 ExFreePool(Hive
->HiveHeader
);
771 KeInitializeSemaphore(&Hive
->RegSem
, 1, 1);
772 VERIFY_REGISTRY_HIVE(Hive
);
774 *RegistryHive
= Hive
;
776 return(STATUS_SUCCESS
);
781 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive
,
784 PHASH_TABLE_CELL HashBlock
;
785 PKEY_CELL CurSubKeyCell
;
789 VERIFY_KEY_CELL(KeyCell
);
792 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
793 if (HashBlock
== NULL
)
798 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
800 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
802 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
803 HashBlock
->Table
[i
].KeyOffset
,
805 if (MaxName
< CurSubKeyCell
->NameSize
)
807 MaxName
= CurSubKeyCell
->NameSize
;
809 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
813 CmiReleaseBlock(RegistryHive
, HashBlock
);
820 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive
,
823 PHASH_TABLE_CELL HashBlock
;
824 PKEY_CELL CurSubKeyCell
;
828 VERIFY_KEY_CELL(KeyCell
);
831 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
832 if (HashBlock
== NULL
)
837 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
839 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
841 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
842 HashBlock
->Table
[i
].KeyOffset
,
844 if (MaxClass
< CurSubKeyCell
->ClassSize
)
846 MaxClass
= CurSubKeyCell
->ClassSize
;
848 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
852 CmiReleaseBlock(RegistryHive
, HashBlock
);
859 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
862 PVALUE_LIST_CELL ValueListCell
;
863 PVALUE_CELL CurValueCell
;
867 VERIFY_KEY_CELL(KeyCell
);
869 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
871 if (ValueListCell
== NULL
)
876 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
878 CurValueCell
= CmiGetBlock(RegistryHive
,
879 ValueListCell
->Values
[i
],
881 if (CurValueCell
!= NULL
&&
882 MaxValueName
< CurValueCell
->NameSize
)
884 MaxValueName
= CurValueCell
->NameSize
;
886 CmiReleaseBlock(RegistryHive
, CurValueCell
);
889 CmiReleaseBlock(RegistryHive
, ValueListCell
);
896 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
899 PVALUE_LIST_CELL ValueListCell
;
900 PVALUE_CELL CurValueCell
;
904 VERIFY_KEY_CELL(KeyCell
);
906 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
908 if (ValueListCell
== NULL
)
913 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
915 CurValueCell
= CmiGetBlock(RegistryHive
,
916 ValueListCell
->Values
[i
],NULL
);
917 if ((CurValueCell
!= NULL
) &&
918 (MaxValueData
< (CurValueCell
->DataSize
& LONG_MAX
)))
920 MaxValueData
= CurValueCell
->DataSize
& LONG_MAX
;
922 CmiReleaseBlock(RegistryHive
, CurValueCell
);
925 CmiReleaseBlock(RegistryHive
, ValueListCell
);
932 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
933 IN PKEY_CELL KeyCell
,
934 OUT PKEY_CELL
*SubKeyCell
,
935 OUT BLOCK_OFFSET
*BlockOffset
,
937 IN ACCESS_MASK DesiredAccess
,
940 PHASH_TABLE_CELL HashBlock
;
941 PKEY_CELL CurSubKeyCell
;
945 VERIFY_KEY_CELL(KeyCell
);
947 DPRINT("Scanning for sub key %s\n", KeyName
);
949 assert(RegistryHive
);
951 KeyLength
= strlen(KeyName
);
953 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
955 if (HashBlock
== NULL
)
957 return STATUS_SUCCESS
;
960 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
)
961 && (i
< HashBlock
->HashTableSize
); i
++)
963 if (Attributes
& OBJ_CASE_INSENSITIVE
)
965 if ((HashBlock
->Table
[i
].KeyOffset
!= 0) &&
966 (HashBlock
->Table
[i
].KeyOffset
!= -1) &&
967 (_strnicmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4) == 0))
969 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
970 HashBlock
->Table
[i
].KeyOffset
,
972 if ((CurSubKeyCell
->NameSize
== KeyLength
)
973 && (_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
) == 0))
975 *SubKeyCell
= CurSubKeyCell
;
976 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
981 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
987 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
988 HashBlock
->Table
[i
].KeyOffset
!= -1 &&
989 !strncmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4))
991 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
992 HashBlock
->Table
[i
].KeyOffset
,NULL
);
993 if (CurSubKeyCell
->NameSize
== KeyLength
994 && !_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
))
996 *SubKeyCell
= CurSubKeyCell
;
997 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
1002 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1008 CmiReleaseBlock(RegistryHive
, HashBlock
);
1010 return STATUS_SUCCESS
;
1015 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
1018 PWSTR NewSubKeyName
,
1019 USHORT NewSubKeyNameSize
,
1021 PUNICODE_STRING Class
,
1022 ULONG CreateOptions
)
1024 PHASH_TABLE_CELL NewHashBlock
;
1025 PHASH_TABLE_CELL HashBlock
;
1026 BLOCK_OFFSET NKBOffset
;
1027 PKEY_CELL NewKeyCell
;
1033 KeyCell
= Parent
->KeyCell
;
1035 VERIFY_KEY_CELL(KeyCell
);
1037 if (NewSubKeyName
[0] == L
'\\')
1040 NameSize
= NewSubKeyNameSize
/ 2 - 1;
1044 NameSize
= NewSubKeyNameSize
/ 2;
1046 Status
= STATUS_SUCCESS
;
1048 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
1049 Status
= CmiAllocateBlock(RegistryHive
,
1050 (PVOID
) &NewKeyCell
,
1054 if (NewKeyCell
== NULL
)
1056 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1060 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
1061 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
1062 ZwQuerySystemTime((PTIME
) &NewKeyCell
->LastWriteTime
);
1063 NewKeyCell
->ParentKeyOffset
= -1;
1064 NewKeyCell
->NumberOfSubKeys
= 0;
1065 NewKeyCell
->HashTableOffset
= -1;
1066 NewKeyCell
->NumberOfValues
= 0;
1067 NewKeyCell
->ValuesOffset
= -1;
1068 NewKeyCell
->SecurityKeyOffset
= -1;
1069 NewKeyCell
->NameSize
= NameSize
;
1070 wcstombs(NewKeyCell
->Name
, NewSubKeyName
, NameSize
);
1071 NewKeyCell
->ClassNameOffset
= -1;
1073 VERIFY_KEY_CELL(NewKeyCell
);
1079 NewKeyCell
->ClassSize
= Class
->Length
+ sizeof(WCHAR
);
1080 Status
= CmiAllocateBlock(RegistryHive
,
1082 NewKeyCell
->ClassSize
,
1083 &NewKeyCell
->ClassNameOffset
);
1084 wcsncpy((PWSTR
) pClass
->Data
, Class
->Buffer
, Class
->Length
);
1085 ((PWSTR
) (pClass
->Data
))[Class
->Length
] = 0;
1089 if (!NT_SUCCESS(Status
))
1094 SubKey
->KeyCell
= NewKeyCell
;
1095 SubKey
->BlockOffset
= NKBOffset
;
1097 /* Don't modify hash table if key is volatile and parent is not */
1098 if (IsVolatileHive(RegistryHive
) && (!IsVolatileHive(Parent
->RegistryHive
)))
1103 if (KeyCell
->HashTableOffset
== -1)
1105 Status
= CmiAllocateHashTableBlock(RegistryHive
,
1107 &KeyCell
->HashTableOffset
,
1108 REG_INIT_HASH_TABLE_SIZE
);
1110 if (!NT_SUCCESS(Status
))
1117 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1118 if (((KeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
1120 BLOCK_OFFSET HTOffset
;
1122 /* Reallocate the hash table block */
1123 Status
= CmiAllocateHashTableBlock(RegistryHive
,
1126 HashBlock
->HashTableSize
+
1127 REG_EXTEND_HASH_TABLE_SIZE
);
1129 if (!NT_SUCCESS(Status
))
1134 RtlZeroMemory(&NewHashBlock
->Table
[0],
1135 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
1136 RtlCopyMemory(&NewHashBlock
->Table
[0],
1137 &HashBlock
->Table
[0],
1138 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
1139 CmiDestroyBlock(RegistryHive
, HashBlock
, KeyCell
->HashTableOffset
);
1140 KeyCell
->HashTableOffset
= HTOffset
;
1141 HashBlock
= NewHashBlock
;
1145 Status
= CmiAddKeyToHashTable(RegistryHive
, HashBlock
, NewKeyCell
, NKBOffset
);
1146 if (NT_SUCCESS(Status
))
1148 KeyCell
->NumberOfSubKeys
++;
1156 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
1157 IN PKEY_CELL KeyCell
,
1159 OUT PVALUE_CELL
*ValueCell
,
1160 OUT BLOCK_OFFSET
*VBOffset
)
1162 PVALUE_LIST_CELL ValueListCell
;
1163 PVALUE_CELL CurValueCell
;
1167 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1171 if (ValueListCell
== NULL
)
1173 DPRINT("ValueListCell is NULL\n");
1174 return STATUS_SUCCESS
;
1177 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1179 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1181 CurValueCell
= CmiGetBlock(RegistryHive
,
1182 ValueListCell
->Values
[i
],
1184 /* FIXME: perhaps we must not ignore case if NtCreateKey has not been */
1185 /* called with OBJ_CASE_INSENSITIVE flag ? */
1186 Length
= strlen(ValueName
);
1187 if ((CurValueCell
!= NULL
) &&
1188 (CurValueCell
->NameSize
== Length
) &&
1189 (_strnicmp(CurValueCell
->Name
, ValueName
, Length
) == 0))
1191 *ValueCell
= CurValueCell
;
1193 *VBOffset
= ValueListCell
->Values
[i
];
1194 DPRINT("Found value %s\n", ValueName
);
1197 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1200 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1202 return STATUS_SUCCESS
;
1207 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
1208 IN PKEY_CELL KeyCell
,
1210 OUT PVALUE_CELL
*ValueCell
)
1212 PVALUE_LIST_CELL ValueListCell
;
1213 PVALUE_CELL CurValueCell
;
1215 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1219 if (ValueListCell
== NULL
)
1221 return STATUS_NO_MORE_ENTRIES
;
1224 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1226 if (Index
>= KeyCell
->NumberOfValues
)
1228 return STATUS_NO_MORE_ENTRIES
;
1231 CurValueCell
= CmiGetBlock(RegistryHive
,
1232 ValueListCell
->Values
[Index
],
1235 if (CurValueCell
!= NULL
)
1237 *ValueCell
= CurValueCell
;
1240 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1241 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1243 return STATUS_SUCCESS
;
1248 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
1249 IN PKEY_CELL KeyCell
,
1250 IN PCHAR ValueNameBuf
,
1251 OUT PVALUE_CELL
*pValueCell
,
1252 OUT BLOCK_OFFSET
*pVBOffset
)
1254 PVALUE_LIST_CELL NewValueListCell
;
1255 PVALUE_LIST_CELL ValueListCell
;
1256 PVALUE_CELL NewValueCell
;
1257 BLOCK_OFFSET VLBOffset
;
1258 BLOCK_OFFSET VBOffset
;
1261 Status
= CmiAllocateValueCell(RegistryHive
,
1265 *pVBOffset
= VBOffset
;
1267 if (!NT_SUCCESS(Status
))
1272 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1274 if (ValueListCell
== NULL
)
1276 Status
= CmiAllocateBlock(RegistryHive
,
1277 (PVOID
) &ValueListCell
,
1278 sizeof(BLOCK_OFFSET
) * 3,
1281 if (!NT_SUCCESS(Status
))
1283 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
1286 KeyCell
->ValuesOffset
= VLBOffset
;
1288 else if ((KeyCell
->NumberOfValues
1289 >= ((LONG
) (ValueListCell
->CellSize
- 4)) / (LONG
) sizeof(BLOCK_OFFSET
)))
1291 Status
= CmiAllocateBlock(RegistryHive
,
1292 (PVOID
) &NewValueListCell
,
1293 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
),
1296 if (!NT_SUCCESS(Status
))
1298 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
1302 RtlCopyMemory(&NewValueListCell
->Values
[0],
1303 &ValueListCell
->Values
[0],
1304 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
1305 CmiDestroyBlock(RegistryHive
, ValueListCell
, KeyCell
->ValuesOffset
);
1306 KeyCell
->ValuesOffset
= VLBOffset
;
1307 ValueListCell
= NewValueListCell
;
1310 DPRINT("KeyCell->NumberOfValues %d, ValueListCell->CellSize %d (%d %x)\n",
1311 KeyCell
->NumberOfValues
, ValueListCell
->CellSize
,
1312 -(ValueListCell
->CellSize
- 4) / sizeof(BLOCK_OFFSET
),
1313 -(ValueListCell
->CellSize
- 4) / sizeof(BLOCK_OFFSET
));
1315 ValueListCell
->Values
[KeyCell
->NumberOfValues
] = VBOffset
;
1316 KeyCell
->NumberOfValues
++;
1317 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1318 CmiReleaseBlock(RegistryHive
, NewValueCell
);
1319 *pValueCell
= NewValueCell
;
1321 return STATUS_SUCCESS
;
1326 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
1327 IN PKEY_CELL KeyCell
,
1330 PVALUE_LIST_CELL ValueListCell
;
1331 PVALUE_CELL CurValueCell
;
1334 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1336 if (ValueListCell
== NULL
)
1338 return STATUS_SUCCESS
;
1341 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1343 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1345 CurValueCell
= CmiGetBlock(RegistryHive
, ValueListCell
->Values
[i
], NULL
);
1346 if ((CurValueCell
!= NULL
) &&
1347 (CurValueCell
->NameSize
== strlen(ValueName
)) &&
1348 (memcmp(CurValueCell
->Name
, ValueName
, strlen(ValueName
)) == 0))
1350 if ((KeyCell
->NumberOfValues
- 1) < i
)
1352 RtlCopyMemory(&ValueListCell
->Values
[i
],
1353 &ValueListCell
->Values
[i
+ 1],
1354 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
1358 RtlZeroMemory(&ValueListCell
->Values
[i
], sizeof(BLOCK_OFFSET
));
1361 KeyCell
->NumberOfValues
-= 1;
1362 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->Values
[i
]);
1365 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1368 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1370 return STATUS_SUCCESS
;
1375 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive
,
1376 OUT PHASH_TABLE_CELL
*HashBlock
,
1377 OUT BLOCK_OFFSET
*HBOffset
,
1378 IN ULONG HashTableSize
)
1380 PHASH_TABLE_CELL NewHashBlock
;
1384 Status
= STATUS_SUCCESS
;
1386 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
1387 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
1388 Status
= CmiAllocateBlock(RegistryHive
,
1389 (PVOID
*) &NewHashBlock
,
1393 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
1395 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1399 NewHashBlock
->Id
= REG_HASH_TABLE_BLOCK_ID
;
1400 NewHashBlock
->HashTableSize
= HashTableSize
;
1401 *HashBlock
= NewHashBlock
;
1409 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
1410 PHASH_TABLE_CELL HashBlock
,
1413 BLOCK_OFFSET KeyOffset
;
1416 if (HashBlock
== NULL
)
1419 if (IsVolatileHive(RegistryHive
))
1421 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
1425 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
1426 KeyCell
= CmiGetBlock(RegistryHive
, KeyOffset
, NULL
);
1428 CmiLockBlock(RegistryHive
, KeyCell
);
1435 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
1436 PHASH_TABLE_CELL HashBlock
,
1437 PKEY_CELL NewKeyCell
,
1438 BLOCK_OFFSET NKBOffset
)
1442 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1444 if (HashBlock
->Table
[i
].KeyOffset
== 0)
1446 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
1447 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
, NewKeyCell
->Name
, 4);
1448 return STATUS_SUCCESS
;
1452 return STATUS_UNSUCCESSFUL
;
1457 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
1458 PVALUE_CELL
*ValueCell
,
1459 BLOCK_OFFSET
*VBOffset
,
1460 IN PCHAR ValueNameBuf
)
1462 PVALUE_CELL NewValueCell
;
1466 Status
= STATUS_SUCCESS
;
1468 NewValueSize
= sizeof(VALUE_CELL
) + strlen(ValueNameBuf
);
1469 Status
= CmiAllocateBlock(RegistryHive
,
1470 (PVOID
*) &NewValueCell
,
1474 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
1476 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1480 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
1481 NewValueCell
->NameSize
= strlen(ValueNameBuf
);
1482 memcpy(NewValueCell
->Name
, ValueNameBuf
, strlen(ValueNameBuf
));
1483 NewValueCell
->DataType
= 0;
1484 NewValueCell
->DataSize
= 0;
1485 NewValueCell
->DataOffset
= 0xffffffff;
1486 *ValueCell
= NewValueCell
;
1494 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
1495 PVALUE_CELL ValueCell
,
1496 BLOCK_OFFSET VBOffset
)
1502 VERIFY_VALUE_CELL(ValueCell
);
1504 /* First, release datas: */
1505 if (ValueCell
->DataSize
> 0)
1507 pBlock
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, &pBin
);
1508 Status
= CmiDestroyBlock(RegistryHive
, pBlock
, ValueCell
->DataOffset
);
1509 if (!NT_SUCCESS(Status
))
1514 /* Update time of heap */
1515 if (IsPermanentHive(RegistryHive
))
1516 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
1519 Status
= CmiDestroyBlock(RegistryHive
, ValueCell
, VBOffset
);
1521 /* Update time of heap */
1522 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, VBOffset
, &pBin
))
1524 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
1532 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
1534 BLOCK_OFFSET
*NewBlockOffset
)
1536 PCELL_HEADER tmpBlock
;
1537 PHBIN
* tmpBlockList
;
1540 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
1543 return STATUS_INSUFFICIENT_RESOURCES
;
1546 tmpBin
->BlockId
= REG_BIN_ID
;
1547 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
1548 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
1549 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
1550 tmpBin
->Unused1
= 0;
1551 ZwQuerySystemTime((PTIME
) &tmpBin
->DateModified
);
1552 tmpBin
->Unused2
= 0;
1554 /* Increase size of list of blocks */
1555 tmpBlockList
= ExAllocatePool(NonPagedPool
,
1556 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
1557 if (tmpBlockList
== NULL
)
1560 return STATUS_INSUFFICIENT_RESOURCES
;
1563 if (RegistryHive
->BlockListSize
> 0)
1565 memcpy(tmpBlockList
,
1566 RegistryHive
->BlockList
,
1567 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
1568 ExFreePool(RegistryHive
->BlockList
);
1571 RegistryHive
->BlockList
= tmpBlockList
;
1572 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
++] = tmpBin
;
1574 /* Initialize a free block in this heap : */
1575 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
1576 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
1577 *NewBlock
= (PVOID
) tmpBlock
;
1580 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
1582 /* FIXME: set first dword to block_offset of another free bloc */
1584 return STATUS_SUCCESS
;
1589 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive
,
1592 BLOCK_OFFSET
* pBlockOffset
)
1594 PCELL_HEADER NewBlock
;
1598 Status
= STATUS_SUCCESS
;
1600 /* Round to 16 bytes multiple */
1601 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
1603 /* Handle volatile hives first */
1604 if (IsVolatileHive(RegistryHive
))
1606 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
1608 if (NewBlock
== NULL
)
1610 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1614 RtlZeroMemory(NewBlock
, BlockSize
);
1615 NewBlock
->CellSize
= BlockSize
;
1616 CmiLockBlock(RegistryHive
, NewBlock
);
1619 *pBlockOffset
= (BLOCK_OFFSET
) NewBlock
;
1626 /* first search in free blocks */
1628 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
1630 if (RegistryHive
->FreeList
[i
]->CellSize
>= BlockSize
)
1633 NewBlock
= RegistryHive
->FreeList
[i
];
1636 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
1638 /* Update time of heap */
1639 Temp
= CmiGetBlock(RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
1642 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
1644 if ((i
+ 1) < RegistryHive
->FreeListSize
)
1646 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
1647 &RegistryHive
->FreeList
[i
+ 1],
1648 sizeof(RegistryHive
->FreeList
[0])
1649 * (RegistryHive
->FreeListSize
- i
- 1));
1650 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
1651 &RegistryHive
->FreeListOffset
[i
+ 1],
1652 sizeof(RegistryHive
->FreeListOffset
[0])
1653 * (RegistryHive
->FreeListSize
- i
- 1));
1655 RegistryHive
->FreeListSize
--;
1660 /* Need to extend hive file : */
1661 if (NewBlock
== NULL
)
1663 /* Add a new block */
1664 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewBlock
, pBlockOffset
);
1667 if (NT_SUCCESS(Status
))
1671 /* Split the block in two parts */
1672 if (NewBlock
->CellSize
> BlockSize
)
1674 NewBlock
= (PCELL_HEADER
) ((ULONG_PTR
) NewBlock
+BlockSize
);
1675 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- BlockSize
;
1676 CmiAddFree(RegistryHive
, NewBlock
, *pBlockOffset
+ BlockSize
);
1678 else if (NewBlock
->CellSize
< BlockSize
)
1680 return STATUS_UNSUCCESSFUL
;
1682 RtlZeroMemory(*Block
, BlockSize
);
1683 ((PCELL_HEADER
) (*Block
))->CellSize
= -BlockSize
;
1684 CmiLockBlock(RegistryHive
, *Block
);
1692 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive
,
1694 BLOCK_OFFSET Offset
)
1699 Status
= STATUS_SUCCESS
;
1701 if (IsVolatileHive(RegistryHive
))
1703 CmiReleaseBlock(RegistryHive
, Block
);
1708 PCELL_HEADER pFree
= Block
;
1710 if (pFree
->CellSize
< 0)
1711 pFree
->CellSize
= -pFree
->CellSize
;
1713 CmiAddFree(RegistryHive
, Block
, Offset
);
1714 CmiReleaseBlock(RegistryHive
, Block
);
1716 /* Update time of heap */
1717 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, Offset
,&pBin
))
1718 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
1720 /* FIXME: Set first dword to block_offset of another free block ? */
1721 /* FIXME: Concatenate with previous and next block if free */
1729 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
1730 PCELL_HEADER FreeBlock
,
1731 BLOCK_OFFSET FreeOffset
)
1733 PCELL_HEADER
*tmpList
;
1734 BLOCK_OFFSET
*tmpListOffset
;
1739 assert(RegistryHive
);
1742 DPRINT("FreeBlock %.08x FreeOffset %.08x\n",
1743 FreeBlock
, FreeOffset
);
1745 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
1748 tmpList
= ExAllocatePool(PagedPool
,
1749 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
1752 if (tmpList
== NULL
)
1753 return STATUS_INSUFFICIENT_RESOURCES
;
1756 tmpListOffset
= ExAllocatePool(PagedPool
,
1757 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
+ 32));
1760 if (tmpListOffset
== NULL
)
1762 ExFreePool(tmpList
);
1763 return STATUS_INSUFFICIENT_RESOURCES
;
1767 if (RegistryHive
->FreeListMax
)
1770 RtlMoveMemory(tmpList
, RegistryHive
->FreeList
,
1771 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
1773 RtlMoveMemory(tmpListOffset
, RegistryHive
->FreeListOffset
,
1774 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
));
1776 ExFreePool(RegistryHive
->FreeList
);
1778 ExFreePool(RegistryHive
->FreeListOffset
);
1782 RegistryHive
->FreeList
= tmpList
;
1783 RegistryHive
->FreeListOffset
= tmpListOffset
;
1784 RegistryHive
->FreeListMax
+= 32;
1789 /* Add new offset to free list, maintaining list in ascending order */
1790 if ((RegistryHive
->FreeListSize
== 0)
1791 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
1794 /* Add to end of list */
1795 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
1796 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
1798 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
1801 /* Add to begin of list */
1802 RtlMoveMemory(&RegistryHive
->FreeList
[1],
1803 &RegistryHive
->FreeList
[0],
1804 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
1805 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
1806 &RegistryHive
->FreeListOffset
[0],
1807 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
1808 RegistryHive
->FreeList
[0] = FreeBlock
;
1809 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
1810 RegistryHive
->FreeListSize
++;
1815 /* Search where to insert */
1817 maxInd
= RegistryHive
->FreeListSize
- 1;
1818 while ((maxInd
- minInd
) > 1)
1820 medInd
= (minInd
+ maxInd
) / 2;
1821 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
1827 /* Insert before maxInd */
1828 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
1829 &RegistryHive
->FreeList
[maxInd
],
1830 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
1831 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
1832 &RegistryHive
->FreeListOffset
[maxInd
],
1833 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
1834 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
1835 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
1836 RegistryHive
->FreeListSize
++;
1840 return STATUS_SUCCESS
;
1845 CmiGetBlock(PREGISTRY_HIVE RegistryHive
,
1846 BLOCK_OFFSET BlockOffset
,
1852 if ((BlockOffset
== 0) || (BlockOffset
== -1))
1855 if (IsVolatileHive(RegistryHive
))
1857 return (PVOID
) BlockOffset
;
1863 pBin
= RegistryHive
->BlockList
[BlockOffset
/ 4096];
1866 return ((PVOID
) ((ULONG_PTR
) pBin
+ (BlockOffset
- pBin
->BlockOffset
)));
1872 CmiPrepareForWrite(PREGISTRY_HIVE RegistryHive
,
1875 if (IsVolatileHive(RegistryHive
))
1877 /* No need to do anything special for volatile hives */
1888 CmiLockBlock(PREGISTRY_HIVE RegistryHive
,
1891 if (IsPermanentHive(RegistryHive
))
1893 /* FIXME: Implement */
1899 CmiReleaseBlock(PREGISTRY_HIVE RegistryHive
,
1902 if (IsPermanentHive(RegistryHive
))
1904 /* FIXME: Implement */