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 */