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
,
511 if (CreateNew
== TRUE
)
512 CreateDisposition
= FILE_OPEN_IF
;
514 CreateDisposition
= FILE_OPEN
;
516 Status
= NtCreateFile(&FileHandle
,
521 FILE_ATTRIBUTE_NORMAL
,
524 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
527 if (!NT_SUCCESS(Status
))
529 RtlFreeUnicodeString(&RegistryHive
->Filename
);
530 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status
);
534 if ((CreateNew
) && (IoSB
.Information
== FILE_CREATED
))
536 Status
= CmiCreateNewRegFile(FileHandle
);
537 if (!NT_SUCCESS(Status
))
539 DPRINT1("CmiCreateNewRegFile() failed (Status %lx)\n", Status
);
540 RtlFreeUnicodeString(&RegistryHive
->Filename
);
545 Status
= ObReferenceObjectByHandle(FileHandle
,
549 (PVOID
*)&RegistryHive
->FileObject
,
552 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
554 if (!NT_SUCCESS(Status
))
557 RtlFreeUnicodeString(&RegistryHive
->Filename
);
558 DPRINT1("CmiInitPermanentRegistryHive() - ObReferenceObjectByHandle Failed with status %x.\n", Status
);
562 /* Read hive header */
563 FileOffset
.u
.HighPart
= 0;
564 FileOffset
.u
.LowPart
= 0;
565 DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle
, sizeof(HIVE_HEADER
), RegistryHive
->HiveHeader
);
566 Status
= NtReadFile(FileHandle
,
571 RegistryHive
->HiveHeader
,
575 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
576 if (!NT_SUCCESS(Status
))
578 ObDereferenceObject(RegistryHive
->FileObject
);
579 RtlFreeUnicodeString(&RegistryHive
->Filename
);
580 DPRINT("CmiInitPermanentRegistryHive() - Failed 4.\n");
584 Status
= NtQueryInformationFile(FileHandle
,
588 FileStandardInformation
);
590 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
592 if (!NT_SUCCESS(Status
))
594 ObDereferenceObject(RegistryHive
->FileObject
);
595 RtlFreeUnicodeString(&RegistryHive
->Filename
);
596 DPRINT("CmiInitPermanentRegistryHive() - Failed 5.\n");
601 /* We have a reference to the file object so we don't need the handle anymore */
605 RegistryHive
->FileSize
= fsi
.EndOfFile
.u
.LowPart
;
607 // assert(RegistryHive->FileSize);
608 if (RegistryHive
->FileSize
)
610 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ 4096) - 1;
614 ObDereferenceObject(RegistryHive
->FileObject
);
615 RtlFreeUnicodeString(&RegistryHive
->Filename
);
616 DPRINT("CmiInitPermanentRegistryHive() - Failed, zero length hive file.\n");
617 return STATUS_INSUFFICIENT_RESOURCES
;
620 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ 4096) - 1;
623 DPRINT("Space needed for block list describing hive: 0x%x\n",
624 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
626 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
627 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
629 if (RegistryHive
->BlockList
== NULL
)
631 ExFreePool(RegistryHive
->BlockList
);
632 ObDereferenceObject(RegistryHive
->FileObject
);
633 RtlFreeUnicodeString(&RegistryHive
->Filename
);
634 DPRINT("CmiInitPermanentRegistryHive() - Failed 6.\n");
635 return STATUS_INSUFFICIENT_RESOURCES
;
639 /* Map hive into cache memory (readonly) (skip the base block) */
640 FileOffset
.u
.HighPart
= 0;
641 FileOffset
.u
.LowPart
= 4096;
642 Success
= CcMapData(RegistryHive
->FileObject
, /* File object */
643 &FileOffset
, /* File offset */
644 RegistryHive
->FileSize
- 4096, /* Region length */
645 TRUE
, /* Wait if needed */
646 &RegistryHive
->Bcb
, /* OUT: Buffer Control Block */
647 (PVOID
*) &RegistryHive
->BlockList
[0]); /* OUT: Mapped data pointer */
649 assertmsg(Success
, ("Success: %d\n", Success
));
653 ExFreePool(RegistryHive
->BlockList
);
654 ObDereferenceObject(RegistryHive
->FileObject
);
655 RtlFreeUnicodeString(&RegistryHive
->Filename
);
656 DPRINT("CmiInitPermanentRegistryHive() - Failed 7.\n");
662 RegistryHive
->BlockList
[0] = ExAllocatePool(PagedPool
,
663 RegistryHive
->FileSize
- 4096);
665 RtlZeroMemory(RegistryHive
->BlockList
[0], RegistryHive
->FileSize
- 4096);
668 if (RegistryHive
->BlockList
[0] == NULL
)
670 ExFreePool(RegistryHive
->BlockList
);
671 ObDereferenceObject(RegistryHive
->FileObject
);
672 RtlFreeUnicodeString(&RegistryHive
->Filename
);
673 DPRINT("CmiInitPermanentRegistryHive() - Failed 8.\n");
674 return STATUS_INSUFFICIENT_RESOURCES
;
677 FileOffset
.u
.HighPart
= 0;
678 FileOffset
.u
.LowPart
= 4096;
680 DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle
, RegistryHive
->FileSize
- 4096, (PVOID
)RegistryHive
->BlockList
[0]);
681 Status
= NtReadFile(FileHandle
,
686 (PVOID
) RegistryHive
->BlockList
[0],
687 RegistryHive
->FileSize
- 4096,
691 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
696 RegistryHive
->FreeListSize
= 0;
697 RegistryHive
->FreeListMax
= 0;
698 RegistryHive
->FreeList
= NULL
;
701 for (i
= 0; i
< RegistryHive
->BlockListSize
; i
++)
703 RegistryHive
->BlockList
[i
] = (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[0]) + BlockOffset
);
704 tmpBin
= (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[i
]));
705 if (tmpBin
->BlockId
!= REG_BIN_ID
)
707 DPRINT("Bad BlockId %x, offset %x\n", tmpBin
->BlockId
, BlockOffset
);
709 return STATUS_INSUFFICIENT_RESOURCES
;
712 assertmsg((tmpBin
->BlockSize
% 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin
->BlockSize
));
714 if (tmpBin
->BlockSize
> 4096)
716 for (j
= 1; j
< tmpBin
->BlockSize
/ 4096; j
++)
718 RegistryHive
->BlockList
[i
+ j
] = RegistryHive
->BlockList
[i
];
723 /* Search free blocks and add to list */
724 FreeOffset
= REG_HBIN_DATA_OFFSET
;
725 while (FreeOffset
< tmpBin
->BlockSize
)
727 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) RegistryHive
->BlockList
[i
] + FreeOffset
);
728 if (FreeBlock
->CellSize
> 0)
730 Status
= CmiAddFree(RegistryHive
,
732 RegistryHive
->BlockList
[i
]->BlockOffset
+ FreeOffset
);
734 if (!NT_SUCCESS(Status
))
740 FreeOffset
+= FreeBlock
->CellSize
;
744 FreeOffset
-= FreeBlock
->CellSize
;
747 BlockOffset
+= tmpBin
->BlockSize
;
750 /* Create block bitmap and clear all bits */
752 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
753 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
754 DPRINT1("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
755 DPRINT1("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
756 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
758 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
761 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
762 RegistryHive
->HiveDirty
= FALSE
;
764 DPRINT1("CmiInitPermanentRegistryHive(%p, %S, %d) - Finished.\n", RegistryHive
, Filename
, CreateNew
);
766 return(STATUS_SUCCESS
);
771 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive
)
773 PKEY_CELL RootKeyCell
;
775 RegistryHive
->Flags
|= HIVE_VOLATILE
;
777 CmiCreateDefaultHiveHeader(RegistryHive
->HiveHeader
);
779 RootKeyCell
= (PKEY_CELL
) ExAllocatePool(NonPagedPool
, sizeof(KEY_CELL
));
781 if (RootKeyCell
== NULL
)
782 return STATUS_INSUFFICIENT_RESOURCES
;
784 CmiCreateDefaultRootKeyCell(RootKeyCell
);
786 RegistryHive
->HiveHeader
->RootKeyCell
= (BLOCK_OFFSET
) RootKeyCell
;
788 return STATUS_SUCCESS
;
793 CmiCreateRegistryHive(PWSTR Filename
,
794 PREGISTRY_HIVE
*RegistryHive
,
801 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename
);
803 *RegistryHive
= NULL
;
805 Hive
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_HIVE
));
807 return(STATUS_INSUFFICIENT_RESOURCES
);
809 DPRINT("Hive %x\n", Hive
);
811 RtlZeroMemory(Hive
, sizeof(REGISTRY_HIVE
));
813 Hive
->HiveHeader
= (PHIVE_HEADER
)
814 ExAllocatePool(NonPagedPool
, sizeof(HIVE_HEADER
));
816 if (Hive
->HiveHeader
== NULL
)
819 return(STATUS_INSUFFICIENT_RESOURCES
);
822 if (Filename
!= NULL
)
824 Status
= CmiInitPermanentRegistryHive(Hive
, Filename
, CreateNew
);
828 Status
= CmiInitVolatileRegistryHive(Hive
);
831 if (!NT_SUCCESS(Status
))
833 ExFreePool(Hive
->HiveHeader
);
838 ExInitializeResourceLite(&Hive
->HiveResource
);
840 /* Add the new hive to the hive list */
841 KeAcquireSpinLock(&CmiHiveListLock
,&oldlvl
);
842 InsertHeadList(&CmiHiveListHead
, &Hive
->HiveList
);
843 KeReleaseSpinLock(&CmiHiveListLock
,oldlvl
);
845 VERIFY_REGISTRY_HIVE(Hive
);
847 *RegistryHive
= Hive
;
849 DPRINT("CmiCreateRegistryHive(Filename %S) - Finished.\n", Filename
);
851 return(STATUS_SUCCESS
);
856 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
860 /* Remove hive from hive list */
861 KeAcquireSpinLock(&CmiHiveListLock
,&oldlvl
);
862 RemoveEntryList(&RegistryHive
->HiveList
);
863 KeReleaseSpinLock(&CmiHiveListLock
,oldlvl
);
866 /* FIXME: Remove attached keys and values */
869 /* Release hive header */
870 ExFreePool(RegistryHive
->HiveHeader
);
873 ExFreePool(RegistryHive
);
875 return(STATUS_SUCCESS
);
880 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
885 LARGE_INTEGER FileOffset
;
886 OBJECT_ATTRIBUTES ObjectAttributes
;
887 IO_STATUS_BLOCK IoStatusBlock
;
894 DPRINT("CmiFlushRegistryHive() called\n");
896 if (RegistryHive
->HiveDirty
== FALSE
)
898 return(STATUS_SUCCESS
);
901 DPRINT1("Hive '%wZ' is dirty\n", &RegistryHive
->Filename
);
904 /* Open hive for writing */
905 InitializeObjectAttributes(&ObjectAttributes
,
906 &RegistryHive
->Filename
,
911 Status
= NtCreateFile(&FileHandle
,
916 FILE_ATTRIBUTE_NORMAL
,
919 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
922 if (!NT_SUCCESS(Status
))
924 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status
);
933 BlockIndex
= RtlFindSetBitsAndClear(&RegistryHive
->DirtyBitMap
,
936 if (BlockIndex
== (ULONG
)-1)
938 DPRINT("No more set bits\n");
942 DPRINT1("Block %lu is dirty\n", BlockIndex
);
944 BlockOffset
= RegistryHive
->BlockList
[BlockIndex
]->BlockOffset
;
945 DPRINT1("Block offset %lx\n", BlockOffset
);
947 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
] + ((BlockIndex
* 4096) - BlockOffset
);
948 DPRINT1("BlockPtr %p\n", BlockPtr
);
950 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096ULL;
951 DPRINT1("File offset %I64x\n", FileOffset
.QuadPart
);
954 /* Write hive block */
955 Status
= NtWriteFile(FileHandle
,
964 if (!NT_SUCCESS(Status
))
966 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
977 /* Clear dirty flag */
978 RegistryHive
->HiveDirty
= FALSE
;
980 DPRINT("CmiFlushRegistryHive() done\n");
982 return(STATUS_SUCCESS
);
987 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive
,
990 PHASH_TABLE_CELL HashBlock
;
991 PKEY_CELL CurSubKeyCell
;
995 VERIFY_KEY_CELL(KeyCell
);
998 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
999 if (HashBlock
== NULL
)
1004 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1006 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
1008 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1009 HashBlock
->Table
[i
].KeyOffset
,
1011 if (MaxName
< CurSubKeyCell
->NameSize
)
1013 MaxName
= CurSubKeyCell
->NameSize
;
1015 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1019 CmiReleaseBlock(RegistryHive
, HashBlock
);
1026 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive
,
1029 PHASH_TABLE_CELL HashBlock
;
1030 PKEY_CELL CurSubKeyCell
;
1034 VERIFY_KEY_CELL(KeyCell
);
1037 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1038 if (HashBlock
== NULL
)
1043 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1045 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
1047 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1048 HashBlock
->Table
[i
].KeyOffset
,
1050 if (MaxClass
< CurSubKeyCell
->ClassSize
)
1052 MaxClass
= CurSubKeyCell
->ClassSize
;
1054 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1058 CmiReleaseBlock(RegistryHive
, HashBlock
);
1065 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
1068 PVALUE_LIST_CELL ValueListCell
;
1069 PVALUE_CELL CurValueCell
;
1073 VERIFY_KEY_CELL(KeyCell
);
1075 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1077 if (ValueListCell
== NULL
)
1082 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1084 CurValueCell
= CmiGetBlock(RegistryHive
,
1085 ValueListCell
->Values
[i
],
1087 if (CurValueCell
!= NULL
&&
1088 MaxValueName
< CurValueCell
->NameSize
)
1090 MaxValueName
= CurValueCell
->NameSize
;
1092 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1095 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1097 return MaxValueName
;
1102 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
1105 PVALUE_LIST_CELL ValueListCell
;
1106 PVALUE_CELL CurValueCell
;
1110 VERIFY_KEY_CELL(KeyCell
);
1112 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1114 if (ValueListCell
== NULL
)
1119 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1121 CurValueCell
= CmiGetBlock(RegistryHive
,
1122 ValueListCell
->Values
[i
],NULL
);
1123 if ((CurValueCell
!= NULL
) &&
1124 (MaxValueData
< (CurValueCell
->DataSize
& LONG_MAX
)))
1126 MaxValueData
= CurValueCell
->DataSize
& LONG_MAX
;
1128 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1131 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1133 return MaxValueData
;
1138 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
1139 IN PKEY_CELL KeyCell
,
1140 OUT PKEY_CELL
*SubKeyCell
,
1141 OUT BLOCK_OFFSET
*BlockOffset
,
1143 IN ACCESS_MASK DesiredAccess
,
1144 IN ULONG Attributes
)
1146 PHASH_TABLE_CELL HashBlock
;
1147 PKEY_CELL CurSubKeyCell
;
1151 VERIFY_KEY_CELL(KeyCell
);
1153 //DPRINT("Scanning for sub key %s\n", KeyName);
1155 assert(RegistryHive
);
1157 KeyLength
= strlen(KeyName
);
1159 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1161 if (HashBlock
== NULL
)
1163 return STATUS_SUCCESS
;
1166 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
)
1167 && (i
< HashBlock
->HashTableSize
); i
++)
1169 if (Attributes
& OBJ_CASE_INSENSITIVE
)
1171 if ((HashBlock
->Table
[i
].KeyOffset
!= 0) &&
1172 (HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1) &&
1173 (_strnicmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4) == 0))
1175 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1176 HashBlock
->Table
[i
].KeyOffset
,
1178 if ((CurSubKeyCell
->NameSize
== KeyLength
)
1179 && (_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
) == 0))
1181 *SubKeyCell
= CurSubKeyCell
;
1182 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
1187 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1193 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
1194 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
1195 !strncmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4))
1197 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1198 HashBlock
->Table
[i
].KeyOffset
,NULL
);
1199 if (CurSubKeyCell
->NameSize
== KeyLength
1200 && !_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
))
1202 *SubKeyCell
= CurSubKeyCell
;
1203 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
1208 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1214 CmiReleaseBlock(RegistryHive
, HashBlock
);
1216 return STATUS_SUCCESS
;
1221 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
1224 PWSTR NewSubKeyName
,
1225 USHORT NewSubKeyNameSize
,
1227 PUNICODE_STRING Class
,
1228 ULONG CreateOptions
)
1230 PHASH_TABLE_CELL NewHashBlock
;
1231 PHASH_TABLE_CELL HashBlock
;
1232 BLOCK_OFFSET NKBOffset
;
1233 PKEY_CELL NewKeyCell
;
1239 KeyCell
= Parent
->KeyCell
;
1241 VERIFY_KEY_CELL(KeyCell
);
1243 if (NewSubKeyName
[0] == L
'\\')
1246 NameSize
= NewSubKeyNameSize
/ 2 - 1;
1250 NameSize
= NewSubKeyNameSize
/ 2;
1252 Status
= STATUS_SUCCESS
;
1254 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
1255 Status
= CmiAllocateBlock(RegistryHive
,
1256 (PVOID
) &NewKeyCell
,
1260 if (NewKeyCell
== NULL
)
1262 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1266 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
1267 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
1268 ZwQuerySystemTime((PTIME
) &NewKeyCell
->LastWriteTime
);
1269 NewKeyCell
->ParentKeyOffset
= -1;
1270 NewKeyCell
->NumberOfSubKeys
= 0;
1271 NewKeyCell
->HashTableOffset
= -1;
1272 NewKeyCell
->NumberOfValues
= 0;
1273 NewKeyCell
->ValuesOffset
= -1;
1274 NewKeyCell
->SecurityKeyOffset
= -1;
1275 NewKeyCell
->NameSize
= NameSize
;
1276 wcstombs(NewKeyCell
->Name
, NewSubKeyName
, NameSize
);
1277 NewKeyCell
->ClassNameOffset
= -1;
1279 VERIFY_KEY_CELL(NewKeyCell
);
1285 NewKeyCell
->ClassSize
= Class
->Length
+ sizeof(WCHAR
);
1286 Status
= CmiAllocateBlock(RegistryHive
,
1288 NewKeyCell
->ClassSize
,
1289 &NewKeyCell
->ClassNameOffset
);
1290 wcsncpy((PWSTR
) pClass
->Data
, Class
->Buffer
, Class
->Length
);
1291 ((PWSTR
) (pClass
->Data
))[Class
->Length
] = 0;
1295 if (!NT_SUCCESS(Status
))
1300 SubKey
->KeyCell
= NewKeyCell
;
1301 SubKey
->BlockOffset
= NKBOffset
;
1303 /* Don't modify hash table if key is volatile and parent is not */
1304 if (IsVolatileHive(RegistryHive
) && (!IsVolatileHive(Parent
->RegistryHive
)))
1309 if (KeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
1311 Status
= CmiAllocateHashTableBlock(RegistryHive
,
1313 &KeyCell
->HashTableOffset
,
1314 REG_INIT_HASH_TABLE_SIZE
);
1315 if (!NT_SUCCESS(Status
))
1322 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1323 if (((KeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
1325 BLOCK_OFFSET HTOffset
;
1327 /* Reallocate the hash table block */
1328 Status
= CmiAllocateHashTableBlock(RegistryHive
,
1331 HashBlock
->HashTableSize
+
1332 REG_EXTEND_HASH_TABLE_SIZE
);
1333 if (!NT_SUCCESS(Status
))
1338 RtlZeroMemory(&NewHashBlock
->Table
[0],
1339 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
1340 RtlCopyMemory(&NewHashBlock
->Table
[0],
1341 &HashBlock
->Table
[0],
1342 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
1343 CmiDestroyBlock(RegistryHive
, HashBlock
, KeyCell
->HashTableOffset
);
1344 KeyCell
->HashTableOffset
= HTOffset
;
1345 HashBlock
= NewHashBlock
;
1349 Status
= CmiAddKeyToHashTable(RegistryHive
, HashBlock
, NewKeyCell
, NKBOffset
);
1350 if (NT_SUCCESS(Status
))
1352 KeyCell
->NumberOfSubKeys
++;
1360 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
1361 IN PKEY_CELL KeyCell
,
1362 IN PUNICODE_STRING ValueName
,
1363 OUT PVALUE_CELL
*ValueCell
,
1364 OUT BLOCK_OFFSET
*VBOffset
)
1366 PVALUE_LIST_CELL ValueListCell
;
1367 PVALUE_CELL CurValueCell
;
1370 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1374 if (ValueListCell
== NULL
)
1376 DPRINT("ValueListCell is NULL\n");
1377 return STATUS_SUCCESS
;
1380 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1382 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1384 CurValueCell
= CmiGetBlock(RegistryHive
,
1385 ValueListCell
->Values
[i
],
1388 if ((CurValueCell
!= NULL
) &&
1389 CmiComparePackedNames(ValueName
,
1391 CurValueCell
->NameSize
,
1392 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
1394 *ValueCell
= CurValueCell
;
1396 *VBOffset
= ValueListCell
->Values
[i
];
1397 //DPRINT("Found value %s\n", ValueName);
1400 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1403 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1405 return STATUS_SUCCESS
;
1410 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
1411 IN PKEY_CELL KeyCell
,
1413 OUT PVALUE_CELL
*ValueCell
)
1415 PVALUE_LIST_CELL ValueListCell
;
1416 PVALUE_CELL CurValueCell
;
1418 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1422 if (ValueListCell
== NULL
)
1424 return STATUS_NO_MORE_ENTRIES
;
1427 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1429 if (Index
>= KeyCell
->NumberOfValues
)
1431 return STATUS_NO_MORE_ENTRIES
;
1434 CurValueCell
= CmiGetBlock(RegistryHive
,
1435 ValueListCell
->Values
[Index
],
1438 if (CurValueCell
!= NULL
)
1440 *ValueCell
= CurValueCell
;
1443 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1444 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1446 return STATUS_SUCCESS
;
1451 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
1452 IN PKEY_CELL KeyCell
,
1453 IN PUNICODE_STRING ValueName
,
1454 OUT PVALUE_CELL
*pValueCell
,
1455 OUT BLOCK_OFFSET
*pVBOffset
)
1457 PVALUE_LIST_CELL NewValueListCell
;
1458 PVALUE_LIST_CELL ValueListCell
;
1459 PVALUE_CELL NewValueCell
;
1460 BLOCK_OFFSET VLBOffset
;
1461 BLOCK_OFFSET VBOffset
;
1464 Status
= CmiAllocateValueCell(RegistryHive
,
1468 *pVBOffset
= VBOffset
;
1470 if (!NT_SUCCESS(Status
))
1475 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1477 if (ValueListCell
== NULL
)
1479 Status
= CmiAllocateBlock(RegistryHive
,
1480 (PVOID
) &ValueListCell
,
1481 sizeof(BLOCK_OFFSET
) * 3,
1484 if (!NT_SUCCESS(Status
))
1486 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
1489 KeyCell
->ValuesOffset
= VLBOffset
;
1491 else if ((KeyCell
->NumberOfValues
1492 >= (ULONG
) ((LONG
) (ValueListCell
->CellSize
- 4)) / (LONG
) sizeof(BLOCK_OFFSET
)))
1494 Status
= CmiAllocateBlock(RegistryHive
,
1495 (PVOID
) &NewValueListCell
,
1496 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
),
1499 if (!NT_SUCCESS(Status
))
1501 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
1505 RtlCopyMemory(&NewValueListCell
->Values
[0],
1506 &ValueListCell
->Values
[0],
1507 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
1508 CmiDestroyBlock(RegistryHive
, ValueListCell
, KeyCell
->ValuesOffset
);
1509 KeyCell
->ValuesOffset
= VLBOffset
;
1510 ValueListCell
= NewValueListCell
;
1513 DPRINT("KeyCell->NumberOfValues %d, ValueListCell->CellSize %d (%d %x)\n",
1514 KeyCell
->NumberOfValues
, ValueListCell
->CellSize
,
1515 -(ValueListCell
->CellSize
- 4) / sizeof(BLOCK_OFFSET
),
1516 -(ValueListCell
->CellSize
- 4) / sizeof(BLOCK_OFFSET
));
1518 ValueListCell
->Values
[KeyCell
->NumberOfValues
] = VBOffset
;
1519 KeyCell
->NumberOfValues
++;
1520 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1521 CmiReleaseBlock(RegistryHive
, NewValueCell
);
1522 *pValueCell
= NewValueCell
;
1524 return STATUS_SUCCESS
;
1529 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
1530 IN PKEY_CELL KeyCell
,
1531 IN PUNICODE_STRING ValueName
)
1533 PVALUE_LIST_CELL ValueListCell
;
1534 PVALUE_CELL CurValueCell
;
1537 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1539 if (ValueListCell
== NULL
)
1541 return STATUS_SUCCESS
;
1544 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1546 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1548 CurValueCell
= CmiGetBlock(RegistryHive
, ValueListCell
->Values
[i
], NULL
);
1550 if ((CurValueCell
!= NULL
) &&
1551 CmiComparePackedNames(ValueName
,
1553 CurValueCell
->NameSize
,
1554 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
1556 if ((KeyCell
->NumberOfValues
- 1) < i
)
1558 RtlCopyMemory(&ValueListCell
->Values
[i
],
1559 &ValueListCell
->Values
[i
+ 1],
1560 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
1564 RtlZeroMemory(&ValueListCell
->Values
[i
], sizeof(BLOCK_OFFSET
));
1567 KeyCell
->NumberOfValues
-= 1;
1568 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->Values
[i
]);
1571 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1574 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1576 return STATUS_SUCCESS
;
1581 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive
,
1582 OUT PHASH_TABLE_CELL
*HashBlock
,
1583 OUT BLOCK_OFFSET
*HBOffset
,
1584 IN ULONG HashTableSize
)
1586 PHASH_TABLE_CELL NewHashBlock
;
1590 Status
= STATUS_SUCCESS
;
1592 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
1593 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
1594 Status
= CmiAllocateBlock(RegistryHive
,
1595 (PVOID
*) &NewHashBlock
,
1599 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
1601 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1605 NewHashBlock
->Id
= REG_HASH_TABLE_BLOCK_ID
;
1606 NewHashBlock
->HashTableSize
= HashTableSize
;
1607 *HashBlock
= NewHashBlock
;
1615 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
1616 PHASH_TABLE_CELL HashBlock
,
1619 BLOCK_OFFSET KeyOffset
;
1622 if (HashBlock
== NULL
)
1625 if (IsVolatileHive(RegistryHive
))
1627 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
1631 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
1632 KeyCell
= CmiGetBlock(RegistryHive
, KeyOffset
, NULL
);
1634 CmiLockBlock(RegistryHive
, KeyCell
);
1641 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
1642 PHASH_TABLE_CELL HashBlock
,
1643 PKEY_CELL NewKeyCell
,
1644 BLOCK_OFFSET NKBOffset
)
1648 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1650 if (HashBlock
->Table
[i
].KeyOffset
== 0)
1652 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
1653 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
, NewKeyCell
->Name
, 4);
1654 return STATUS_SUCCESS
;
1658 return STATUS_UNSUCCESSFUL
;
1663 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
1664 PHASH_TABLE_CELL HashBlock
,
1665 BLOCK_OFFSET NKBOffset
)
1669 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1671 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
1673 HashBlock
->Table
[i
].KeyOffset
= 0;
1674 RtlZeroMemory(&HashBlock
->Table
[i
].HashValue
, 4);
1675 return STATUS_SUCCESS
;
1679 return STATUS_UNSUCCESSFUL
;
1684 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
1685 PVALUE_CELL
*ValueCell
,
1686 BLOCK_OFFSET
*VBOffset
,
1687 IN PUNICODE_STRING ValueName
)
1689 PVALUE_CELL NewValueCell
;
1695 Status
= STATUS_SUCCESS
;
1697 NameSize
= CmiGetPackedNameLength(ValueName
,
1700 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
1702 Status
= CmiAllocateBlock(RegistryHive
,
1703 (PVOID
*) &NewValueCell
,
1704 sizeof(VALUE_CELL
) + NameSize
,
1706 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
1708 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1712 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
1713 NewValueCell
->NameSize
= NameSize
;
1716 /* Pack the value name */
1717 for (i
= 0; i
< NameSize
; i
++)
1718 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
1719 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
1723 /* Copy the value name */
1724 RtlCopyMemory(NewValueCell
->Name
,
1727 NewValueCell
->Flags
= 0;
1729 NewValueCell
->DataType
= 0;
1730 NewValueCell
->DataSize
= 0;
1731 NewValueCell
->DataOffset
= 0xffffffff;
1732 *ValueCell
= NewValueCell
;
1740 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
1741 PVALUE_CELL ValueCell
,
1742 BLOCK_OFFSET VBOffset
)
1748 VERIFY_VALUE_CELL(ValueCell
);
1750 /* First, release datas: */
1751 if (ValueCell
->DataSize
> 0)
1753 pBlock
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, &pBin
);
1754 Status
= CmiDestroyBlock(RegistryHive
, pBlock
, ValueCell
->DataOffset
);
1755 if (!NT_SUCCESS(Status
))
1760 /* Update time of heap */
1761 if (IsPermanentHive(RegistryHive
))
1762 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
1765 Status
= CmiDestroyBlock(RegistryHive
, ValueCell
, VBOffset
);
1767 /* Update time of heap */
1768 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, VBOffset
, &pBin
))
1770 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
1778 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
1780 BLOCK_OFFSET
*NewBlockOffset
)
1782 PCELL_HEADER tmpBlock
;
1783 PHBIN
* tmpBlockList
;
1786 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
1789 return STATUS_INSUFFICIENT_RESOURCES
;
1792 tmpBin
->BlockId
= REG_BIN_ID
;
1793 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
1794 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
1795 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
1796 tmpBin
->Unused1
= 0;
1797 ZwQuerySystemTime((PTIME
) &tmpBin
->DateModified
);
1798 tmpBin
->Unused2
= 0;
1800 /* Increase size of list of blocks */
1801 tmpBlockList
= ExAllocatePool(NonPagedPool
,
1802 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
1803 if (tmpBlockList
== NULL
)
1806 return STATUS_INSUFFICIENT_RESOURCES
;
1809 if (RegistryHive
->BlockListSize
> 0)
1811 memcpy(tmpBlockList
,
1812 RegistryHive
->BlockList
,
1813 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
1814 ExFreePool(RegistryHive
->BlockList
);
1817 RegistryHive
->BlockList
= tmpBlockList
;
1818 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
++] = tmpBin
;
1820 /* Initialize a free block in this heap : */
1821 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
1822 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
1824 /* Grow bitmap if necessary */
1825 if (IsVolatileHive(RegistryHive
) &&
1826 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
1828 DPRINT1("Grow hive bitmap - BlockListSize %lu\n", RegistryHive
->BlockListSize
);
1834 *NewBlock
= (PVOID
) tmpBlock
;
1837 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
1839 /* FIXME: set first dword to block_offset of another free bloc */
1841 return STATUS_SUCCESS
;
1846 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive
,
1849 BLOCK_OFFSET
* pBlockOffset
)
1851 PCELL_HEADER NewBlock
;
1855 Status
= STATUS_SUCCESS
;
1857 /* Round to 16 bytes multiple */
1858 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
1860 /* Handle volatile hives first */
1861 if (IsVolatileHive(RegistryHive
))
1863 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
1865 if (NewBlock
== NULL
)
1867 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1871 RtlZeroMemory(NewBlock
, BlockSize
);
1872 NewBlock
->CellSize
= BlockSize
;
1873 CmiLockBlock(RegistryHive
, NewBlock
);
1876 *pBlockOffset
= (BLOCK_OFFSET
) NewBlock
;
1883 /* first search in free blocks */
1885 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
1887 if (RegistryHive
->FreeList
[i
]->CellSize
>= BlockSize
)
1891 NewBlock
= RegistryHive
->FreeList
[i
];
1893 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
1895 /* Update time of heap */
1896 Temp
= CmiGetBlock(RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
1900 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
1901 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
1904 if ((i
+ 1) < RegistryHive
->FreeListSize
)
1906 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
1907 &RegistryHive
->FreeList
[i
+ 1],
1908 sizeof(RegistryHive
->FreeList
[0])
1909 * (RegistryHive
->FreeListSize
- i
- 1));
1910 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
1911 &RegistryHive
->FreeListOffset
[i
+ 1],
1912 sizeof(RegistryHive
->FreeListOffset
[0])
1913 * (RegistryHive
->FreeListSize
- i
- 1));
1915 RegistryHive
->FreeListSize
--;
1920 /* Need to extend hive file : */
1921 if (NewBlock
== NULL
)
1923 /* Add a new block */
1924 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewBlock
, pBlockOffset
);
1927 if (NT_SUCCESS(Status
))
1931 /* Split the block in two parts */
1932 if (NewBlock
->CellSize
> BlockSize
)
1934 NewBlock
= (PCELL_HEADER
) ((ULONG_PTR
) NewBlock
+BlockSize
);
1935 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- BlockSize
;
1936 CmiAddFree(RegistryHive
, NewBlock
, *pBlockOffset
+ BlockSize
);
1937 CmiMarkBlockDirty(RegistryHive
, *pBlockOffset
+ BlockSize
);
1939 else if (NewBlock
->CellSize
< BlockSize
)
1941 return(STATUS_UNSUCCESSFUL
);
1944 RtlZeroMemory(*Block
, BlockSize
);
1945 ((PCELL_HEADER
) (*Block
))->CellSize
= -BlockSize
;
1946 CmiLockBlock(RegistryHive
, *Block
);
1955 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive
,
1957 BLOCK_OFFSET Offset
)
1962 Status
= STATUS_SUCCESS
;
1964 if (IsVolatileHive(RegistryHive
))
1966 CmiReleaseBlock(RegistryHive
, Block
);
1971 PCELL_HEADER pFree
= Block
;
1973 if (pFree
->CellSize
< 0)
1974 pFree
->CellSize
= -pFree
->CellSize
;
1976 /* Clear block (except the block size) */
1977 RtlZeroMemory(((PVOID
)pFree
) + sizeof(ULONG
),
1978 pFree
->CellSize
- sizeof(ULONG
));
1980 CmiAddFree(RegistryHive
, Block
, Offset
);
1981 CmiReleaseBlock(RegistryHive
, Block
);
1983 /* Update time of heap */
1984 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, Offset
,&pBin
))
1985 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
1987 CmiMarkBlockDirty(RegistryHive
, Offset
);
1989 /* FIXME: Set first dword to block_offset of another free block ? */
1990 /* FIXME: Concatenate with previous and next block if free */
1998 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
1999 PCELL_HEADER FreeBlock
,
2000 BLOCK_OFFSET FreeOffset
)
2002 PCELL_HEADER
*tmpList
;
2003 BLOCK_OFFSET
*tmpListOffset
;
2008 assert(RegistryHive
);
2011 DPRINT("FreeBlock %.08x FreeOffset %.08x\n",
2012 FreeBlock
, FreeOffset
);
2014 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
2017 tmpList
= ExAllocatePool(PagedPool
,
2018 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
2021 if (tmpList
== NULL
)
2022 return STATUS_INSUFFICIENT_RESOURCES
;
2025 tmpListOffset
= ExAllocatePool(PagedPool
,
2026 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
+ 32));
2029 if (tmpListOffset
== NULL
)
2031 ExFreePool(tmpList
);
2032 return STATUS_INSUFFICIENT_RESOURCES
;
2036 if (RegistryHive
->FreeListMax
)
2039 RtlMoveMemory(tmpList
,
2040 RegistryHive
->FreeList
,
2041 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
2043 RtlMoveMemory(tmpListOffset
,
2044 RegistryHive
->FreeListOffset
,
2045 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
));
2047 ExFreePool(RegistryHive
->FreeList
);
2049 ExFreePool(RegistryHive
->FreeListOffset
);
2053 RegistryHive
->FreeList
= tmpList
;
2054 RegistryHive
->FreeListOffset
= tmpListOffset
;
2055 RegistryHive
->FreeListMax
+= 32;
2060 /* Add new offset to free list, maintaining list in ascending order */
2061 if ((RegistryHive
->FreeListSize
== 0)
2062 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
2065 /* Add to end of list */
2066 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
2067 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
2069 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
2072 /* Add to begin of list */
2073 RtlMoveMemory(&RegistryHive
->FreeList
[1],
2074 &RegistryHive
->FreeList
[0],
2075 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
2076 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
2077 &RegistryHive
->FreeListOffset
[0],
2078 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
2079 RegistryHive
->FreeList
[0] = FreeBlock
;
2080 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
2081 RegistryHive
->FreeListSize
++;
2086 /* Search where to insert */
2088 maxInd
= RegistryHive
->FreeListSize
- 1;
2089 while ((maxInd
- minInd
) > 1)
2091 medInd
= (minInd
+ maxInd
) / 2;
2092 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
2098 /* Insert before maxInd */
2099 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
2100 &RegistryHive
->FreeList
[maxInd
],
2101 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
2102 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
2103 &RegistryHive
->FreeListOffset
[maxInd
],
2104 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
2105 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
2106 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
2107 RegistryHive
->FreeListSize
++;
2111 return STATUS_SUCCESS
;
2116 CmiGetBlock(PREGISTRY_HIVE RegistryHive
,
2117 BLOCK_OFFSET BlockOffset
,
2123 if ((BlockOffset
== 0) || (BlockOffset
== (ULONG_PTR
) -1))
2126 if (IsVolatileHive(RegistryHive
))
2128 return (PVOID
) BlockOffset
;
2134 pBin
= RegistryHive
->BlockList
[BlockOffset
/ 4096];
2137 return ((PVOID
) ((ULONG_PTR
) pBin
+ (BlockOffset
- pBin
->BlockOffset
)));
2143 CmiLockBlock(PREGISTRY_HIVE RegistryHive
,
2146 if (IsPermanentHive(RegistryHive
))
2148 /* FIXME: Implement */
2154 CmiReleaseBlock(PREGISTRY_HIVE RegistryHive
,
2157 if (IsPermanentHive(RegistryHive
))
2159 /* FIXME: Implement */
2165 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
2166 BLOCK_OFFSET BlockOffset
)
2170 if (IsVolatileHive(RegistryHive
))
2173 Index
= (ULONG
)BlockOffset
/ 4096;
2175 DPRINT1("CmiMarkBlockDirty(Offset 0x%lx) Index %lu\n", (ULONG
)BlockOffset
, Index
);
2177 RegistryHive
->HiveDirty
= TRUE
;
2178 RtlSetBits(&RegistryHive
->DirtyBitMap
,
2185 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
2186 OUT PBOOLEAN Packable
)
2190 if (Packable
!= NULL
)
2193 for (i
= 0; i
< Name
->Length
; i
++)
2195 if (Name
->Buffer
[i
] > 0xFF)
2197 if (Packable
!= NULL
)
2199 return(Name
->Length
);
2203 return(Name
->Length
/ sizeof(WCHAR
));
2208 CmiComparePackedNames(IN PUNICODE_STRING Name
,
2209 IN PCHAR NameBuffer
,
2210 IN USHORT NameBufferSize
,
2211 IN BOOLEAN NamePacked
)
2216 if (NamePacked
== TRUE
)
2218 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
2221 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
2223 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
2229 if (Name
->Length
!= NameBufferSize
)
2232 UNameBuffer
= (PWCHAR
)NameBuffer
;
2234 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
2236 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
2246 CmiCopyPackedName(PWCHAR NameBuffer
,
2247 PCHAR PackedNameBuffer
,
2248 ULONG PackedNameSize
)
2252 for (i
= 0; i
< PackedNameSize
; i
++)
2253 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];