2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/regfile.c
5 * PURPOSE: Registry file manipulation routines
12 #include <ddk/ntddk.h>
13 #include <ddk/ntifs.h>
15 #include <internal/ob.h>
18 #include <internal/pool.h>
19 #include <internal/registry.h>
22 #include <internal/debug.h>
27 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
29 BOOLEAN CmiDoVerify = FALSE;
31 /* FUNCTIONS ****************************************************************/
34 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header)
37 RtlZeroMemory(Header, sizeof(HIVE_HEADER));
38 Header->BlockId = REG_HIVE_ID;
39 Header->DateModified.dwLowDateTime = 0;
40 Header->DateModified.dwHighDateTime = 0;
47 Header->RootKeyCell = 0;
48 Header->BlockSize = REG_BLOCK_SIZE;
55 CmiCreateDefaultBinCell(PHBIN BinCell)
58 RtlZeroMemory(BinCell, sizeof(HBIN));
59 BinCell->BlockId = REG_BIN_ID;
60 BinCell->DateModified.dwLowDateTime = 0;
61 BinCell->DateModified.dwHighDateTime = 0;
62 BinCell->BlockSize = REG_BLOCK_SIZE;
67 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell)
70 RtlZeroMemory(RootKeyCell, sizeof(KEY_CELL));
72 RootKeyCell->CellSize = -(LONG)sizeof(KEY_CELL);
74 RootKeyCell->CellSize = -sizeof(KEY_CELL);
76 RootKeyCell->Id = REG_KEY_CELL_ID;
77 RootKeyCell->Type = REG_ROOT_KEY_CELL_TYPE;
78 ZwQuerySystemTime((PTIME) &RootKeyCell->LastWriteTime);
79 RootKeyCell->ParentKeyOffset = 0;
80 RootKeyCell->NumberOfSubKeys = 0;
81 RootKeyCell->HashTableOffset = -1;
82 RootKeyCell->NumberOfValues = 0;
83 RootKeyCell->ValuesOffset = -1;
84 RootKeyCell->SecurityKeyOffset = 0;
85 RootKeyCell->ClassNameOffset = -1;
86 RootKeyCell->NameSize = 0;
87 RootKeyCell->ClassSize = 0;
92 CmiVerifyBinCell(PHBIN BinCell)
99 if (BinCell->BlockId != REG_BIN_ID)
101 DbgPrint("BlockId is %.08x (should be %.08x)\n",
102 BinCell->BlockId, REG_BIN_ID);
103 assert(BinCell->BlockId == REG_BIN_ID);
106 //BinCell->DateModified.dwLowDateTime
108 //BinCell->DateModified.dwHighDateTime
111 if (BinCell->BlockSize != REG_BLOCK_SIZE)
113 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
114 BinCell->BlockSize, REG_BLOCK_SIZE);
115 assert(BinCell->BlockSize == REG_BLOCK_SIZE);
123 CmiVerifyKeyCell(PKEY_CELL KeyCell)
130 if (KeyCell->CellSize == 0)
132 DbgPrint("CellSize is %d (must not be 0)\n",
134 assert(KeyCell->CellSize != 0);
137 if (KeyCell->Id != REG_KEY_CELL_ID)
139 DbgPrint("Id is %.08x (should be %.08x)\n",
140 KeyCell->Id, REG_KEY_CELL_ID);
141 assert(KeyCell->Id == REG_KEY_CELL_ID);
144 if ((KeyCell->Type != REG_KEY_CELL_TYPE)
145 && (KeyCell->Type != REG_ROOT_KEY_CELL_TYPE))
147 DbgPrint("Type is %.08x (should be %.08x or %.08x)\n",
148 KeyCell->Type, REG_KEY_CELL_TYPE, REG_ROOT_KEY_CELL_TYPE);
152 //KeyCell->LastWriteTime;
154 if (KeyCell->ParentKeyOffset < 0)
156 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
157 KeyCell->ParentKeyOffset);
158 assert(KeyCell->ParentKeyOffset >= 0);
161 if (KeyCell->NumberOfSubKeys < 0)
163 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
164 KeyCell->NumberOfSubKeys);
165 assert(KeyCell->NumberOfSubKeys >= 0);
168 //KeyCell->HashTableOffset;
170 if (KeyCell->NumberOfValues < 0)
172 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
173 KeyCell->NumberOfValues);
174 assert(KeyCell->NumberOfValues >= 0);
177 //KeyCell->ValuesOffset = -1;
179 if (KeyCell->SecurityKeyOffset < 0)
181 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
182 KeyCell->SecurityKeyOffset);
183 assert(KeyCell->SecurityKeyOffset >= 0);
186 //KeyCell->ClassNameOffset = -1;
197 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell)
202 CmiVerifyKeyCell(RootKeyCell);
204 if (RootKeyCell->Type != REG_ROOT_KEY_CELL_TYPE)
206 DbgPrint("Type is %.08x (should be %.08x)\n",
207 RootKeyCell->Type, REG_ROOT_KEY_CELL_TYPE);
208 assert(RootKeyCell->Type == REG_ROOT_KEY_CELL_TYPE);
216 CmiVerifyValueCell(PVALUE_CELL ValueCell)
223 if (ValueCell->CellSize == 0)
225 DbgPrint("CellSize is %d (must not be 0)\n",
226 ValueCell->CellSize);
227 assert(ValueCell->CellSize != 0);
230 if (ValueCell->Id != REG_VALUE_CELL_ID)
232 DbgPrint("Id is %.08x (should be %.08x)\n",
233 ValueCell->Id, REG_VALUE_CELL_ID);
234 assert(ValueCell->Id == REG_VALUE_CELL_ID);
237 //ValueCell->NameSize;
238 //ValueCell->LONG DataSize;
239 //ValueCell->DataOffset;
240 //ValueCell->ULONG DataType;
241 //ValueCell->USHORT Flags;
242 //ValueCell->USHORT Unused1;
243 //ValueCell->UCHAR Name[0];
249 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell)
254 if (ValueListCell->CellSize == 0)
256 DbgPrint("CellSize is %d (must not be 0)\n",
257 ValueListCell->CellSize);
258 assert(ValueListCell->CellSize != 0);
266 CmiVerifyKeyObject(PKEY_OBJECT KeyObject)
271 if (KeyObject->RegistryHive == NULL)
273 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
274 KeyObject->RegistryHive);
275 assert(KeyObject->RegistryHive != NULL);
278 if (KeyObject->KeyCell == NULL)
280 DbgPrint("KeyCell is NULL (must not be NULL)\n",
282 assert(KeyObject->KeyCell != NULL);
285 if (KeyObject->ParentKey == NULL)
287 DbgPrint("ParentKey is NULL (must not be NULL)\n",
288 KeyObject->ParentKey);
289 assert(KeyObject->ParentKey != NULL);
297 CmiVerifyHiveHeader(PHIVE_HEADER Header)
302 if (Header->BlockId != REG_HIVE_ID)
304 DbgPrint("BlockId is %.08x (must be %.08x)\n",
307 assert(Header->BlockId == REG_HIVE_ID);
310 if (Header->Unused3 != 1)
312 DbgPrint("Unused3 is %.08x (must be 1)\n",
314 assert(Header->Unused3 == 1);
317 if (Header->Unused4 != 3)
319 DbgPrint("Unused4 is %.08x (must be 3)\n",
321 assert(Header->Unused4 == 3);
324 if (Header->Unused5 != 0)
326 DbgPrint("Unused5 is %.08x (must be 0)\n",
328 assert(Header->Unused5 == 0);
331 if (Header->Unused6 != 1)
333 DbgPrint("Unused6 is %.08x (must be 1)\n",
335 assert(Header->Unused6 == 1);
338 if (Header->Unused7 != 1)
340 DbgPrint("Unused7 is %.08x (must be 1)\n",
342 assert(Header->Unused7 == 1);
350 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive)
355 CmiVerifyHiveHeader(RegistryHive->HiveHeader);
362 CmiPopulateHive(HANDLE FileHandle)
364 IO_STATUS_BLOCK IoStatusBlock;
365 LARGE_INTEGER FileOffset;
366 PCELL_HEADER FreeCell;
372 tBuf = (PCHAR) ExAllocatePool(NonPagedPool, REG_BLOCK_SIZE);
374 return STATUS_INSUFFICIENT_RESOURCES;
376 BinCell = (PHBIN) tBuf;
377 FreeCell = (PCELL_HEADER) (tBuf + REG_HBIN_DATA_OFFSET);
379 CmiCreateDefaultBinCell(BinCell);
381 // The whole block is free
382 FreeCell->CellSize = REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET;
384 // Add free blocks so we don't need to expand
385 // the file for a while
386 for (i = 0; i < 50; i++)
388 // Block offset of this bin
389 BinCell->BlockOffset = (2 + i) * REG_BLOCK_SIZE;
391 FileOffset.u.HighPart = 0;
392 FileOffset.u.LowPart = (2 + i) * REG_BLOCK_SIZE;
394 Status = ZwWriteFile(FileHandle,
403 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
404 if (!NT_SUCCESS(Status))
418 CmiCreateNewRegFile(HANDLE FileHandle)
420 IO_STATUS_BLOCK IoStatusBlock;
421 PCELL_HEADER FreeCell;
422 PHIVE_HEADER HiveHeader;
423 PKEY_CELL RootKeyCell;
428 Buffer = (PCHAR) ExAllocatePool(NonPagedPool, 2 * REG_BLOCK_SIZE);
430 return STATUS_INSUFFICIENT_RESOURCES;
432 HiveHeader = (PHIVE_HEADER)Buffer;
433 BinCell = (PHBIN)((ULONG_PTR)Buffer + REG_BLOCK_SIZE);
434 RootKeyCell = (PKEY_CELL)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET);
435 FreeCell = (PCELL_HEADER)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
437 CmiCreateDefaultHiveHeader(HiveHeader);
438 CmiCreateDefaultBinCell(BinCell);
439 CmiCreateDefaultRootKeyCell(RootKeyCell);
442 BinCell->BlockOffset = 0;
444 /* Offset to root key block */
445 HiveHeader->RootKeyCell = REG_HBIN_DATA_OFFSET;
447 /* The rest of the block is free */
448 FreeCell->CellSize = REG_BLOCK_SIZE - (REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
450 Status = ZwWriteFile(FileHandle,
462 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
465 if (NT_SUCCESS(Status))
467 CmiPopulateHive(FileHandle);
476 CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive,
480 OBJECT_ATTRIBUTES ObjectAttributes;
481 FILE_STANDARD_INFORMATION fsi;
482 PCELL_HEADER FreeBlock;
483 LARGE_INTEGER FileOffset;
484 BLOCK_OFFSET BlockOffset;
485 ULONG CreateDisposition;
486 IO_STATUS_BLOCK IoSB;
495 DPRINT1("CmiInitPermanentRegistryHive(%p, %S, %d) - Entered.\n", RegistryHive, Filename, CreateNew);
497 /* Duplicate Filename */
498 Status = RtlCreateUnicodeString(&RegistryHive->Filename, Filename);
499 if (!NT_SUCCESS(Status))
501 DPRINT1("CmiInitPermanentRegistryHive() - Failed 1.\n");
505 InitializeObjectAttributes(&ObjectAttributes,
506 &RegistryHive->Filename,
513 * This is a workaround to prevent a BSOD because of missing registry hives.
514 * The workaround is only useful for developers. An implementation for the
515 * ordinary user must bail out on missing registry hives because they are
516 * essential to booting and configuring the OS.
519 if (CreateNew == TRUE)
520 CreateDisposition = FILE_OPEN_IF;
522 CreateDisposition = FILE_OPEN;
524 CreateDisposition = FILE_OPEN_IF;
526 Status = NtCreateFile(&FileHandle,
531 FILE_ATTRIBUTE_NORMAL,
534 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
537 if (!NT_SUCCESS(Status))
539 RtlFreeUnicodeString(&RegistryHive->Filename);
540 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status);
544 /* Note: Another workaround! See the note above! */
546 if ((CreateNew) && (IoSB.Information == FILE_CREATED))
548 if (IoSB.Information != FILE_OPENED)
550 Status = CmiCreateNewRegFile(FileHandle);
551 if (!NT_SUCCESS(Status))
553 DPRINT1("CmiCreateNewRegFile() failed (Status %lx)\n", Status);
554 RtlFreeUnicodeString(&RegistryHive->Filename);
559 Status = ObReferenceObjectByHandle(FileHandle,
563 (PVOID*)&RegistryHive->FileObject,
566 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
568 if (!NT_SUCCESS(Status))
571 RtlFreeUnicodeString(&RegistryHive->Filename);
572 DPRINT1("CmiInitPermanentRegistryHive() - ObReferenceObjectByHandle Failed with status %x.\n", Status);
576 /* Read hive header */
577 FileOffset.u.HighPart = 0;
578 FileOffset.u.LowPart = 0;
579 DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle, sizeof(HIVE_HEADER), RegistryHive->HiveHeader);
580 Status = NtReadFile(FileHandle,
585 RegistryHive->HiveHeader,
589 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
590 if (!NT_SUCCESS(Status))
592 ObDereferenceObject(RegistryHive->FileObject);
593 RtlFreeUnicodeString(&RegistryHive->Filename);
594 DPRINT("CmiInitPermanentRegistryHive() - Failed 4.\n");
598 Status = NtQueryInformationFile(FileHandle,
602 FileStandardInformation);
604 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
606 if (!NT_SUCCESS(Status))
608 ObDereferenceObject(RegistryHive->FileObject);
609 RtlFreeUnicodeString(&RegistryHive->Filename);
610 DPRINT("CmiInitPermanentRegistryHive() - Failed 5.\n");
615 /* We have a reference to the file object so we don't need the handle anymore */
619 RegistryHive->FileSize = fsi.EndOfFile.u.LowPart;
621 // assert(RegistryHive->FileSize);
622 if (RegistryHive->FileSize)
624 RegistryHive->BlockListSize = (RegistryHive->FileSize / 4096) - 1;
628 ObDereferenceObject(RegistryHive->FileObject);
629 RtlFreeUnicodeString(&RegistryHive->Filename);
630 DPRINT("CmiInitPermanentRegistryHive() - Failed, zero length hive file.\n");
631 return STATUS_INSUFFICIENT_RESOURCES;
634 RegistryHive->BlockListSize = (RegistryHive->FileSize / 4096) - 1;
637 DPRINT("Space needed for block list describing hive: 0x%x\n",
638 sizeof(PHBIN *) * RegistryHive->BlockListSize);
640 RegistryHive->BlockList = ExAllocatePool(NonPagedPool,
641 sizeof(PHBIN *) * RegistryHive->BlockListSize);
643 if (RegistryHive->BlockList == NULL)
645 ExFreePool(RegistryHive->BlockList);
646 ObDereferenceObject(RegistryHive->FileObject);
647 RtlFreeUnicodeString(&RegistryHive->Filename);
648 DPRINT("CmiInitPermanentRegistryHive() - Failed 6.\n");
649 return STATUS_INSUFFICIENT_RESOURCES;
653 /* Map hive into cache memory (readonly) (skip the base block) */
654 FileOffset.u.HighPart = 0;
655 FileOffset.u.LowPart = 4096;
656 Success = CcMapData(RegistryHive->FileObject, /* File object */
657 &FileOffset, /* File offset */
658 RegistryHive->FileSize - 4096, /* Region length */
659 TRUE, /* Wait if needed */
660 &RegistryHive->Bcb, /* OUT: Buffer Control Block */
661 (PVOID*) &RegistryHive->BlockList[0]); /* OUT: Mapped data pointer */
663 assertmsg(Success, ("Success: %d\n", Success));
667 ExFreePool(RegistryHive->BlockList);
668 ObDereferenceObject(RegistryHive->FileObject);
669 RtlFreeUnicodeString(&RegistryHive->Filename);
670 DPRINT("CmiInitPermanentRegistryHive() - Failed 7.\n");
676 RegistryHive->BlockList[0] = ExAllocatePool(PagedPool,
677 RegistryHive->FileSize - 4096);
679 RtlZeroMemory(RegistryHive->BlockList[0], RegistryHive->FileSize - 4096);
682 if (RegistryHive->BlockList[0] == NULL)
684 ExFreePool(RegistryHive->BlockList);
685 ObDereferenceObject(RegistryHive->FileObject);
686 RtlFreeUnicodeString(&RegistryHive->Filename);
687 DPRINT("CmiInitPermanentRegistryHive() - Failed 8.\n");
688 return STATUS_INSUFFICIENT_RESOURCES;
691 FileOffset.u.HighPart = 0;
692 FileOffset.u.LowPart = 4096;
694 DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle, RegistryHive->FileSize - 4096, (PVOID)RegistryHive->BlockList[0]);
695 Status = NtReadFile(FileHandle,
700 (PVOID) RegistryHive->BlockList[0],
701 RegistryHive->FileSize - 4096,
705 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
710 RegistryHive->FreeListSize = 0;
711 RegistryHive->FreeListMax = 0;
712 RegistryHive->FreeList = NULL;
715 for (i = 0; i < RegistryHive->BlockListSize; i++)
717 RegistryHive->BlockList[i] = (PHBIN) (((ULONG_PTR) RegistryHive->BlockList[0]) + BlockOffset);
718 tmpBin = (PHBIN) (((ULONG_PTR) RegistryHive->BlockList[i]));
719 if (tmpBin->BlockId != REG_BIN_ID)
721 DPRINT("Bad BlockId %x, offset %x\n", tmpBin->BlockId, BlockOffset);
723 return STATUS_INSUFFICIENT_RESOURCES;
726 assertmsg((tmpBin->BlockSize % 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin->BlockSize));
728 if (tmpBin->BlockSize > 4096)
730 for (j = 1; j < tmpBin->BlockSize / 4096; j++)
732 RegistryHive->BlockList[i + j] = RegistryHive->BlockList[i];
737 /* Search free blocks and add to list */
738 FreeOffset = REG_HBIN_DATA_OFFSET;
739 while (FreeOffset < tmpBin->BlockSize)
741 FreeBlock = (PCELL_HEADER) ((ULONG_PTR) RegistryHive->BlockList[i] + FreeOffset);
742 if (FreeBlock->CellSize > 0)
744 Status = CmiAddFree(RegistryHive,
746 RegistryHive->BlockList[i]->BlockOffset + FreeOffset);
748 if (!NT_SUCCESS(Status))
754 FreeOffset += FreeBlock->CellSize;
758 FreeOffset -= FreeBlock->CellSize;
761 BlockOffset += tmpBin->BlockSize;
764 /* Create block bitmap and clear all bits */
766 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
767 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
768 DPRINT1("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
769 DPRINT1("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
770 BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
772 RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
775 RtlClearAllBits(&RegistryHive->DirtyBitMap);
776 RegistryHive->HiveDirty = FALSE;
778 DPRINT1("CmiInitPermanentRegistryHive(%p, %S, %d) - Finished.\n", RegistryHive, Filename, CreateNew);
780 return(STATUS_SUCCESS);
785 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive)
787 PKEY_CELL RootKeyCell;
789 RegistryHive->Flags |= HIVE_VOLATILE;
791 CmiCreateDefaultHiveHeader(RegistryHive->HiveHeader);
793 RootKeyCell = (PKEY_CELL) ExAllocatePool(NonPagedPool, sizeof(KEY_CELL));
795 if (RootKeyCell == NULL)
796 return STATUS_INSUFFICIENT_RESOURCES;
798 CmiCreateDefaultRootKeyCell(RootKeyCell);
800 RegistryHive->HiveHeader->RootKeyCell = (BLOCK_OFFSET) RootKeyCell;
802 return STATUS_SUCCESS;
807 CmiCreateRegistryHive(PWSTR Filename,
808 PREGISTRY_HIVE *RegistryHive,
814 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename);
816 *RegistryHive = NULL;
818 Hive = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_HIVE));
820 return(STATUS_INSUFFICIENT_RESOURCES);
822 DPRINT("Hive %x\n", Hive);
824 RtlZeroMemory(Hive, sizeof(REGISTRY_HIVE));
826 Hive->HiveHeader = (PHIVE_HEADER)
827 ExAllocatePool(NonPagedPool, sizeof(HIVE_HEADER));
829 if (Hive->HiveHeader == NULL)
832 return(STATUS_INSUFFICIENT_RESOURCES);
835 if (Filename != NULL)
837 Status = CmiInitPermanentRegistryHive(Hive, Filename, CreateNew);
841 Status = CmiInitVolatileRegistryHive(Hive);
844 if (!NT_SUCCESS(Status))
846 ExFreePool(Hive->HiveHeader);
851 ExInitializeResourceLite(&Hive->HiveResource);
853 /* Acquire hive list lock exclusively */
854 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
856 /* Add the new hive to the hive list */
857 InsertHeadList(&CmiHiveListHead, &Hive->HiveList);
859 /* Release hive list lock */
860 ExReleaseResourceLite(&CmiHiveListLock);
862 VERIFY_REGISTRY_HIVE(Hive);
864 *RegistryHive = Hive;
866 DPRINT("CmiCreateRegistryHive(Filename %S) - Finished.\n", Filename);
868 return(STATUS_SUCCESS);
873 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive)
875 /* Acquire hive list lock exclusively */
876 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
878 /* Remove hive from hive list */
879 RemoveEntryList(&RegistryHive->HiveList);
881 /* Release hive list lock */
882 ExReleaseResourceLite(&CmiHiveListLock);
885 /* FIXME: Remove attached keys and values */
888 /* Release hive header */
889 ExFreePool(RegistryHive->HiveHeader);
892 ExFreePool(RegistryHive);
894 return(STATUS_SUCCESS);
899 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
904 LARGE_INTEGER FileOffset;
905 OBJECT_ATTRIBUTES ObjectAttributes;
906 IO_STATUS_BLOCK IoStatusBlock;
913 DPRINT("CmiFlushRegistryHive() called\n");
915 if (RegistryHive->HiveDirty == FALSE)
917 return(STATUS_SUCCESS);
920 DPRINT1("Hive '%wZ' is dirty\n", &RegistryHive->Filename);
923 /* Open hive for writing */
924 InitializeObjectAttributes(&ObjectAttributes,
925 &RegistryHive->Filename,
930 Status = NtCreateFile(&FileHandle,
935 FILE_ATTRIBUTE_NORMAL,
938 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
941 if (!NT_SUCCESS(Status))
943 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status);
952 BlockIndex = RtlFindSetBitsAndClear(&RegistryHive->DirtyBitMap,
955 if (BlockIndex == (ULONG)-1)
957 DPRINT("No more set bits\n");
961 DPRINT1("Block %lu is dirty\n", BlockIndex);
963 BlockOffset = RegistryHive->BlockList[BlockIndex]->BlockOffset;
964 DPRINT1("Block offset %lx\n", BlockOffset);
966 BlockPtr = RegistryHive->BlockList[BlockIndex] + ((BlockIndex * 4096) - BlockOffset);
967 DPRINT1("BlockPtr %p\n", BlockPtr);
969 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096ULL;
970 DPRINT1("File offset %I64x\n", FileOffset.QuadPart);
973 /* Write hive block */
974 Status = NtWriteFile(FileHandle,
983 if (!NT_SUCCESS(Status))
985 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
996 /* Clear dirty flag */
997 RegistryHive->HiveDirty = FALSE;
999 DPRINT("CmiFlushRegistryHive() done\n");
1001 return(STATUS_SUCCESS);
1006 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive,
1009 PHASH_TABLE_CELL HashBlock;
1010 PKEY_CELL CurSubKeyCell;
1014 VERIFY_KEY_CELL(KeyCell);
1017 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1018 if (HashBlock == NULL)
1023 for (i = 0; i < HashBlock->HashTableSize; i++)
1025 if (HashBlock->Table[i].KeyOffset != 0)
1027 CurSubKeyCell = CmiGetBlock(RegistryHive,
1028 HashBlock->Table[i].KeyOffset,
1030 if (MaxName < CurSubKeyCell->NameSize)
1032 MaxName = CurSubKeyCell->NameSize;
1034 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
1038 CmiReleaseBlock(RegistryHive, HashBlock);
1045 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive,
1048 PHASH_TABLE_CELL HashBlock;
1049 PKEY_CELL CurSubKeyCell;
1053 VERIFY_KEY_CELL(KeyCell);
1056 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1057 if (HashBlock == NULL)
1062 for (i = 0; i < HashBlock->HashTableSize; i++)
1064 if (HashBlock->Table[i].KeyOffset != 0)
1066 CurSubKeyCell = CmiGetBlock(RegistryHive,
1067 HashBlock->Table[i].KeyOffset,
1069 if (MaxClass < CurSubKeyCell->ClassSize)
1071 MaxClass = CurSubKeyCell->ClassSize;
1073 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
1077 CmiReleaseBlock(RegistryHive, HashBlock);
1084 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive,
1087 PVALUE_LIST_CELL ValueListCell;
1088 PVALUE_CELL CurValueCell;
1092 VERIFY_KEY_CELL(KeyCell);
1094 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1096 if (ValueListCell == NULL)
1101 for (i = 0; i < KeyCell->NumberOfValues; i++)
1103 CurValueCell = CmiGetBlock(RegistryHive,
1104 ValueListCell->Values[i],
1106 if (CurValueCell != NULL &&
1107 MaxValueName < CurValueCell->NameSize)
1109 MaxValueName = CurValueCell->NameSize;
1111 CmiReleaseBlock(RegistryHive, CurValueCell);
1114 CmiReleaseBlock(RegistryHive, ValueListCell);
1116 return MaxValueName;
1121 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive,
1124 PVALUE_LIST_CELL ValueListCell;
1125 PVALUE_CELL CurValueCell;
1129 VERIFY_KEY_CELL(KeyCell);
1131 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1133 if (ValueListCell == NULL)
1138 for (i = 0; i < KeyCell->NumberOfValues; i++)
1140 CurValueCell = CmiGetBlock(RegistryHive,
1141 ValueListCell->Values[i],NULL);
1142 if ((CurValueCell != NULL) &&
1143 (MaxValueData < (CurValueCell->DataSize & LONG_MAX)))
1145 MaxValueData = CurValueCell->DataSize & LONG_MAX;
1147 CmiReleaseBlock(RegistryHive, CurValueCell);
1150 CmiReleaseBlock(RegistryHive, ValueListCell);
1152 return MaxValueData;
1157 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
1158 IN PKEY_CELL KeyCell,
1159 OUT PKEY_CELL *SubKeyCell,
1160 OUT BLOCK_OFFSET *BlockOffset,
1162 IN ACCESS_MASK DesiredAccess,
1163 IN ULONG Attributes)
1165 PHASH_TABLE_CELL HashBlock;
1166 PKEY_CELL CurSubKeyCell;
1170 VERIFY_KEY_CELL(KeyCell);
1172 //DPRINT("Scanning for sub key %s\n", KeyName);
1174 assert(RegistryHive);
1176 KeyLength = strlen(KeyName);
1178 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1180 if (HashBlock == NULL)
1182 return STATUS_SUCCESS;
1185 for (i = 0; (i < KeyCell->NumberOfSubKeys)
1186 && (i < HashBlock->HashTableSize); i++)
1188 if (Attributes & OBJ_CASE_INSENSITIVE)
1190 if ((HashBlock->Table[i].KeyOffset != 0) &&
1191 (HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1) &&
1192 (_strnicmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4) == 0))
1194 CurSubKeyCell = CmiGetBlock(RegistryHive,
1195 HashBlock->Table[i].KeyOffset,
1197 if ((CurSubKeyCell->NameSize == KeyLength)
1198 && (_strnicmp(KeyName, CurSubKeyCell->Name, KeyLength) == 0))
1200 *SubKeyCell = CurSubKeyCell;
1201 *BlockOffset = HashBlock->Table[i].KeyOffset;
1206 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
1212 if (HashBlock->Table[i].KeyOffset != 0 &&
1213 HashBlock->Table[i].KeyOffset != (ULONG_PTR) -1 &&
1214 !strncmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4))
1216 CurSubKeyCell = CmiGetBlock(RegistryHive,
1217 HashBlock->Table[i].KeyOffset,NULL);
1218 if (CurSubKeyCell->NameSize == KeyLength
1219 && !_strnicmp(KeyName, CurSubKeyCell->Name, KeyLength))
1221 *SubKeyCell = CurSubKeyCell;
1222 *BlockOffset = HashBlock->Table[i].KeyOffset;
1227 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
1233 CmiReleaseBlock(RegistryHive, HashBlock);
1235 return STATUS_SUCCESS;
1240 CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
1243 PWSTR NewSubKeyName,
1244 USHORT NewSubKeyNameSize,
1246 PUNICODE_STRING Class,
1247 ULONG CreateOptions)
1249 PHASH_TABLE_CELL NewHashBlock;
1250 PHASH_TABLE_CELL HashBlock;
1251 BLOCK_OFFSET NKBOffset;
1252 PKEY_CELL NewKeyCell;
1258 KeyCell = Parent->KeyCell;
1260 VERIFY_KEY_CELL(KeyCell);
1262 if (NewSubKeyName[0] == L'\\')
1265 NameSize = NewSubKeyNameSize / 2 - 1;
1269 NameSize = NewSubKeyNameSize / 2;
1271 Status = STATUS_SUCCESS;
1273 NewBlockSize = sizeof(KEY_CELL) + NameSize;
1274 Status = CmiAllocateBlock(RegistryHive,
1275 (PVOID) &NewKeyCell,
1279 if (NewKeyCell == NULL)
1281 Status = STATUS_INSUFFICIENT_RESOURCES;
1285 NewKeyCell->Id = REG_KEY_CELL_ID;
1286 NewKeyCell->Type = REG_KEY_CELL_TYPE;
1287 ZwQuerySystemTime((PTIME) &NewKeyCell->LastWriteTime);
1288 NewKeyCell->ParentKeyOffset = -1;
1289 NewKeyCell->NumberOfSubKeys = 0;
1290 NewKeyCell->HashTableOffset = -1;
1291 NewKeyCell->NumberOfValues = 0;
1292 NewKeyCell->ValuesOffset = -1;
1293 NewKeyCell->SecurityKeyOffset = -1;
1294 NewKeyCell->NameSize = NameSize;
1295 wcstombs(NewKeyCell->Name, NewSubKeyName, NameSize);
1296 NewKeyCell->ClassNameOffset = -1;
1298 VERIFY_KEY_CELL(NewKeyCell);
1304 NewKeyCell->ClassSize = Class->Length + sizeof(WCHAR);
1305 Status = CmiAllocateBlock(RegistryHive,
1307 NewKeyCell->ClassSize,
1308 &NewKeyCell->ClassNameOffset);
1309 wcsncpy((PWSTR) pClass->Data, Class->Buffer, Class->Length);
1310 ((PWSTR) (pClass->Data))[Class->Length] = 0;
1314 if (!NT_SUCCESS(Status))
1319 SubKey->KeyCell = NewKeyCell;
1320 SubKey->BlockOffset = NKBOffset;
1322 /* Don't modify hash table if key is volatile and parent is not */
1323 if (IsVolatileHive(RegistryHive) && (!IsVolatileHive(Parent->RegistryHive)))
1328 if (KeyCell->HashTableOffset == (ULONG_PTR) -1)
1330 Status = CmiAllocateHashTableBlock(RegistryHive,
1332 &KeyCell->HashTableOffset,
1333 REG_INIT_HASH_TABLE_SIZE);
1334 if (!NT_SUCCESS(Status))
1341 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1342 if (((KeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
1344 BLOCK_OFFSET HTOffset;
1346 /* Reallocate the hash table block */
1347 Status = CmiAllocateHashTableBlock(RegistryHive,
1350 HashBlock->HashTableSize +
1351 REG_EXTEND_HASH_TABLE_SIZE);
1352 if (!NT_SUCCESS(Status))
1357 RtlZeroMemory(&NewHashBlock->Table[0],
1358 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
1359 RtlCopyMemory(&NewHashBlock->Table[0],
1360 &HashBlock->Table[0],
1361 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
1362 CmiDestroyBlock(RegistryHive,
1364 KeyCell->HashTableOffset);
1365 KeyCell->HashTableOffset = HTOffset;
1366 HashBlock = NewHashBlock;
1370 Status = CmiAddKeyToHashTable(RegistryHive,
1374 if (NT_SUCCESS(Status))
1376 KeyCell->NumberOfSubKeys++;
1384 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
1385 PKEY_OBJECT ParentKey,
1388 PHASH_TABLE_CELL HashBlock;
1390 DPRINT1("CmiRemoveSubKey() called\n");
1392 /* Remove the key from the parent key's hash block */
1393 if (ParentKey->KeyCell->HashTableOffset != -1)
1395 DPRINT1("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset)
1396 HashBlock = CmiGetBlock(RegistryHive,
1397 ParentKey->KeyCell->HashTableOffset,
1399 DPRINT1("ParentKey HashBlock %p\n", HashBlock)
1400 if (HashBlock != NULL)
1402 CmiRemoveKeyFromHashTable(RegistryHive,
1404 SubKey->BlockOffset);
1405 CmiMarkBlockDirty(RegistryHive,
1406 ParentKey->KeyCell->HashTableOffset);
1410 /* Remove the key's hash block */
1411 if (SubKey->KeyCell->HashTableOffset != -1)
1413 DPRINT1("SubKey HashTableOffset %lx\n", SubKey->KeyCell->HashTableOffset)
1414 HashBlock = CmiGetBlock(RegistryHive,
1415 SubKey->KeyCell->HashTableOffset,
1417 DPRINT1("SubKey HashBlock %p\n", HashBlock)
1418 if (HashBlock != NULL)
1420 CmiDestroyBlock(RegistryHive,
1422 SubKey->KeyCell->HashTableOffset);
1423 SubKey->KeyCell->HashTableOffset = -1;
1427 /* Decrement the number of the parent key's sub keys */
1428 if (ParentKey != NULL)
1430 DPRINT1("ParentKey %p\n", ParentKey)
1431 ParentKey->KeyCell->NumberOfSubKeys--;
1432 NtQuerySystemTime((PTIME)&ParentKey->KeyCell->LastWriteTime);
1433 CmiMarkBlockDirty(RegistryHive,
1434 ParentKey->BlockOffset);
1436 /* Remove the parent key's hash table */
1437 if (ParentKey->KeyCell->NumberOfSubKeys == 0)
1439 DPRINT1("FIXME: Remove parent key hash table\n")
1444 /* Destroy key cell */
1445 CmiDestroyBlock(RegistryHive,
1447 SubKey->BlockOffset);
1448 SubKey->BlockOffset = -1;
1449 SubKey->KeyCell = NULL;
1451 /* FIXME: Merge free blocks within the Bin */
1453 return(STATUS_SUCCESS);
1458 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
1459 IN PKEY_CELL KeyCell,
1460 IN PUNICODE_STRING ValueName,
1461 OUT PVALUE_CELL *ValueCell,
1462 OUT BLOCK_OFFSET *VBOffset)
1464 PVALUE_LIST_CELL ValueListCell;
1465 PVALUE_CELL CurValueCell;
1468 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1472 if (ValueListCell == NULL)
1474 DPRINT("ValueListCell is NULL\n");
1475 return STATUS_SUCCESS;
1478 VERIFY_VALUE_LIST_CELL(ValueListCell);
1480 for (i = 0; i < KeyCell->NumberOfValues; i++)
1482 CurValueCell = CmiGetBlock(RegistryHive,
1483 ValueListCell->Values[i],
1486 if ((CurValueCell != NULL) &&
1487 CmiComparePackedNames(ValueName,
1489 CurValueCell->NameSize,
1490 CurValueCell->Flags & REG_VALUE_NAME_PACKED))
1492 *ValueCell = CurValueCell;
1494 *VBOffset = ValueListCell->Values[i];
1495 //DPRINT("Found value %s\n", ValueName);
1498 CmiReleaseBlock(RegistryHive, CurValueCell);
1501 CmiReleaseBlock(RegistryHive, ValueListCell);
1503 return STATUS_SUCCESS;
1508 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
1509 IN PKEY_CELL KeyCell,
1511 OUT PVALUE_CELL *ValueCell)
1513 PVALUE_LIST_CELL ValueListCell;
1514 PVALUE_CELL CurValueCell;
1516 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1520 if (ValueListCell == NULL)
1522 return STATUS_NO_MORE_ENTRIES;
1525 VERIFY_VALUE_LIST_CELL(ValueListCell);
1527 if (Index >= KeyCell->NumberOfValues)
1529 return STATUS_NO_MORE_ENTRIES;
1532 CurValueCell = CmiGetBlock(RegistryHive,
1533 ValueListCell->Values[Index],
1536 if (CurValueCell != NULL)
1538 *ValueCell = CurValueCell;
1541 CmiReleaseBlock(RegistryHive, CurValueCell);
1542 CmiReleaseBlock(RegistryHive, ValueListCell);
1544 return STATUS_SUCCESS;
1549 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
1550 IN PKEY_CELL KeyCell,
1551 IN PUNICODE_STRING ValueName,
1552 OUT PVALUE_CELL *pValueCell,
1553 OUT BLOCK_OFFSET *pVBOffset)
1555 PVALUE_LIST_CELL NewValueListCell;
1556 PVALUE_LIST_CELL ValueListCell;
1557 PVALUE_CELL NewValueCell;
1558 BLOCK_OFFSET VLBOffset;
1559 BLOCK_OFFSET VBOffset;
1562 Status = CmiAllocateValueCell(RegistryHive,
1566 *pVBOffset = VBOffset;
1568 if (!NT_SUCCESS(Status))
1573 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1575 if (ValueListCell == NULL)
1577 Status = CmiAllocateBlock(RegistryHive,
1578 (PVOID) &ValueListCell,
1579 sizeof(BLOCK_OFFSET) * 3,
1582 if (!NT_SUCCESS(Status))
1584 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
1587 KeyCell->ValuesOffset = VLBOffset;
1589 else if ((KeyCell->NumberOfValues
1590 >= (ULONG) ((LONG) (ValueListCell->CellSize - 4)) / (LONG) sizeof(BLOCK_OFFSET)))
1592 Status = CmiAllocateBlock(RegistryHive,
1593 (PVOID) &NewValueListCell,
1594 sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues + REG_VALUE_LIST_CELL_MULTIPLE),
1597 if (!NT_SUCCESS(Status))
1599 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
1603 RtlCopyMemory(&NewValueListCell->Values[0],
1604 &ValueListCell->Values[0],
1605 sizeof(BLOCK_OFFSET) * KeyCell->NumberOfValues);
1606 CmiDestroyBlock(RegistryHive, ValueListCell, KeyCell->ValuesOffset);
1607 KeyCell->ValuesOffset = VLBOffset;
1608 ValueListCell = NewValueListCell;
1611 DPRINT("KeyCell->NumberOfValues %d, ValueListCell->CellSize %d (%d %x)\n",
1612 KeyCell->NumberOfValues, ValueListCell->CellSize,
1613 -(ValueListCell->CellSize - 4) / sizeof(BLOCK_OFFSET),
1614 -(ValueListCell->CellSize - 4) / sizeof(BLOCK_OFFSET));
1616 ValueListCell->Values[KeyCell->NumberOfValues] = VBOffset;
1617 KeyCell->NumberOfValues++;
1618 CmiReleaseBlock(RegistryHive, ValueListCell);
1619 CmiReleaseBlock(RegistryHive, NewValueCell);
1620 *pValueCell = NewValueCell;
1622 return STATUS_SUCCESS;
1627 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
1628 IN PKEY_CELL KeyCell,
1629 IN BLOCK_OFFSET KeyCellOffset,
1630 IN PUNICODE_STRING ValueName)
1632 PVALUE_LIST_CELL ValueListCell;
1633 PVALUE_CELL CurValueCell;
1636 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1638 if (ValueListCell == NULL)
1640 return STATUS_SUCCESS;
1643 VERIFY_VALUE_LIST_CELL(ValueListCell);
1645 for (i = 0; i < KeyCell->NumberOfValues; i++)
1647 CurValueCell = CmiGetBlock(RegistryHive, ValueListCell->Values[i], NULL);
1649 if ((CurValueCell != NULL) &&
1650 CmiComparePackedNames(ValueName,
1652 CurValueCell->NameSize,
1653 CurValueCell->Flags & REG_VALUE_NAME_PACKED))
1655 if ((KeyCell->NumberOfValues - 1) < i)
1657 RtlCopyMemory(&ValueListCell->Values[i],
1658 &ValueListCell->Values[i + 1],
1659 sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues - 1 - i));
1663 RtlZeroMemory(&ValueListCell->Values[i], sizeof(BLOCK_OFFSET));
1666 KeyCell->NumberOfValues -= 1;
1667 CmiDestroyValueCell(RegistryHive, CurValueCell, ValueListCell->Values[i]);
1670 CmiReleaseBlock(RegistryHive, CurValueCell);
1673 CmiReleaseBlock(RegistryHive, ValueListCell);
1675 if (KeyCell->NumberOfValues == 0)
1677 CmiDestroyBlock(RegistryHive,
1679 KeyCell->ValuesOffset);
1683 CmiMarkBlockDirty(RegistryHive,
1684 KeyCell->ValuesOffset);
1687 CmiMarkBlockDirty(RegistryHive,
1690 return STATUS_SUCCESS;
1695 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive,
1696 OUT PHASH_TABLE_CELL *HashBlock,
1697 OUT BLOCK_OFFSET *HBOffset,
1698 IN ULONG HashTableSize)
1700 PHASH_TABLE_CELL NewHashBlock;
1704 Status = STATUS_SUCCESS;
1706 NewHashSize = sizeof(HASH_TABLE_CELL) +
1707 (HashTableSize - 1) * sizeof(HASH_RECORD);
1708 Status = CmiAllocateBlock(RegistryHive,
1709 (PVOID*) &NewHashBlock,
1713 if ((NewHashBlock == NULL) || (!NT_SUCCESS(Status)))
1715 Status = STATUS_INSUFFICIENT_RESOURCES;
1719 NewHashBlock->Id = REG_HASH_TABLE_BLOCK_ID;
1720 NewHashBlock->HashTableSize = HashTableSize;
1721 *HashBlock = NewHashBlock;
1729 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
1730 PHASH_TABLE_CELL HashBlock,
1733 BLOCK_OFFSET KeyOffset;
1736 if (HashBlock == NULL)
1739 if (IsVolatileHive(RegistryHive))
1741 KeyCell = (PKEY_CELL) HashBlock->Table[Index].KeyOffset;
1745 KeyOffset = HashBlock->Table[Index].KeyOffset;
1746 KeyCell = CmiGetBlock(RegistryHive, KeyOffset, NULL);
1748 CmiLockBlock(RegistryHive, KeyCell);
1755 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
1756 PHASH_TABLE_CELL HashBlock,
1757 PKEY_CELL NewKeyCell,
1758 BLOCK_OFFSET NKBOffset)
1762 for (i = 0; i < HashBlock->HashTableSize; i++)
1764 if (HashBlock->Table[i].KeyOffset == 0)
1766 HashBlock->Table[i].KeyOffset = NKBOffset;
1767 RtlCopyMemory(&HashBlock->Table[i].HashValue, NewKeyCell->Name, 4);
1768 return STATUS_SUCCESS;
1772 return STATUS_UNSUCCESSFUL;
1777 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive,
1778 PHASH_TABLE_CELL HashBlock,
1779 BLOCK_OFFSET NKBOffset)
1783 for (i = 0; i < HashBlock->HashTableSize; i++)
1785 if (HashBlock->Table[i].KeyOffset == NKBOffset)
1787 HashBlock->Table[i].KeyOffset = 0;
1788 RtlZeroMemory(&HashBlock->Table[i].HashValue, 4);
1789 return STATUS_SUCCESS;
1793 return STATUS_UNSUCCESSFUL;
1798 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
1799 PVALUE_CELL *ValueCell,
1800 BLOCK_OFFSET *VBOffset,
1801 IN PUNICODE_STRING ValueName)
1803 PVALUE_CELL NewValueCell;
1809 Status = STATUS_SUCCESS;
1811 NameSize = CmiGetPackedNameLength(ValueName,
1814 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName->Length, NameSize);
1816 Status = CmiAllocateBlock(RegistryHive,
1817 (PVOID*) &NewValueCell,
1818 sizeof(VALUE_CELL) + NameSize,
1820 if ((NewValueCell == NULL) || (!NT_SUCCESS(Status)))
1822 Status = STATUS_INSUFFICIENT_RESOURCES;
1826 NewValueCell->Id = REG_VALUE_CELL_ID;
1827 NewValueCell->NameSize = NameSize;
1830 /* Pack the value name */
1831 for (i = 0; i < NameSize; i++)
1832 NewValueCell->Name[i] = (CHAR)ValueName->Buffer[i];
1833 NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
1837 /* Copy the value name */
1838 RtlCopyMemory(NewValueCell->Name,
1841 NewValueCell->Flags = 0;
1843 NewValueCell->DataType = 0;
1844 NewValueCell->DataSize = 0;
1845 NewValueCell->DataOffset = 0xffffffff;
1846 *ValueCell = NewValueCell;
1854 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
1855 PVALUE_CELL ValueCell,
1856 BLOCK_OFFSET VBOffset)
1862 VERIFY_VALUE_CELL(ValueCell);
1864 /* First, release data: */
1865 if (ValueCell->DataSize > 4)
1867 pBlock = CmiGetBlock(RegistryHive, ValueCell->DataOffset, &pBin);
1868 Status = CmiDestroyBlock(RegistryHive, pBlock, ValueCell->DataOffset);
1869 if (!NT_SUCCESS(Status))
1874 /* Update time of heap */
1875 if (IsPermanentHive(RegistryHive))
1876 ZwQuerySystemTime((PTIME) &pBin->DateModified);
1879 Status = CmiDestroyBlock(RegistryHive, ValueCell, VBOffset);
1881 /* Update time of heap */
1882 if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
1884 ZwQuerySystemTime((PTIME) &pBin->DateModified);
1892 CmiAddBin(PREGISTRY_HIVE RegistryHive,
1894 BLOCK_OFFSET *NewBlockOffset)
1896 PCELL_HEADER tmpBlock;
1897 PHBIN * tmpBlockList;
1900 tmpBin = ExAllocatePool(PagedPool, REG_BLOCK_SIZE);
1903 return STATUS_INSUFFICIENT_RESOURCES;
1906 tmpBin->BlockId = REG_BIN_ID;
1907 tmpBin->BlockOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
1908 RegistryHive->FileSize += REG_BLOCK_SIZE;
1909 tmpBin->BlockSize = REG_BLOCK_SIZE;
1910 tmpBin->Unused1 = 0;
1911 ZwQuerySystemTime((PTIME) &tmpBin->DateModified);
1912 tmpBin->Unused2 = 0;
1914 /* Increase size of list of blocks */
1915 tmpBlockList = ExAllocatePool(NonPagedPool,
1916 sizeof(PHBIN *) * (RegistryHive->BlockListSize + 1));
1917 if (tmpBlockList == NULL)
1920 return STATUS_INSUFFICIENT_RESOURCES;
1923 if (RegistryHive->BlockListSize > 0)
1925 memcpy(tmpBlockList,
1926 RegistryHive->BlockList,
1927 sizeof(PHBIN *)*(RegistryHive->BlockListSize));
1928 ExFreePool(RegistryHive->BlockList);
1931 RegistryHive->BlockList = tmpBlockList;
1932 RegistryHive->BlockList[RegistryHive->BlockListSize++] = tmpBin;
1934 /* Initialize a free block in this heap : */
1935 tmpBlock = (PCELL_HEADER)((ULONG_PTR) tmpBin + REG_HBIN_DATA_OFFSET);
1936 tmpBlock->CellSize = (REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET);
1938 /* Grow bitmap if necessary */
1939 if (IsVolatileHive(RegistryHive) &&
1940 (RegistryHive->BlockListSize % (sizeof(ULONG) * 8) == 0))
1942 DPRINT1("Grow hive bitmap - BlockListSize %lu\n", RegistryHive->BlockListSize);
1948 *NewBlock = (PVOID) tmpBlock;
1951 *NewBlockOffset = tmpBin->BlockOffset + REG_HBIN_DATA_OFFSET;
1953 /* FIXME: set first dword to block_offset of another free bloc */
1955 return STATUS_SUCCESS;
1960 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive,
1963 BLOCK_OFFSET * pBlockOffset)
1965 PCELL_HEADER NewBlock;
1969 Status = STATUS_SUCCESS;
1971 /* Round to 16 bytes multiple */
1972 BlockSize = (BlockSize + sizeof(DWORD) + 15) & 0xfffffff0;
1974 /* Handle volatile hives first */
1975 if (IsVolatileHive(RegistryHive))
1977 NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
1979 if (NewBlock == NULL)
1981 Status = STATUS_INSUFFICIENT_RESOURCES;
1985 RtlZeroMemory(NewBlock, BlockSize);
1986 NewBlock->CellSize = BlockSize;
1987 CmiLockBlock(RegistryHive, NewBlock);
1990 *pBlockOffset = (BLOCK_OFFSET) NewBlock;
1997 /* first search in free blocks */
1999 for (i = 0; i < RegistryHive->FreeListSize; i++)
2001 if (RegistryHive->FreeList[i]->CellSize >= BlockSize)
2005 NewBlock = RegistryHive->FreeList[i];
2007 *pBlockOffset = RegistryHive->FreeListOffset[i];
2009 /* Update time of heap */
2010 Temp = CmiGetBlock(RegistryHive, RegistryHive->FreeListOffset[i], &pBin);
2014 ZwQuerySystemTime((PTIME) &pBin->DateModified);
2015 CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]);
2018 if ((i + 1) < RegistryHive->FreeListSize)
2020 RtlMoveMemory(&RegistryHive->FreeList[i],
2021 &RegistryHive->FreeList[i + 1],
2022 sizeof(RegistryHive->FreeList[0])
2023 * (RegistryHive->FreeListSize - i - 1));
2024 RtlMoveMemory(&RegistryHive->FreeListOffset[i],
2025 &RegistryHive->FreeListOffset[i + 1],
2026 sizeof(RegistryHive->FreeListOffset[0])
2027 * (RegistryHive->FreeListSize - i - 1));
2029 RegistryHive->FreeListSize--;
2034 /* Need to extend hive file : */
2035 if (NewBlock == NULL)
2037 /* Add a new block */
2038 Status = CmiAddBin(RegistryHive, (PVOID *) &NewBlock , pBlockOffset);
2041 if (NT_SUCCESS(Status))
2045 /* Split the block in two parts */
2046 if (NewBlock->CellSize > BlockSize)
2048 NewBlock = (PCELL_HEADER) ((ULONG_PTR) NewBlock+BlockSize);
2049 NewBlock->CellSize = ((PCELL_HEADER) (*Block))->CellSize - BlockSize;
2050 CmiAddFree(RegistryHive, NewBlock, *pBlockOffset + BlockSize);
2051 CmiMarkBlockDirty(RegistryHive, *pBlockOffset + BlockSize);
2053 else if (NewBlock->CellSize < BlockSize)
2055 return(STATUS_UNSUCCESSFUL);
2058 RtlZeroMemory(*Block, BlockSize);
2059 ((PCELL_HEADER) (*Block))->CellSize = -BlockSize;
2060 CmiLockBlock(RegistryHive, *Block);
2069 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive,
2071 BLOCK_OFFSET Offset)
2076 Status = STATUS_SUCCESS;
2078 if (IsVolatileHive(RegistryHive))
2080 CmiReleaseBlock(RegistryHive, Block);
2085 PCELL_HEADER pFree = Block;
2087 if (pFree->CellSize < 0)
2088 pFree->CellSize = -pFree->CellSize;
2090 /* Clear block (except the block size) */
2091 RtlZeroMemory(((PVOID)pFree) + sizeof(ULONG),
2092 pFree->CellSize - sizeof(ULONG));
2094 CmiAddFree(RegistryHive, Block, Offset);
2095 CmiReleaseBlock(RegistryHive, Block);
2097 /* Update time of heap */
2098 if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, Offset,&pBin))
2099 ZwQuerySystemTime((PTIME) &pBin->DateModified);
2101 CmiMarkBlockDirty(RegistryHive, Offset);
2103 /* FIXME: Set first dword to block_offset of another free block ? */
2104 /* FIXME: Concatenate with previous and next block if free */
2112 CmiAddFree(PREGISTRY_HIVE RegistryHive,
2113 PCELL_HEADER FreeBlock,
2114 BLOCK_OFFSET FreeOffset)
2116 PCELL_HEADER *tmpList;
2117 BLOCK_OFFSET *tmpListOffset;
2122 assert(RegistryHive);
2125 DPRINT("FreeBlock %.08x FreeOffset %.08x\n",
2126 FreeBlock, FreeOffset);
2128 if ((RegistryHive->FreeListSize + 1) > RegistryHive->FreeListMax)
2131 tmpList = ExAllocatePool(PagedPool,
2132 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax + 32));
2135 if (tmpList == NULL)
2136 return STATUS_INSUFFICIENT_RESOURCES;
2139 tmpListOffset = ExAllocatePool(PagedPool,
2140 sizeof(BLOCK_OFFSET *) * (RegistryHive->FreeListMax + 32));
2143 if (tmpListOffset == NULL)
2145 ExFreePool(tmpList);
2146 return STATUS_INSUFFICIENT_RESOURCES;
2150 if (RegistryHive->FreeListMax)
2153 RtlMoveMemory(tmpList,
2154 RegistryHive->FreeList,
2155 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
2157 RtlMoveMemory(tmpListOffset,
2158 RegistryHive->FreeListOffset,
2159 sizeof(BLOCK_OFFSET *) * (RegistryHive->FreeListMax));
2161 ExFreePool(RegistryHive->FreeList);
2163 ExFreePool(RegistryHive->FreeListOffset);
2167 RegistryHive->FreeList = tmpList;
2168 RegistryHive->FreeListOffset = tmpListOffset;
2169 RegistryHive->FreeListMax += 32;
2174 /* Add new offset to free list, maintaining list in ascending order */
2175 if ((RegistryHive->FreeListSize == 0)
2176 || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
2179 /* Add to end of list */
2180 RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
2181 RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
2183 else if (RegistryHive->FreeListOffset[0] > FreeOffset)
2186 /* Add to begin of list */
2187 RtlMoveMemory(&RegistryHive->FreeList[1],
2188 &RegistryHive->FreeList[0],
2189 sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
2190 RtlMoveMemory(&RegistryHive->FreeListOffset[1],
2191 &RegistryHive->FreeListOffset[0],
2192 sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
2193 RegistryHive->FreeList[0] = FreeBlock;
2194 RegistryHive->FreeListOffset[0] = FreeOffset;
2195 RegistryHive->FreeListSize++;
2200 /* Search where to insert */
2202 maxInd = RegistryHive->FreeListSize - 1;
2203 while ((maxInd - minInd) > 1)
2205 medInd = (minInd + maxInd) / 2;
2206 if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
2212 /* Insert before maxInd */
2213 RtlMoveMemory(&RegistryHive->FreeList[maxInd+1],
2214 &RegistryHive->FreeList[maxInd],
2215 sizeof(RegistryHive->FreeList[0]) * (RegistryHive->FreeListSize - minInd));
2216 RtlMoveMemory(&RegistryHive->FreeListOffset[maxInd + 1],
2217 &RegistryHive->FreeListOffset[maxInd],
2218 sizeof(RegistryHive->FreeListOffset[0]) * (RegistryHive->FreeListSize-minInd));
2219 RegistryHive->FreeList[maxInd] = FreeBlock;
2220 RegistryHive->FreeListOffset[maxInd] = FreeOffset;
2221 RegistryHive->FreeListSize++;
2225 return STATUS_SUCCESS;
2230 CmiGetBlock(PREGISTRY_HIVE RegistryHive,
2231 BLOCK_OFFSET BlockOffset,
2237 if ((BlockOffset == 0) || (BlockOffset == (ULONG_PTR) -1))
2240 if (IsVolatileHive(RegistryHive))
2242 return (PVOID) BlockOffset;
2248 pBin = RegistryHive->BlockList[BlockOffset / 4096];
2251 return ((PVOID) ((ULONG_PTR) pBin + (BlockOffset - pBin->BlockOffset)));
2257 CmiLockBlock(PREGISTRY_HIVE RegistryHive,
2260 if (IsPermanentHive(RegistryHive))
2262 /* FIXME: Implement */
2268 CmiReleaseBlock(PREGISTRY_HIVE RegistryHive,
2271 if (IsPermanentHive(RegistryHive))
2273 /* FIXME: Implement */
2279 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
2280 BLOCK_OFFSET BlockOffset)
2284 if (IsVolatileHive(RegistryHive))
2287 Index = (ULONG)BlockOffset / 4096;
2289 DPRINT1("CmiMarkBlockDirty(Offset 0x%lx) Index %lu\n",
2290 (ULONG)BlockOffset, Index);
2292 RegistryHive->HiveDirty = TRUE;
2293 RtlSetBits(&RegistryHive->DirtyBitMap,
2300 CmiGetPackedNameLength(IN PUNICODE_STRING Name,
2301 OUT PBOOLEAN Packable)
2305 if (Packable != NULL)
2308 for (i = 0; i < Name->Length; i++)
2310 if (Name->Buffer[i] > 0xFF)
2312 if (Packable != NULL)
2314 return(Name->Length);
2318 return(Name->Length / sizeof(WCHAR));
2323 CmiComparePackedNames(IN PUNICODE_STRING Name,
2324 IN PCHAR NameBuffer,
2325 IN USHORT NameBufferSize,
2326 IN BOOLEAN NamePacked)
2331 if (NamePacked == TRUE)
2333 if (Name->Length != NameBufferSize * sizeof(WCHAR))
2336 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
2338 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar((WCHAR)NameBuffer[i]))
2344 if (Name->Length != NameBufferSize)
2347 UNameBuffer = (PWCHAR)NameBuffer;
2349 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
2351 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar(UNameBuffer[i]))
2361 CmiCopyPackedName(PWCHAR NameBuffer,
2362 PCHAR PackedNameBuffer,
2363 ULONG PackedNameSize)
2367 for (i = 0; i < PackedNameSize; i++)
2368 NameBuffer[i] = (WCHAR)PackedNameBuffer[i];