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))
28 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
30 BOOLEAN CmiDoVerify
= FALSE
;
32 /* FUNCTIONS ****************************************************************/
35 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header
)
38 RtlZeroMemory(Header
, sizeof(HIVE_HEADER
));
39 Header
->BlockId
= REG_HIVE_ID
;
40 Header
->UpdateCounter1
= 0;
41 Header
->UpdateCounter2
= 0;
42 Header
->DateModified
.dwLowDateTime
= 0;
43 Header
->DateModified
.dwHighDateTime
= 0;
49 Header
->RootKeyCell
= 0;
50 Header
->BlockSize
= REG_BLOCK_SIZE
;
57 CmiCreateDefaultBinCell(PHBIN BinCell
)
60 RtlZeroMemory(BinCell
, sizeof(HBIN
));
61 BinCell
->BlockId
= REG_BIN_ID
;
62 BinCell
->DateModified
.dwLowDateTime
= 0;
63 BinCell
->DateModified
.dwHighDateTime
= 0;
64 BinCell
->BlockSize
= REG_BLOCK_SIZE
;
69 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
)
72 RtlZeroMemory(RootKeyCell
, sizeof(KEY_CELL
));
74 RootKeyCell
->CellSize
= -(LONG
)sizeof(KEY_CELL
);
76 RootKeyCell
->CellSize
= -sizeof(KEY_CELL
);
78 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
79 RootKeyCell
->Type
= REG_ROOT_KEY_CELL_TYPE
;
80 ZwQuerySystemTime((PTIME
) &RootKeyCell
->LastWriteTime
);
81 RootKeyCell
->ParentKeyOffset
= 0;
82 RootKeyCell
->NumberOfSubKeys
= 0;
83 RootKeyCell
->HashTableOffset
= -1;
84 RootKeyCell
->NumberOfValues
= 0;
85 RootKeyCell
->ValuesOffset
= -1;
86 RootKeyCell
->SecurityKeyOffset
= 0;
87 RootKeyCell
->ClassNameOffset
= -1;
88 RootKeyCell
->NameSize
= 0;
89 RootKeyCell
->ClassSize
= 0;
94 CmiVerifyBinCell(PHBIN BinCell
)
101 if (BinCell
->BlockId
!= REG_BIN_ID
)
103 DbgPrint("BlockId is %.08x (should be %.08x)\n",
104 BinCell
->BlockId
, REG_BIN_ID
);
105 assert(BinCell
->BlockId
== REG_BIN_ID
);
108 //BinCell->DateModified.dwLowDateTime
110 //BinCell->DateModified.dwHighDateTime
113 if (BinCell
->BlockSize
!= REG_BLOCK_SIZE
)
115 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
116 BinCell
->BlockSize
, REG_BLOCK_SIZE
);
117 assert(BinCell
->BlockSize
== REG_BLOCK_SIZE
);
125 CmiVerifyKeyCell(PKEY_CELL KeyCell
)
132 if (KeyCell
->CellSize
== 0)
134 DbgPrint("CellSize is %d (must not be 0)\n",
136 assert(KeyCell
->CellSize
!= 0);
139 if (KeyCell
->Id
!= REG_KEY_CELL_ID
)
141 DbgPrint("Id is %.08x (should be %.08x)\n",
142 KeyCell
->Id
, REG_KEY_CELL_ID
);
143 assert(KeyCell
->Id
== REG_KEY_CELL_ID
);
146 if ((KeyCell
->Type
!= REG_KEY_CELL_TYPE
)
147 && (KeyCell
->Type
!= REG_ROOT_KEY_CELL_TYPE
))
149 DbgPrint("Type is %.08x (should be %.08x or %.08x)\n",
150 KeyCell
->Type
, REG_KEY_CELL_TYPE
, REG_ROOT_KEY_CELL_TYPE
);
154 //KeyCell->LastWriteTime;
156 if (KeyCell
->ParentKeyOffset
< 0)
158 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
159 KeyCell
->ParentKeyOffset
);
160 assert(KeyCell
->ParentKeyOffset
>= 0);
163 if (KeyCell
->NumberOfSubKeys
< 0)
165 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
166 KeyCell
->NumberOfSubKeys
);
167 assert(KeyCell
->NumberOfSubKeys
>= 0);
170 //KeyCell->HashTableOffset;
172 if (KeyCell
->NumberOfValues
< 0)
174 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
175 KeyCell
->NumberOfValues
);
176 assert(KeyCell
->NumberOfValues
>= 0);
179 //KeyCell->ValuesOffset = -1;
181 if (KeyCell
->SecurityKeyOffset
< 0)
183 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
184 KeyCell
->SecurityKeyOffset
);
185 assert(KeyCell
->SecurityKeyOffset
>= 0);
188 //KeyCell->ClassNameOffset = -1;
199 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell
)
204 CmiVerifyKeyCell(RootKeyCell
);
206 if (RootKeyCell
->Type
!= REG_ROOT_KEY_CELL_TYPE
)
208 DbgPrint("Type is %.08x (should be %.08x)\n",
209 RootKeyCell
->Type
, REG_ROOT_KEY_CELL_TYPE
);
210 assert(RootKeyCell
->Type
== REG_ROOT_KEY_CELL_TYPE
);
218 CmiVerifyValueCell(PVALUE_CELL ValueCell
)
225 if (ValueCell
->CellSize
== 0)
227 DbgPrint("CellSize is %d (must not be 0)\n",
228 ValueCell
->CellSize
);
229 assert(ValueCell
->CellSize
!= 0);
232 if (ValueCell
->Id
!= REG_VALUE_CELL_ID
)
234 DbgPrint("Id is %.08x (should be %.08x)\n",
235 ValueCell
->Id
, REG_VALUE_CELL_ID
);
236 assert(ValueCell
->Id
== REG_VALUE_CELL_ID
);
239 //ValueCell->NameSize;
240 //ValueCell->LONG DataSize;
241 //ValueCell->DataOffset;
242 //ValueCell->ULONG DataType;
243 //ValueCell->USHORT Flags;
244 //ValueCell->USHORT Unused1;
245 //ValueCell->UCHAR Name[0];
251 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell
)
256 if (ValueListCell
->CellSize
== 0)
258 DbgPrint("CellSize is %d (must not be 0)\n",
259 ValueListCell
->CellSize
);
260 assert(ValueListCell
->CellSize
!= 0);
268 CmiVerifyKeyObject(PKEY_OBJECT KeyObject
)
273 if (KeyObject
->RegistryHive
== NULL
)
275 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
276 KeyObject
->RegistryHive
);
277 assert(KeyObject
->RegistryHive
!= NULL
);
280 if (KeyObject
->KeyCell
== NULL
)
282 DbgPrint("KeyCell is NULL (must not be NULL)\n",
284 assert(KeyObject
->KeyCell
!= NULL
);
287 if (KeyObject
->ParentKey
== NULL
)
289 DbgPrint("ParentKey is NULL (must not be NULL)\n",
290 KeyObject
->ParentKey
);
291 assert(KeyObject
->ParentKey
!= NULL
);
299 CmiVerifyHiveHeader(PHIVE_HEADER Header
)
304 if (Header
->BlockId
!= REG_HIVE_ID
)
306 DbgPrint("BlockId is %.08x (must be %.08x)\n",
309 assert(Header
->BlockId
== REG_HIVE_ID
);
312 if (Header
->Unused3
!= 1)
314 DbgPrint("Unused3 is %.08x (must be 1)\n",
316 assert(Header
->Unused3
== 1);
319 if (Header
->Unused4
!= 3)
321 DbgPrint("Unused4 is %.08x (must be 3)\n",
323 assert(Header
->Unused4
== 3);
326 if (Header
->Unused5
!= 0)
328 DbgPrint("Unused5 is %.08x (must be 0)\n",
330 assert(Header
->Unused5
== 0);
333 if (Header
->Unused6
!= 1)
335 DbgPrint("Unused6 is %.08x (must be 1)\n",
337 assert(Header
->Unused6
== 1);
340 if (Header
->Unused7
!= 1)
342 DbgPrint("Unused7 is %.08x (must be 1)\n",
344 assert(Header
->Unused7
== 1);
352 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive
)
357 CmiVerifyHiveHeader(RegistryHive
->HiveHeader
);
364 CmiPopulateHive(HANDLE FileHandle
)
366 IO_STATUS_BLOCK IoStatusBlock
;
367 LARGE_INTEGER FileOffset
;
368 PCELL_HEADER FreeCell
;
374 tBuf
= (PCHAR
) ExAllocatePool(NonPagedPool
, REG_BLOCK_SIZE
);
376 return STATUS_INSUFFICIENT_RESOURCES
;
378 BinCell
= (PHBIN
) tBuf
;
379 FreeCell
= (PCELL_HEADER
) (tBuf
+ REG_HBIN_DATA_OFFSET
);
381 CmiCreateDefaultBinCell(BinCell
);
383 // The whole block is free
384 FreeCell
->CellSize
= REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
;
386 // Add free blocks so we don't need to expand
387 // the file for a while
388 for (i
= 0; i
< 50; i
++)
390 // Block offset of this bin
391 BinCell
->BlockOffset
= (2 + i
) * REG_BLOCK_SIZE
;
393 FileOffset
.u
.HighPart
= 0;
394 FileOffset
.u
.LowPart
= (2 + i
) * REG_BLOCK_SIZE
;
396 Status
= ZwWriteFile(FileHandle
,
405 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
406 if (!NT_SUCCESS(Status
))
420 CmiCreateNewRegFile(HANDLE FileHandle
)
422 IO_STATUS_BLOCK IoStatusBlock
;
423 PCELL_HEADER FreeCell
;
424 PHIVE_HEADER HiveHeader
;
425 PKEY_CELL RootKeyCell
;
430 Buffer
= (PCHAR
) ExAllocatePool(NonPagedPool
, 2 * REG_BLOCK_SIZE
);
432 return STATUS_INSUFFICIENT_RESOURCES
;
434 HiveHeader
= (PHIVE_HEADER
)Buffer
;
435 BinCell
= (PHBIN
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
);
436 RootKeyCell
= (PKEY_CELL
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
);
437 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)Buffer
+ REG_BLOCK_SIZE
+ REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
439 CmiCreateDefaultHiveHeader(HiveHeader
);
440 CmiCreateDefaultBinCell(BinCell
);
441 CmiCreateDefaultRootKeyCell(RootKeyCell
);
444 BinCell
->BlockOffset
= 0;
446 /* Offset to root key block */
447 HiveHeader
->RootKeyCell
= REG_HBIN_DATA_OFFSET
;
449 /* The rest of the block is free */
450 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
452 Status
= NtWriteFile(FileHandle
,
464 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
466 if (!NT_SUCCESS(Status
))
472 if (NT_SUCCESS(Status
))
474 CmiPopulateHive(FileHandle
);
478 Status
= NtFlushBuffersFile(FileHandle
,
486 CmiInitNonVolatileRegistryHive(PREGISTRY_HIVE RegistryHive
,
490 OBJECT_ATTRIBUTES ObjectAttributes
;
491 FILE_STANDARD_INFORMATION fsi
;
492 PCELL_HEADER FreeBlock
;
493 LARGE_INTEGER FileOffset
;
494 BLOCK_OFFSET BlockOffset
;
495 ULONG CreateDisposition
;
496 IO_STATUS_BLOCK IoSB
;
505 DPRINT1("CmiInitNonVolatileRegistryHive(%p, %S, %d) - Entered.\n", RegistryHive
, Filename
, CreateNew
);
507 /* Duplicate Filename */
508 Status
= RtlCreateUnicodeString(&RegistryHive
->HiveFileName
,
510 if (!NT_SUCCESS(Status
))
512 DPRINT1("CmiInitNonVolatileRegistryHive() - Failed 1.\n");
516 /* Create log file name */
517 RegistryHive
->LogFileName
.Length
= (wcslen(Filename
) + 4) * sizeof(WCHAR
);
518 RegistryHive
->LogFileName
.MaximumLength
= RegistryHive
->LogFileName
.Length
+ sizeof(WCHAR
);
519 RegistryHive
->LogFileName
.Buffer
= ExAllocatePool(NonPagedPool
,
520 RegistryHive
->LogFileName
.MaximumLength
);
521 if (RegistryHive
->LogFileName
.Buffer
== NULL
)
523 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
524 DPRINT1("ExAllocatePool() failed\n");
525 return(STATUS_INSUFFICIENT_RESOURCES
);
527 wcscpy(RegistryHive
->LogFileName
.Buffer
,
529 wcscat(RegistryHive
->LogFileName
.Buffer
,
532 InitializeObjectAttributes(&ObjectAttributes
,
533 &RegistryHive
->HiveFileName
,
540 * This is a workaround to prevent a BSOD because of missing registry hives.
541 * The workaround is only useful for developers. An implementation for the
542 * ordinary user must bail out on missing registry hives because they are
543 * essential to booting and configuring the OS.
546 if (CreateNew
== TRUE
)
547 CreateDisposition
= FILE_OPEN_IF
;
549 CreateDisposition
= FILE_OPEN
;
551 CreateDisposition
= FILE_OPEN_IF
;
553 Status
= NtCreateFile(&FileHandle
,
558 FILE_ATTRIBUTE_NORMAL
,
561 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
564 if (!NT_SUCCESS(Status
))
566 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
567 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
568 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status
);
572 /* Note: Another workaround! See the note above! */
574 if ((CreateNew
) && (IoSB
.Information
== FILE_CREATED
))
576 if (IoSB
.Information
!= FILE_OPENED
)
578 Status
= CmiCreateNewRegFile(FileHandle
);
579 if (!NT_SUCCESS(Status
))
581 DPRINT1("CmiCreateNewRegFile() failed (Status %lx)\n", Status
);
583 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
584 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
589 /* Read hive header */
590 FileOffset
.u
.HighPart
= 0;
591 FileOffset
.u
.LowPart
= 0;
592 DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle
, sizeof(HIVE_HEADER
), RegistryHive
->HiveHeader
);
593 Status
= NtReadFile(FileHandle
,
598 RegistryHive
->HiveHeader
,
602 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
603 if (!NT_SUCCESS(Status
))
606 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
607 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
608 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 4.\n");
612 /* FIXME: Check hive header */
614 /* Read update counter */
615 RegistryHive
->UpdateCounter
= RegistryHive
->HiveHeader
->UpdateCounter1
;
617 Status
= NtQueryInformationFile(FileHandle
,
621 FileStandardInformation
);
622 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
623 if (!NT_SUCCESS(Status
))
626 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
627 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
628 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 5.\n");
632 RegistryHive
->FileSize
= fsi
.EndOfFile
.u
.LowPart
;
634 // assert(RegistryHive->FileSize);
635 if (RegistryHive
->FileSize
== 0)
638 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
639 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
640 DPRINT("CmiInitPermanentRegistryHive() - Failed, zero length hive file.\n");
641 return STATUS_INSUFFICIENT_RESOURCES
;
644 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ 4096) - 1;
646 DPRINT("Space needed for block list describing hive: 0x%x\n",
647 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
649 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
650 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
652 if (RegistryHive
->BlockList
== NULL
)
654 ExFreePool(RegistryHive
->BlockList
);
656 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
657 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
658 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 6.\n");
659 return STATUS_INSUFFICIENT_RESOURCES
;
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
);
672 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
673 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
674 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 8.\n");
675 return STATUS_INSUFFICIENT_RESOURCES
;
678 FileOffset
.u
.HighPart
= 0;
679 FileOffset
.u
.LowPart
= 4096;
681 DPRINT(" Attempting to NtReadFile(%d) for %d bytes into %p\n",
682 FileHandle
, RegistryHive
->FileSize
- 4096, (PVOID
)RegistryHive
->BlockList
[0]);
683 Status
= NtReadFile(FileHandle
,
688 (PVOID
) RegistryHive
->BlockList
[0],
689 RegistryHive
->FileSize
- 4096,
693 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
697 RegistryHive
->FreeListSize
= 0;
698 RegistryHive
->FreeListMax
= 0;
699 RegistryHive
->FreeList
= NULL
;
702 for (i
= 0; i
< RegistryHive
->BlockListSize
; i
++)
704 RegistryHive
->BlockList
[i
] = (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[0]) + BlockOffset
);
705 tmpBin
= (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[i
]));
706 if (tmpBin
->BlockId
!= REG_BIN_ID
)
708 DPRINT("Bad BlockId %x, offset %x\n", tmpBin
->BlockId
, BlockOffset
);
710 return STATUS_INSUFFICIENT_RESOURCES
;
713 assertmsg((tmpBin
->BlockSize
% 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin
->BlockSize
));
715 if (tmpBin
->BlockSize
> 4096)
717 for (j
= 1; j
< tmpBin
->BlockSize
/ 4096; j
++)
719 RegistryHive
->BlockList
[i
+ j
] = RegistryHive
->BlockList
[i
];
724 /* Search free blocks and add to list */
725 FreeOffset
= REG_HBIN_DATA_OFFSET
;
726 while (FreeOffset
< tmpBin
->BlockSize
)
728 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) RegistryHive
->BlockList
[i
] + FreeOffset
);
729 if (FreeBlock
->CellSize
> 0)
731 Status
= CmiAddFree(RegistryHive
,
733 RegistryHive
->BlockList
[i
]->BlockOffset
+ FreeOffset
,
736 if (!NT_SUCCESS(Status
))
742 FreeOffset
+= FreeBlock
->CellSize
;
746 FreeOffset
-= FreeBlock
->CellSize
;
749 BlockOffset
+= tmpBin
->BlockSize
;
753 * Create block bitmap and clear all bits
755 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
756 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
757 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
758 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
760 /* Allocate bitmap */
761 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
763 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
767 /* Initialize bitmap */
768 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
769 RegistryHive
->HiveDirty
= FALSE
;
771 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S, %d) - Finished.\n",
772 RegistryHive
, Filename
, CreateNew
);
774 return(STATUS_SUCCESS
);
779 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive
)
781 PKEY_CELL RootKeyCell
;
783 RegistryHive
->Flags
|= HIVE_VOLATILE
;
785 CmiCreateDefaultHiveHeader(RegistryHive
->HiveHeader
);
787 RootKeyCell
= (PKEY_CELL
) ExAllocatePool(NonPagedPool
, sizeof(KEY_CELL
));
789 if (RootKeyCell
== NULL
)
790 return STATUS_INSUFFICIENT_RESOURCES
;
792 CmiCreateDefaultRootKeyCell(RootKeyCell
);
794 RegistryHive
->HiveHeader
->RootKeyCell
= (BLOCK_OFFSET
) RootKeyCell
;
796 return STATUS_SUCCESS
;
801 CmiCreateRegistryHive(PWSTR Filename
,
802 PREGISTRY_HIVE
*RegistryHive
,
808 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename
);
810 *RegistryHive
= NULL
;
812 Hive
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_HIVE
));
814 return(STATUS_INSUFFICIENT_RESOURCES
);
816 DPRINT("Hive %x\n", Hive
);
818 RtlZeroMemory(Hive
, sizeof(REGISTRY_HIVE
));
820 Hive
->HiveHeader
= (PHIVE_HEADER
)
821 ExAllocatePool(NonPagedPool
, sizeof(HIVE_HEADER
));
823 if (Hive
->HiveHeader
== NULL
)
826 return(STATUS_INSUFFICIENT_RESOURCES
);
829 if (Filename
!= NULL
)
831 Status
= CmiInitNonVolatileRegistryHive(Hive
, Filename
, CreateNew
);
835 Status
= CmiInitVolatileRegistryHive(Hive
);
838 if (!NT_SUCCESS(Status
))
840 ExFreePool(Hive
->HiveHeader
);
845 ExInitializeResourceLite(&Hive
->HiveResource
);
847 /* Acquire hive list lock exclusively */
848 ExAcquireResourceExclusiveLite(&CmiHiveListLock
, TRUE
);
850 /* Add the new hive to the hive list */
851 InsertHeadList(&CmiHiveListHead
, &Hive
->HiveList
);
853 /* Release hive list lock */
854 ExReleaseResourceLite(&CmiHiveListLock
);
856 VERIFY_REGISTRY_HIVE(Hive
);
858 *RegistryHive
= Hive
;
860 DPRINT("CmiCreateRegistryHive(Filename %S) - Finished.\n", Filename
);
862 return(STATUS_SUCCESS
);
867 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
869 /* Acquire hive list lock exclusively */
870 ExAcquireResourceExclusiveLite(&CmiHiveListLock
, TRUE
);
872 /* Remove hive from hive list */
873 RemoveEntryList(&RegistryHive
->HiveList
);
875 /* Release hive list lock */
876 ExReleaseResourceLite(&CmiHiveListLock
);
879 /* FIXME: Remove attached keys and values */
882 /* Release hive header */
883 ExFreePool(RegistryHive
->HiveHeader
);
886 ExFreePool(RegistryHive
);
888 return(STATUS_SUCCESS
);
893 CmiCalcChecksum(PULONG Buffer
)
898 for (i
= 0; i
< 127; i
++)
906 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
908 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
909 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
910 OBJECT_ATTRIBUTES ObjectAttributes
;
911 IO_STATUS_BLOCK IoStatusBlock
;
913 LARGE_INTEGER FileOffset
;
923 DPRINT1("CmiStartLogUpdate() called\n");
925 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
926 BufferSize
= sizeof(HIVE_HEADER
) +
929 BufferSize
= ROUND_UP(BufferSize
, 4096);
931 DPRINT1("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
933 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
936 DPRINT1("ExAllocatePool() failed\n");
937 return(STATUS_INSUFFICIENT_RESOURCES
);
940 /* Open log file for writing */
941 InitializeObjectAttributes(&ObjectAttributes
,
942 &RegistryHive
->LogFileName
,
947 Status
= NtCreateFile(&FileHandle
,
952 FILE_ATTRIBUTE_NORMAL
,
955 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
958 if (!NT_SUCCESS(Status
))
960 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status
);
965 /* Update firt update counter and checksum */
966 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
967 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
969 /* Copy hive header */
970 RtlCopyMemory(Buffer
,
971 RegistryHive
->HiveHeader
,
972 sizeof(HIVE_HEADER
));
973 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
980 RegistryHive
->DirtyBitMap
.Buffer
,
983 /* Write hive block and block bitmap */
984 FileOffset
.QuadPart
= 0ULL;
985 Status
= NtWriteFile(FileHandle
,
994 if (!NT_SUCCESS(Status
))
996 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1005 /* Write dirty blocks */
1006 FileOffset
.QuadPart
= (ULONGLONG
)BufferSize
;
1010 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1013 if (BlockIndex
== (ULONG
)-1)
1015 DPRINT("No more set bits\n");
1016 Status
= STATUS_SUCCESS
;
1020 DPRINT1("Block %lu is dirty\n", BlockIndex
);
1022 BlockOffset
= RegistryHive
->BlockList
[BlockIndex
]->BlockOffset
;
1023 DPRINT1("Block offset %lx\n", BlockOffset
);
1025 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
] + ((BlockIndex
* 4096) - BlockOffset
);
1026 DPRINT1("BlockPtr %p\n", BlockPtr
);
1028 DPRINT1("File offset %I64x\n", FileOffset
.QuadPart
);
1030 /* Write hive block */
1031 Status
= NtWriteFile(FileHandle
,
1040 if (!NT_SUCCESS(Status
))
1042 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1043 NtClose(FileHandle
);
1048 FileOffset
.QuadPart
+= 4096ULL;
1051 /* Truncate log file */
1052 EndOfFileInfo
.EndOfFile
.QuadPart
= FileOffset
.QuadPart
;
1053 Status
= NtSetInformationFile(FileHandle
,
1056 sizeof(FILE_END_OF_FILE_INFORMATION
),
1057 FileEndOfFileInformation
);
1058 if (!NT_SUCCESS(Status
))
1060 DPRINT1("NtSetInformationFile() failed (Status %lx)\n", Status
);
1061 NtClose(FileHandle
);
1065 FileAllocationInfo
.AllocationSize
.QuadPart
= FileOffset
.QuadPart
;
1066 Status
= NtSetInformationFile(FileHandle
,
1068 &FileAllocationInfo
,
1069 sizeof(FILE_ALLOCATION_INFORMATION
),
1070 FileAllocationInformation
);
1071 if (!NT_SUCCESS(Status
))
1073 DPRINT1("NtSetInformationFile() failed (Status %lx)\n", Status
);
1074 NtClose(FileHandle
);
1078 /* Flush the log file */
1079 Status
= NtFlushBuffersFile(FileHandle
,
1081 if (!NT_SUCCESS(Status
))
1083 DPRINT1("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1086 NtClose(FileHandle
);
1093 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
1095 OBJECT_ATTRIBUTES ObjectAttributes
;
1096 IO_STATUS_BLOCK IoStatusBlock
;
1098 LARGE_INTEGER FileOffset
;
1105 DPRINT1("CmiFinishLogUpdate() called\n");
1107 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1108 BufferSize
= sizeof(HIVE_HEADER
) +
1111 BufferSize
= ROUND_UP(BufferSize
, 4096);
1113 DPRINT1("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1115 Buffer
= (PUCHAR
)ExAllocatePool(NonPagedPool
, BufferSize
);
1118 DPRINT1("ExAllocatePool() failed\n");
1119 return(STATUS_INSUFFICIENT_RESOURCES
);
1122 /* Open log file for writing */
1123 InitializeObjectAttributes(&ObjectAttributes
,
1124 &RegistryHive
->LogFileName
,
1129 Status
= NtCreateFile(&FileHandle
,
1134 FILE_ATTRIBUTE_NORMAL
,
1137 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1140 if (!NT_SUCCESS(Status
))
1142 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status
);
1147 /* Update first and second update counter and checksum */
1148 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1149 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1150 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1152 /* Copy hive header */
1153 RtlCopyMemory(Buffer
,
1154 RegistryHive
->HiveHeader
,
1155 sizeof(HIVE_HEADER
));
1156 Ptr
= Buffer
+ sizeof(HIVE_HEADER
);
1158 /* Write empty block bitmap */
1163 // RtlCopyMemory(Ptr,
1164 // RegistryHive->DirtyBitMap.Buffer,
1169 /* Write hive block and block bitmap */
1170 FileOffset
.QuadPart
= 0ULL;
1171 Status
= NtWriteFile(FileHandle
,
1180 if (!NT_SUCCESS(Status
))
1182 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1183 NtClose(FileHandle
);
1190 /* Flush the log file */
1191 Status
= NtFlushBuffersFile(FileHandle
,
1193 if (!NT_SUCCESS(Status
))
1195 DPRINT1("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1198 NtClose(FileHandle
);
1205 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive
)
1207 FILE_END_OF_FILE_INFORMATION EndOfFileInfo
;
1208 FILE_ALLOCATION_INFORMATION FileAllocationInfo
;
1209 OBJECT_ATTRIBUTES ObjectAttributes
;
1210 IO_STATUS_BLOCK IoStatusBlock
;
1216 DPRINT1("CmiFinishLogUpdate() called\n");
1218 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
1219 BufferSize
= sizeof(HIVE_HEADER
) +
1222 BufferSize
= ROUND_UP(BufferSize
, 4096);
1224 DPRINT1("Bitmap size %lu buffer size: %lu\n", BitmapSize
, BufferSize
);
1226 /* Open log file for writing */
1227 InitializeObjectAttributes(&ObjectAttributes
,
1228 &RegistryHive
->LogFileName
,
1233 Status
= NtCreateFile(&FileHandle
,
1238 FILE_ATTRIBUTE_NORMAL
,
1241 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1244 if (!NT_SUCCESS(Status
))
1246 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status
);
1250 /* Truncate log file */
1251 EndOfFileInfo
.EndOfFile
.QuadPart
= (ULONGLONG
)BufferSize
;
1252 Status
= NtSetInformationFile(FileHandle
,
1255 sizeof(FILE_END_OF_FILE_INFORMATION
),
1256 FileEndOfFileInformation
);
1257 if (!NT_SUCCESS(Status
))
1259 DPRINT1("NtSetInformationFile() failed (Status %lx)\n", Status
);
1260 NtClose(FileHandle
);
1264 FileAllocationInfo
.AllocationSize
.QuadPart
= (ULONGLONG
)BufferSize
;
1265 Status
= NtSetInformationFile(FileHandle
,
1267 &FileAllocationInfo
,
1268 sizeof(FILE_ALLOCATION_INFORMATION
),
1269 FileAllocationInformation
);
1270 if (!NT_SUCCESS(Status
))
1272 DPRINT1("NtSetInformationFile() failed (Status %lx)\n", Status
);
1273 NtClose(FileHandle
);
1277 /* Flush the log file */
1278 Status
= NtFlushBuffersFile(FileHandle
,
1280 if (!NT_SUCCESS(Status
))
1282 DPRINT1("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1285 NtClose(FileHandle
);
1292 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1294 OBJECT_ATTRIBUTES ObjectAttributes
;
1295 IO_STATUS_BLOCK IoStatusBlock
;
1297 LARGE_INTEGER FileOffset
;
1303 DPRINT("CmiStartHiveUpdate() called\n");
1305 /* Open hive for writing */
1306 InitializeObjectAttributes(&ObjectAttributes
,
1307 &RegistryHive
->HiveFileName
,
1312 Status
= NtCreateFile(&FileHandle
,
1317 FILE_ATTRIBUTE_NORMAL
,
1320 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1323 if (!NT_SUCCESS(Status
))
1325 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status
);
1329 /* Update firt update counter and checksum */
1330 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1331 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1333 /* Write hive block */
1334 FileOffset
.QuadPart
= 0ULL;
1335 Status
= NtWriteFile(FileHandle
,
1340 RegistryHive
->HiveHeader
,
1341 sizeof(HIVE_HEADER
),
1344 if (!NT_SUCCESS(Status
))
1346 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1347 NtClose(FileHandle
);
1354 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
1357 if (BlockIndex
== (ULONG
)-1)
1359 DPRINT("No more set bits\n");
1360 Status
= STATUS_SUCCESS
;
1364 DPRINT1("Block %lu is dirty\n", BlockIndex
);
1366 BlockOffset
= RegistryHive
->BlockList
[BlockIndex
]->BlockOffset
;
1367 DPRINT1("Block offset %lx\n", BlockOffset
);
1369 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
] + ((BlockIndex
* 4096) - BlockOffset
);
1370 DPRINT1("BlockPtr %p\n", BlockPtr
);
1372 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096ULL;
1373 DPRINT1("File offset %I64x\n", FileOffset
.QuadPart
);
1376 /* Write hive block */
1377 Status
= NtWriteFile(FileHandle
,
1386 if (!NT_SUCCESS(Status
))
1388 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1389 NtClose(FileHandle
);
1396 Status
= NtFlushBuffersFile(FileHandle
,
1398 if (!NT_SUCCESS(Status
))
1400 DPRINT1("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1403 NtClose(FileHandle
);
1410 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1412 OBJECT_ATTRIBUTES ObjectAttributes
;
1413 IO_STATUS_BLOCK IoStatusBlock
;
1414 LARGE_INTEGER FileOffset
;
1418 DPRINT1("CmiFinishHiveUpdate() called\n");
1420 InitializeObjectAttributes(&ObjectAttributes
,
1421 &RegistryHive
->HiveFileName
,
1426 Status
= NtCreateFile(&FileHandle
,
1431 FILE_ATTRIBUTE_NORMAL
,
1434 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1437 if (!NT_SUCCESS(Status
))
1439 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status
);
1443 /* Update second update counter and checksum */
1444 RegistryHive
->HiveHeader
->UpdateCounter1
= RegistryHive
->UpdateCounter
+ 1;
1445 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->UpdateCounter
+ 1;
1446 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1448 /* Write hive block */
1449 FileOffset
.QuadPart
= 0ULL;
1450 Status
= NtWriteFile(FileHandle
,
1455 RegistryHive
->HiveHeader
,
1456 sizeof(HIVE_HEADER
),
1459 if (!NT_SUCCESS(Status
))
1461 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1462 NtClose(FileHandle
);
1466 Status
= NtFlushBuffersFile(FileHandle
,
1468 if (!NT_SUCCESS(Status
))
1470 DPRINT1("NtFlushBuffersFile() failed (Status %lx)\n", Status
);
1473 NtClose(FileHandle
);
1480 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1484 DPRINT("CmiFlushRegistryHive() called\n");
1486 if (RegistryHive
->HiveDirty
== FALSE
)
1488 return(STATUS_SUCCESS
);
1491 DPRINT1("Hive '%wZ' is dirty\n",
1492 &RegistryHive
->HiveFileName
);
1494 DPRINT1("Log file: '%wZ'\n",
1495 &RegistryHive
->LogFileName
);
1498 /* Update hive header modification time */
1499 NtQuerySystemTime((PTIME
)&RegistryHive
->HiveHeader
->DateModified
);
1501 /* Start log update */
1502 Status
= CmiStartLogUpdate(RegistryHive
);
1503 if (!NT_SUCCESS(Status
))
1505 DPRINT1("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1509 /* Finish log update */
1510 Status
= CmiFinishLogUpdate(RegistryHive
);
1511 if (!NT_SUCCESS(Status
))
1513 DPRINT1("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1517 /* Start hive update */
1518 Status
= CmiStartHiveUpdate(RegistryHive
);
1519 if (!NT_SUCCESS(Status
))
1521 DPRINT1("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1525 /* Finish the hive update */
1526 Status
= CmiFinishHiveUpdate(RegistryHive
);
1527 if (!NT_SUCCESS(Status
))
1529 DPRINT1("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
1533 /* Cleanup log update */
1534 Status
= CmiCleanupLogUpdate(RegistryHive
);
1535 if (!NT_SUCCESS(Status
))
1537 DPRINT1("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1541 /* Increment hive update counter */
1542 RegistryHive
->UpdateCounter
++;
1544 /* Clear dirty bitmap and dirty flag */
1545 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
1546 RegistryHive
->HiveDirty
= FALSE
;
1548 DPRINT1("CmiFlushRegistryHive() done\n");
1550 return(STATUS_SUCCESS
);
1555 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive
,
1558 PHASH_TABLE_CELL HashBlock
;
1559 PKEY_CELL CurSubKeyCell
;
1563 VERIFY_KEY_CELL(KeyCell
);
1566 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1567 if (HashBlock
== NULL
)
1572 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1574 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
1576 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1577 HashBlock
->Table
[i
].KeyOffset
,
1579 if (MaxName
< CurSubKeyCell
->NameSize
)
1581 MaxName
= CurSubKeyCell
->NameSize
;
1583 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1587 CmiReleaseBlock(RegistryHive
, HashBlock
);
1594 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive
,
1597 PHASH_TABLE_CELL HashBlock
;
1598 PKEY_CELL CurSubKeyCell
;
1602 VERIFY_KEY_CELL(KeyCell
);
1605 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1606 if (HashBlock
== NULL
)
1611 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1613 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
1615 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1616 HashBlock
->Table
[i
].KeyOffset
,
1618 if (MaxClass
< CurSubKeyCell
->ClassSize
)
1620 MaxClass
= CurSubKeyCell
->ClassSize
;
1622 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1626 CmiReleaseBlock(RegistryHive
, HashBlock
);
1633 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
1636 PVALUE_LIST_CELL ValueListCell
;
1637 PVALUE_CELL CurValueCell
;
1641 VERIFY_KEY_CELL(KeyCell
);
1643 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1645 if (ValueListCell
== NULL
)
1650 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1652 CurValueCell
= CmiGetBlock(RegistryHive
,
1653 ValueListCell
->Values
[i
],
1655 if (CurValueCell
!= NULL
&&
1656 MaxValueName
< CurValueCell
->NameSize
)
1658 MaxValueName
= CurValueCell
->NameSize
;
1660 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1663 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1665 return MaxValueName
;
1670 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
1673 PVALUE_LIST_CELL ValueListCell
;
1674 PVALUE_CELL CurValueCell
;
1678 VERIFY_KEY_CELL(KeyCell
);
1680 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1682 if (ValueListCell
== NULL
)
1687 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1689 CurValueCell
= CmiGetBlock(RegistryHive
,
1690 ValueListCell
->Values
[i
],NULL
);
1691 if ((CurValueCell
!= NULL
) &&
1692 (MaxValueData
< (CurValueCell
->DataSize
& LONG_MAX
)))
1694 MaxValueData
= CurValueCell
->DataSize
& LONG_MAX
;
1696 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1699 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1701 return MaxValueData
;
1706 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
1707 IN PKEY_CELL KeyCell
,
1708 OUT PKEY_CELL
*SubKeyCell
,
1709 OUT BLOCK_OFFSET
*BlockOffset
,
1711 IN ACCESS_MASK DesiredAccess
,
1712 IN ULONG Attributes
)
1714 PHASH_TABLE_CELL HashBlock
;
1715 PKEY_CELL CurSubKeyCell
;
1719 VERIFY_KEY_CELL(KeyCell
);
1721 //DPRINT("Scanning for sub key %s\n", KeyName);
1723 assert(RegistryHive
);
1725 KeyLength
= strlen(KeyName
);
1727 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1729 if (HashBlock
== NULL
)
1731 return STATUS_SUCCESS
;
1734 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
)
1735 && (i
< HashBlock
->HashTableSize
); i
++)
1737 if (Attributes
& OBJ_CASE_INSENSITIVE
)
1739 if ((HashBlock
->Table
[i
].KeyOffset
!= 0) &&
1740 (HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1) &&
1741 (_strnicmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4) == 0))
1743 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1744 HashBlock
->Table
[i
].KeyOffset
,
1746 if ((CurSubKeyCell
->NameSize
== KeyLength
)
1747 && (_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
) == 0))
1749 *SubKeyCell
= CurSubKeyCell
;
1750 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
1755 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1761 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
1762 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
1763 !strncmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4))
1765 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1766 HashBlock
->Table
[i
].KeyOffset
,NULL
);
1767 if (CurSubKeyCell
->NameSize
== KeyLength
1768 && !_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
))
1770 *SubKeyCell
= CurSubKeyCell
;
1771 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
1776 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1782 CmiReleaseBlock(RegistryHive
, HashBlock
);
1784 return STATUS_SUCCESS
;
1789 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
1792 PWSTR NewSubKeyName
,
1793 USHORT NewSubKeyNameSize
,
1795 PUNICODE_STRING Class
,
1796 ULONG CreateOptions
)
1798 PHASH_TABLE_CELL NewHashBlock
;
1799 PHASH_TABLE_CELL HashBlock
;
1800 BLOCK_OFFSET NKBOffset
;
1801 PKEY_CELL NewKeyCell
;
1807 KeyCell
= Parent
->KeyCell
;
1809 VERIFY_KEY_CELL(KeyCell
);
1811 if (NewSubKeyName
[0] == L
'\\')
1814 NameSize
= NewSubKeyNameSize
/ 2 - 1;
1818 NameSize
= NewSubKeyNameSize
/ 2;
1820 Status
= STATUS_SUCCESS
;
1822 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
1823 Status
= CmiAllocateBlock(RegistryHive
,
1824 (PVOID
) &NewKeyCell
,
1828 if (NewKeyCell
== NULL
)
1830 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1834 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
1835 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
1836 ZwQuerySystemTime((PTIME
) &NewKeyCell
->LastWriteTime
);
1837 NewKeyCell
->ParentKeyOffset
= -1;
1838 NewKeyCell
->NumberOfSubKeys
= 0;
1839 NewKeyCell
->HashTableOffset
= -1;
1840 NewKeyCell
->NumberOfValues
= 0;
1841 NewKeyCell
->ValuesOffset
= -1;
1842 NewKeyCell
->SecurityKeyOffset
= -1;
1843 NewKeyCell
->NameSize
= NameSize
;
1844 wcstombs(NewKeyCell
->Name
, NewSubKeyName
, NameSize
);
1845 NewKeyCell
->ClassNameOffset
= -1;
1847 VERIFY_KEY_CELL(NewKeyCell
);
1853 NewKeyCell
->ClassSize
= Class
->Length
+ sizeof(WCHAR
);
1854 Status
= CmiAllocateBlock(RegistryHive
,
1856 NewKeyCell
->ClassSize
,
1857 &NewKeyCell
->ClassNameOffset
);
1858 wcsncpy((PWSTR
) pClass
->Data
, Class
->Buffer
, Class
->Length
);
1859 ((PWSTR
) (pClass
->Data
))[Class
->Length
] = 0;
1863 if (!NT_SUCCESS(Status
))
1868 SubKey
->KeyCell
= NewKeyCell
;
1869 SubKey
->BlockOffset
= NKBOffset
;
1871 /* Don't modify hash table if key is volatile and parent is not */
1872 if (IsVolatileHive(RegistryHive
) && (!IsVolatileHive(Parent
->RegistryHive
)))
1877 if (KeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
1879 Status
= CmiAllocateHashTableBlock(RegistryHive
,
1881 &KeyCell
->HashTableOffset
,
1882 REG_INIT_HASH_TABLE_SIZE
);
1883 if (!NT_SUCCESS(Status
))
1890 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1891 if (((KeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
1893 BLOCK_OFFSET HTOffset
;
1895 /* Reallocate the hash table block */
1896 Status
= CmiAllocateHashTableBlock(RegistryHive
,
1899 HashBlock
->HashTableSize
+
1900 REG_EXTEND_HASH_TABLE_SIZE
);
1901 if (!NT_SUCCESS(Status
))
1906 RtlZeroMemory(&NewHashBlock
->Table
[0],
1907 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
1908 RtlCopyMemory(&NewHashBlock
->Table
[0],
1909 &HashBlock
->Table
[0],
1910 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
1911 CmiDestroyBlock(RegistryHive
,
1913 KeyCell
->HashTableOffset
);
1914 KeyCell
->HashTableOffset
= HTOffset
;
1915 HashBlock
= NewHashBlock
;
1919 Status
= CmiAddKeyToHashTable(RegistryHive
,
1923 if (NT_SUCCESS(Status
))
1925 KeyCell
->NumberOfSubKeys
++;
1933 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
1934 PKEY_OBJECT ParentKey
,
1937 PHASH_TABLE_CELL HashBlock
;
1938 PVALUE_LIST_CELL ValueList
;
1939 PVALUE_CELL ValueCell
;
1940 PDATA_CELL DataCell
;
1943 DPRINT1("CmiRemoveSubKey() called\n");
1945 /* Remove all values */
1946 if (SubKey
->KeyCell
->NumberOfValues
!= 0)
1948 /* Get pointer to the value list cell */
1949 ValueList
= CmiGetBlock(RegistryHive
,
1950 SubKey
->KeyCell
->ValuesOffset
,
1952 if (ValueList
!= NULL
)
1954 /* Enumerate all values */
1955 for (i
= 0; i
< SubKey
->KeyCell
->NumberOfValues
; i
++)
1957 /* Get pointer to value cell */
1958 ValueCell
= CmiGetBlock(RegistryHive
,
1959 ValueList
->Values
[i
],
1961 if (ValueCell
!= NULL
)
1963 if (ValueCell
->DataSize
> 4)
1965 DataCell
= CmiGetBlock(RegistryHive
,
1966 ValueCell
->DataOffset
,
1968 if (DataCell
!= NULL
)
1970 /* Destroy data cell */
1971 CmiDestroyBlock(RegistryHive
,
1973 ValueCell
->DataOffset
);
1977 /* Destroy value cell */
1978 CmiDestroyBlock(RegistryHive
,
1980 ValueList
->Values
[i
]);
1985 /* Destroy value list cell */
1986 CmiDestroyBlock(RegistryHive
,
1988 SubKey
->KeyCell
->ValuesOffset
);
1990 SubKey
->KeyCell
->NumberOfValues
= 0;
1991 SubKey
->KeyCell
->ValuesOffset
= -1;
1994 /* Remove the key from the parent key's hash block */
1995 if (ParentKey
->KeyCell
->HashTableOffset
!= -1)
1997 DPRINT1("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
)
1998 HashBlock
= CmiGetBlock(RegistryHive
,
1999 ParentKey
->KeyCell
->HashTableOffset
,
2001 DPRINT1("ParentKey HashBlock %p\n", HashBlock
)
2002 if (HashBlock
!= NULL
)
2004 CmiRemoveKeyFromHashTable(RegistryHive
,
2006 SubKey
->BlockOffset
);
2007 CmiMarkBlockDirty(RegistryHive
,
2008 ParentKey
->KeyCell
->HashTableOffset
);
2012 /* Remove the key's hash block */
2013 if (SubKey
->KeyCell
->HashTableOffset
!= -1)
2015 DPRINT1("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
)
2016 HashBlock
= CmiGetBlock(RegistryHive
,
2017 SubKey
->KeyCell
->HashTableOffset
,
2019 DPRINT1("SubKey HashBlock %p\n", HashBlock
)
2020 if (HashBlock
!= NULL
)
2022 CmiDestroyBlock(RegistryHive
,
2024 SubKey
->KeyCell
->HashTableOffset
);
2025 SubKey
->KeyCell
->HashTableOffset
= -1;
2029 /* Decrement the number of the parent key's sub keys */
2030 if (ParentKey
!= NULL
)
2032 DPRINT1("ParentKey %p\n", ParentKey
)
2033 ParentKey
->KeyCell
->NumberOfSubKeys
--;
2035 /* Remove the parent key's hash table */
2036 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
2038 DPRINT1("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
)
2039 HashBlock
= CmiGetBlock(RegistryHive
,
2040 ParentKey
->KeyCell
->HashTableOffset
,
2042 DPRINT1("ParentKey HashBlock %p\n", HashBlock
)
2043 if (HashBlock
!= NULL
)
2045 CmiDestroyBlock(RegistryHive
,
2047 ParentKey
->KeyCell
->HashTableOffset
);
2048 ParentKey
->KeyCell
->HashTableOffset
= -1;
2052 NtQuerySystemTime((PTIME
)&ParentKey
->KeyCell
->LastWriteTime
);
2053 CmiMarkBlockDirty(RegistryHive
,
2054 ParentKey
->BlockOffset
);
2057 /* Destroy key cell */
2058 CmiDestroyBlock(RegistryHive
,
2060 SubKey
->BlockOffset
);
2061 SubKey
->BlockOffset
= -1;
2062 SubKey
->KeyCell
= NULL
;
2064 return(STATUS_SUCCESS
);
2069 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
2070 IN PKEY_CELL KeyCell
,
2071 IN PUNICODE_STRING ValueName
,
2072 OUT PVALUE_CELL
*ValueCell
,
2073 OUT BLOCK_OFFSET
*VBOffset
)
2075 PVALUE_LIST_CELL ValueListCell
;
2076 PVALUE_CELL CurValueCell
;
2079 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2083 if (ValueListCell
== NULL
)
2085 DPRINT("ValueListCell is NULL\n");
2086 return STATUS_SUCCESS
;
2089 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2091 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2093 CurValueCell
= CmiGetBlock(RegistryHive
,
2094 ValueListCell
->Values
[i
],
2097 if ((CurValueCell
!= NULL
) &&
2098 CmiComparePackedNames(ValueName
,
2100 CurValueCell
->NameSize
,
2101 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
2103 *ValueCell
= CurValueCell
;
2105 *VBOffset
= ValueListCell
->Values
[i
];
2106 //DPRINT("Found value %s\n", ValueName);
2109 CmiReleaseBlock(RegistryHive
, CurValueCell
);
2112 CmiReleaseBlock(RegistryHive
, ValueListCell
);
2114 return STATUS_SUCCESS
;
2119 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
2120 IN PKEY_CELL KeyCell
,
2122 OUT PVALUE_CELL
*ValueCell
)
2124 PVALUE_LIST_CELL ValueListCell
;
2125 PVALUE_CELL CurValueCell
;
2127 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2131 if (ValueListCell
== NULL
)
2133 return STATUS_NO_MORE_ENTRIES
;
2136 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2138 if (Index
>= KeyCell
->NumberOfValues
)
2140 return STATUS_NO_MORE_ENTRIES
;
2143 CurValueCell
= CmiGetBlock(RegistryHive
,
2144 ValueListCell
->Values
[Index
],
2147 if (CurValueCell
!= NULL
)
2149 *ValueCell
= CurValueCell
;
2152 CmiReleaseBlock(RegistryHive
, CurValueCell
);
2153 CmiReleaseBlock(RegistryHive
, ValueListCell
);
2155 return STATUS_SUCCESS
;
2160 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
2161 IN PKEY_CELL KeyCell
,
2162 IN PUNICODE_STRING ValueName
,
2163 OUT PVALUE_CELL
*pValueCell
,
2164 OUT BLOCK_OFFSET
*pVBOffset
)
2166 PVALUE_LIST_CELL NewValueListCell
;
2167 PVALUE_LIST_CELL ValueListCell
;
2168 PVALUE_CELL NewValueCell
;
2169 BLOCK_OFFSET VLBOffset
;
2170 BLOCK_OFFSET VBOffset
;
2173 Status
= CmiAllocateValueCell(RegistryHive
,
2177 *pVBOffset
= VBOffset
;
2179 if (!NT_SUCCESS(Status
))
2184 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2186 if (ValueListCell
== NULL
)
2188 Status
= CmiAllocateBlock(RegistryHive
,
2189 (PVOID
) &ValueListCell
,
2190 sizeof(BLOCK_OFFSET
) * 3,
2193 if (!NT_SUCCESS(Status
))
2195 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2198 KeyCell
->ValuesOffset
= VLBOffset
;
2200 else if ((KeyCell
->NumberOfValues
2201 >= (ULONG
) ((LONG
) (ValueListCell
->CellSize
- 4)) / (LONG
) sizeof(BLOCK_OFFSET
)))
2203 Status
= CmiAllocateBlock(RegistryHive
,
2204 (PVOID
) &NewValueListCell
,
2205 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
),
2208 if (!NT_SUCCESS(Status
))
2210 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
2214 RtlCopyMemory(&NewValueListCell
->Values
[0],
2215 &ValueListCell
->Values
[0],
2216 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
2217 CmiDestroyBlock(RegistryHive
, ValueListCell
, KeyCell
->ValuesOffset
);
2218 KeyCell
->ValuesOffset
= VLBOffset
;
2219 ValueListCell
= NewValueListCell
;
2222 DPRINT("KeyCell->NumberOfValues %d, ValueListCell->CellSize %d (%d %x)\n",
2223 KeyCell
->NumberOfValues
, ValueListCell
->CellSize
,
2224 -(ValueListCell
->CellSize
- 4) / sizeof(BLOCK_OFFSET
),
2225 -(ValueListCell
->CellSize
- 4) / sizeof(BLOCK_OFFSET
));
2227 ValueListCell
->Values
[KeyCell
->NumberOfValues
] = VBOffset
;
2228 KeyCell
->NumberOfValues
++;
2229 CmiReleaseBlock(RegistryHive
, ValueListCell
);
2230 CmiReleaseBlock(RegistryHive
, NewValueCell
);
2231 *pValueCell
= NewValueCell
;
2233 return STATUS_SUCCESS
;
2238 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
2239 IN PKEY_CELL KeyCell
,
2240 IN BLOCK_OFFSET KeyCellOffset
,
2241 IN PUNICODE_STRING ValueName
)
2243 PVALUE_LIST_CELL ValueListCell
;
2244 PVALUE_CELL CurValueCell
;
2247 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
2249 if (ValueListCell
== NULL
)
2251 return STATUS_SUCCESS
;
2254 VERIFY_VALUE_LIST_CELL(ValueListCell
);
2256 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
2258 CurValueCell
= CmiGetBlock(RegistryHive
, ValueListCell
->Values
[i
], NULL
);
2260 if ((CurValueCell
!= NULL
) &&
2261 CmiComparePackedNames(ValueName
,
2263 CurValueCell
->NameSize
,
2264 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
2266 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->Values
[i
]);
2268 if ((KeyCell
->NumberOfValues
- 1) < i
)
2270 RtlCopyMemory(&ValueListCell
->Values
[i
],
2271 &ValueListCell
->Values
[i
+ 1],
2272 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
2276 RtlZeroMemory(&ValueListCell
->Values
[i
], sizeof(BLOCK_OFFSET
));
2279 KeyCell
->NumberOfValues
-= 1;
2282 CmiReleaseBlock(RegistryHive
, CurValueCell
);
2285 CmiReleaseBlock(RegistryHive
, ValueListCell
);
2287 if (KeyCell
->NumberOfValues
== 0)
2289 CmiDestroyBlock(RegistryHive
,
2291 KeyCell
->ValuesOffset
);
2295 CmiMarkBlockDirty(RegistryHive
,
2296 KeyCell
->ValuesOffset
);
2299 CmiMarkBlockDirty(RegistryHive
,
2302 return STATUS_SUCCESS
;
2307 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive
,
2308 OUT PHASH_TABLE_CELL
*HashBlock
,
2309 OUT BLOCK_OFFSET
*HBOffset
,
2310 IN ULONG HashTableSize
)
2312 PHASH_TABLE_CELL NewHashBlock
;
2316 Status
= STATUS_SUCCESS
;
2318 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
2319 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
2320 Status
= CmiAllocateBlock(RegistryHive
,
2321 (PVOID
*) &NewHashBlock
,
2325 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
2327 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2331 NewHashBlock
->Id
= REG_HASH_TABLE_BLOCK_ID
;
2332 NewHashBlock
->HashTableSize
= HashTableSize
;
2333 *HashBlock
= NewHashBlock
;
2341 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
2342 PHASH_TABLE_CELL HashBlock
,
2345 BLOCK_OFFSET KeyOffset
;
2348 if (HashBlock
== NULL
)
2351 if (IsVolatileHive(RegistryHive
))
2353 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
2357 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
2358 KeyCell
= CmiGetBlock(RegistryHive
, KeyOffset
, NULL
);
2360 CmiLockBlock(RegistryHive
, KeyCell
);
2367 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
2368 PHASH_TABLE_CELL HashBlock
,
2369 PKEY_CELL NewKeyCell
,
2370 BLOCK_OFFSET NKBOffset
)
2374 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2376 if (HashBlock
->Table
[i
].KeyOffset
== 0)
2378 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
2379 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
, NewKeyCell
->Name
, 4);
2380 return STATUS_SUCCESS
;
2384 return STATUS_UNSUCCESSFUL
;
2389 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
2390 PHASH_TABLE_CELL HashBlock
,
2391 BLOCK_OFFSET NKBOffset
)
2395 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
2397 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
2399 HashBlock
->Table
[i
].KeyOffset
= 0;
2400 RtlZeroMemory(&HashBlock
->Table
[i
].HashValue
, 4);
2401 return STATUS_SUCCESS
;
2405 return STATUS_UNSUCCESSFUL
;
2410 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
2411 PVALUE_CELL
*ValueCell
,
2412 BLOCK_OFFSET
*VBOffset
,
2413 IN PUNICODE_STRING ValueName
)
2415 PVALUE_CELL NewValueCell
;
2421 Status
= STATUS_SUCCESS
;
2423 NameSize
= CmiGetPackedNameLength(ValueName
,
2426 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
2428 Status
= CmiAllocateBlock(RegistryHive
,
2429 (PVOID
*) &NewValueCell
,
2430 sizeof(VALUE_CELL
) + NameSize
,
2432 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
2434 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2438 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
2439 NewValueCell
->NameSize
= NameSize
;
2442 /* Pack the value name */
2443 for (i
= 0; i
< NameSize
; i
++)
2444 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
2445 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
2449 /* Copy the value name */
2450 RtlCopyMemory(NewValueCell
->Name
,
2453 NewValueCell
->Flags
= 0;
2455 NewValueCell
->DataType
= 0;
2456 NewValueCell
->DataSize
= 0;
2457 NewValueCell
->DataOffset
= 0xffffffff;
2458 *ValueCell
= NewValueCell
;
2466 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
2467 PVALUE_CELL ValueCell
,
2468 BLOCK_OFFSET VBOffset
)
2474 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell
, VBOffset
);
2476 VERIFY_VALUE_CELL(ValueCell
);
2478 /* Destroy the data cell */
2479 if (ValueCell
->DataSize
> 4)
2481 pBlock
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, &pBin
);
2482 Status
= CmiDestroyBlock(RegistryHive
, pBlock
, ValueCell
->DataOffset
);
2483 if (!NT_SUCCESS(Status
))
2488 /* Update time of heap */
2489 if (IsPermanentHive(RegistryHive
))
2490 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2493 /* Destroy the value cell */
2494 Status
= CmiDestroyBlock(RegistryHive
, ValueCell
, VBOffset
);
2496 /* Update time of heap */
2497 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, VBOffset
, &pBin
))
2499 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2507 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
2509 BLOCK_OFFSET
*NewBlockOffset
)
2511 PCELL_HEADER tmpBlock
;
2512 PHBIN
* tmpBlockList
;
2515 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
2518 return STATUS_INSUFFICIENT_RESOURCES
;
2521 tmpBin
->BlockId
= REG_BIN_ID
;
2522 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
2523 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
2524 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
2525 tmpBin
->Unused1
= 0;
2526 ZwQuerySystemTime((PTIME
) &tmpBin
->DateModified
);
2527 tmpBin
->Unused2
= 0;
2529 /* Increase size of list of blocks */
2530 tmpBlockList
= ExAllocatePool(NonPagedPool
,
2531 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
2532 if (tmpBlockList
== NULL
)
2535 return STATUS_INSUFFICIENT_RESOURCES
;
2538 if (RegistryHive
->BlockListSize
> 0)
2540 memcpy(tmpBlockList
,
2541 RegistryHive
->BlockList
,
2542 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
2543 ExFreePool(RegistryHive
->BlockList
);
2546 RegistryHive
->BlockList
= tmpBlockList
;
2547 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
++] = tmpBin
;
2549 /* Initialize a free block in this heap : */
2550 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
2551 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
2553 /* Grow bitmap if necessary */
2554 if (IsVolatileHive(RegistryHive
) &&
2555 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
2557 PULONG BitmapBuffer
;
2560 DPRINT1("Grow hive bitmap\n");
2562 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
2563 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
2564 DPRINT1("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
2565 DPRINT1("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
2566 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
2568 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
2569 RtlCopyMemory(BitmapBuffer
,
2570 RegistryHive
->DirtyBitMap
.Buffer
,
2571 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
2572 ExFreePool(RegistryHive
->DirtyBitMap
.Buffer
);
2573 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
2578 *NewBlock
= (PVOID
) tmpBlock
;
2581 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
2583 /* Mark new bin dirty */
2584 CmiMarkBinDirty(RegistryHive
,
2585 tmpBin
->BlockOffset
);
2587 /* FIXME: set first dword to block_offset of another free bloc */
2589 return STATUS_SUCCESS
;
2594 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive
,
2597 BLOCK_OFFSET
* pBlockOffset
)
2599 PCELL_HEADER NewBlock
;
2603 Status
= STATUS_SUCCESS
;
2605 /* Round to 16 bytes multiple */
2606 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
2608 /* Handle volatile hives first */
2609 if (IsVolatileHive(RegistryHive
))
2611 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
2613 if (NewBlock
== NULL
)
2615 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2619 RtlZeroMemory(NewBlock
, BlockSize
);
2620 NewBlock
->CellSize
= BlockSize
;
2621 CmiLockBlock(RegistryHive
, NewBlock
);
2624 *pBlockOffset
= (BLOCK_OFFSET
) NewBlock
;
2631 /* first search in free blocks */
2633 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
2635 if (RegistryHive
->FreeList
[i
]->CellSize
>= BlockSize
)
2639 NewBlock
= RegistryHive
->FreeList
[i
];
2641 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
2643 /* Update time of heap */
2644 Temp
= CmiGetBlock(RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
2648 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2649 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
2652 if ((i
+ 1) < RegistryHive
->FreeListSize
)
2654 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
2655 &RegistryHive
->FreeList
[i
+ 1],
2656 sizeof(RegistryHive
->FreeList
[0])
2657 * (RegistryHive
->FreeListSize
- i
- 1));
2658 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
2659 &RegistryHive
->FreeListOffset
[i
+ 1],
2660 sizeof(RegistryHive
->FreeListOffset
[0])
2661 * (RegistryHive
->FreeListSize
- i
- 1));
2663 RegistryHive
->FreeListSize
--;
2668 /* Need to extend hive file : */
2669 if (NewBlock
== NULL
)
2671 /* Add a new block */
2672 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewBlock
, pBlockOffset
);
2675 if (NT_SUCCESS(Status
))
2679 /* Split the block in two parts */
2680 if (NewBlock
->CellSize
> BlockSize
)
2682 NewBlock
= (PCELL_HEADER
) ((ULONG_PTR
) NewBlock
+BlockSize
);
2683 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- BlockSize
;
2684 CmiAddFree(RegistryHive
,
2686 *pBlockOffset
+ BlockSize
,
2688 CmiMarkBlockDirty(RegistryHive
,
2689 *pBlockOffset
+ BlockSize
);
2691 else if (NewBlock
->CellSize
< BlockSize
)
2693 return(STATUS_UNSUCCESSFUL
);
2696 RtlZeroMemory(*Block
, BlockSize
);
2697 ((PCELL_HEADER
) (*Block
))->CellSize
= -BlockSize
;
2698 CmiLockBlock(RegistryHive
, *Block
);
2707 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive
,
2709 BLOCK_OFFSET Offset
)
2714 Status
= STATUS_SUCCESS
;
2716 if (IsVolatileHive(RegistryHive
))
2718 CmiReleaseBlock(RegistryHive
, Block
);
2723 PCELL_HEADER pFree
= Block
;
2725 if (pFree
->CellSize
< 0)
2726 pFree
->CellSize
= -pFree
->CellSize
;
2728 /* Clear block (except the block size) */
2729 RtlZeroMemory(((PVOID
)pFree
) + sizeof(ULONG
),
2730 pFree
->CellSize
- sizeof(ULONG
));
2732 /* add block to the list of free blocks */
2733 CmiAddFree(RegistryHive
, Block
, Offset
, TRUE
);
2734 CmiReleaseBlock(RegistryHive
, Block
);
2736 /* Update time of heap */
2737 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, Offset
,&pBin
))
2738 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2740 CmiMarkBlockDirty(RegistryHive
, Offset
);
2742 /* FIXME: Set first dword to block_offset of another free block ? */
2743 /* FIXME: Concatenate with previous and next block if free */
2751 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
2752 PCELL_HEADER FreeBlock
,
2753 BLOCK_OFFSET FreeOffset
)
2755 BLOCK_OFFSET BlockOffset
;
2756 BLOCK_OFFSET BinOffset
;
2762 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
2763 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
2765 CmiGetBlock(RegistryHive
,
2768 DPRINT("Bin %p\n", Bin
);
2772 BinOffset
= Bin
->BlockOffset
;
2773 BinSize
= Bin
->BlockSize
;
2774 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
2776 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
2778 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
2779 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
2780 if (BlockOffset
> BinOffset
&&
2781 BlockOffset
< BinOffset
+ BinSize
)
2783 DPRINT("Free block: Offset %lx Size %lx\n",
2784 BlockOffset
, BlockSize
);
2786 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
2787 (BlockOffset
+ BlockSize
== FreeOffset
) &&
2788 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
2790 DPRINT("Merge current block with previous and next block\n");
2792 RegistryHive
->FreeList
[i
]->CellSize
+=
2793 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
2795 FreeBlock
->CellSize
= 0;
2796 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
2799 if ((i
+ 2) < RegistryHive
->FreeListSize
)
2801 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
2802 &RegistryHive
->FreeListOffset
[i
+ 2],
2803 sizeof(RegistryHive
->FreeListOffset
[0])
2804 * (RegistryHive
->FreeListSize
- i
- 2));
2806 RegistryHive
->FreeListSize
--;
2808 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
2812 else if (BlockOffset
+ BlockSize
== FreeOffset
)
2814 DPRINT("Merge current block with previous block\n");
2816 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
2817 FreeBlock
->CellSize
= 0;
2819 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
2823 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
2825 DPRINT("Merge current block with next block\n");
2827 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
2828 RegistryHive
->FreeList
[i
]->CellSize
= 0;
2829 RegistryHive
->FreeList
[i
] = FreeBlock
;
2830 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
2832 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
2844 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
2845 PCELL_HEADER FreeBlock
,
2846 BLOCK_OFFSET FreeOffset
,
2847 BOOLEAN MergeFreeBlocks
)
2849 PCELL_HEADER
*tmpList
;
2850 BLOCK_OFFSET
*tmpListOffset
;
2855 assert(RegistryHive
);
2858 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
2859 FreeBlock
, FreeOffset
);
2861 /* Merge free blocks */
2862 if (MergeFreeBlocks
== TRUE
)
2864 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
2865 return(STATUS_SUCCESS
);
2868 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
2870 tmpList
= ExAllocatePool(PagedPool
,
2871 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
2872 if (tmpList
== NULL
)
2873 return STATUS_INSUFFICIENT_RESOURCES
;
2875 tmpListOffset
= ExAllocatePool(PagedPool
,
2876 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
+ 32));
2878 if (tmpListOffset
== NULL
)
2880 ExFreePool(tmpList
);
2881 return STATUS_INSUFFICIENT_RESOURCES
;
2884 if (RegistryHive
->FreeListMax
)
2886 RtlMoveMemory(tmpList
,
2887 RegistryHive
->FreeList
,
2888 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
2889 RtlMoveMemory(tmpListOffset
,
2890 RegistryHive
->FreeListOffset
,
2891 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
));
2892 ExFreePool(RegistryHive
->FreeList
);
2893 ExFreePool(RegistryHive
->FreeListOffset
);
2895 RegistryHive
->FreeList
= tmpList
;
2896 RegistryHive
->FreeListOffset
= tmpListOffset
;
2897 RegistryHive
->FreeListMax
+= 32;
2900 /* Add new offset to free list, maintaining list in ascending order */
2901 if ((RegistryHive
->FreeListSize
== 0)
2902 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
2904 /* Add to end of list */
2905 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
2906 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
2908 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
2910 /* Add to begin of list */
2911 RtlMoveMemory(&RegistryHive
->FreeList
[1],
2912 &RegistryHive
->FreeList
[0],
2913 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
2914 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
2915 &RegistryHive
->FreeListOffset
[0],
2916 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
2917 RegistryHive
->FreeList
[0] = FreeBlock
;
2918 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
2919 RegistryHive
->FreeListSize
++;
2923 /* Search where to insert */
2925 maxInd
= RegistryHive
->FreeListSize
- 1;
2926 while ((maxInd
- minInd
) > 1)
2928 medInd
= (minInd
+ maxInd
) / 2;
2929 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
2935 /* Insert before maxInd */
2936 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
2937 &RegistryHive
->FreeList
[maxInd
],
2938 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
2939 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
2940 &RegistryHive
->FreeListOffset
[maxInd
],
2941 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
2942 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
2943 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
2944 RegistryHive
->FreeListSize
++;
2947 return STATUS_SUCCESS
;
2952 CmiGetBlock(PREGISTRY_HIVE RegistryHive
,
2953 BLOCK_OFFSET BlockOffset
,
2959 if ((BlockOffset
== 0) || (BlockOffset
== (ULONG_PTR
) -1))
2962 if (IsVolatileHive(RegistryHive
))
2964 return (PVOID
) BlockOffset
;
2970 pBin
= RegistryHive
->BlockList
[BlockOffset
/ 4096];
2973 return((PVOID
)((ULONG_PTR
)pBin
+ (BlockOffset
- pBin
->BlockOffset
)));
2979 CmiLockBlock(PREGISTRY_HIVE RegistryHive
,
2982 if (IsPermanentHive(RegistryHive
))
2984 /* FIXME: Implement */
2990 CmiReleaseBlock(PREGISTRY_HIVE RegistryHive
,
2993 if (IsPermanentHive(RegistryHive
))
2995 /* FIXME: Implement */
3001 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
3002 BLOCK_OFFSET BlockOffset
)
3009 if (IsVolatileHive(RegistryHive
))
3012 DPRINT1("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
3014 BlockNumber
= (ULONG
)BlockOffset
/ 4096;
3016 Cell
= CmiGetBlock(RegistryHive
,
3020 CellSize
= Cell
->CellSize
;
3022 CellSize
= -CellSize
;
3024 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, 4096) - ROUND_DOWN(BlockOffset
, 4096)) / 4096;
3026 DPRINT1(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3029 (Cell
->CellSize
< 0) ? "used" : "free",
3032 RegistryHive
->HiveDirty
= TRUE
;
3033 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3040 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
3041 BLOCK_OFFSET BinOffset
)
3047 if (IsVolatileHive(RegistryHive
))
3050 DPRINT1("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
3052 BlockNumber
= (ULONG
)BinOffset
/ 4096;
3054 Bin
= RegistryHive
->BlockList
[BlockNumber
];
3056 BlockCount
= Bin
->BlockSize
/ 4096;
3058 DPRINT1(" BlockNumber %lu Size %lu BlockCount %lu\n",
3063 RegistryHive
->HiveDirty
= TRUE
;
3064 RtlSetBits(&RegistryHive
->DirtyBitMap
,
3071 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
3072 OUT PBOOLEAN Packable
)
3076 if (Packable
!= NULL
)
3079 for (i
= 0; i
< Name
->Length
; i
++)
3081 if (Name
->Buffer
[i
] > 0xFF)
3083 if (Packable
!= NULL
)
3085 return(Name
->Length
);
3089 return(Name
->Length
/ sizeof(WCHAR
));
3094 CmiComparePackedNames(IN PUNICODE_STRING Name
,
3095 IN PCHAR NameBuffer
,
3096 IN USHORT NameBufferSize
,
3097 IN BOOLEAN NamePacked
)
3102 if (NamePacked
== TRUE
)
3104 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
3107 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3109 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
3115 if (Name
->Length
!= NameBufferSize
)
3118 UNameBuffer
= (PWCHAR
)NameBuffer
;
3120 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
3122 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
3132 CmiCopyPackedName(PWCHAR NameBuffer
,
3133 PCHAR PackedNameBuffer
,
3134 ULONG PackedNameSize
)
3138 for (i
= 0; i
< PackedNameSize
; i
++)
3139 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];