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 Status
= NtQueryInformationFile(FileHandle
,
618 FileStandardInformation
);
619 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
620 if (!NT_SUCCESS(Status
))
623 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
624 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
625 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 5.\n");
629 RegistryHive
->FileSize
= fsi
.EndOfFile
.u
.LowPart
;
631 // assert(RegistryHive->FileSize);
632 if (RegistryHive
->FileSize
== 0)
635 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
636 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
637 DPRINT("CmiInitPermanentRegistryHive() - Failed, zero length hive file.\n");
638 return STATUS_INSUFFICIENT_RESOURCES
;
641 RegistryHive
->BlockListSize
= (RegistryHive
->FileSize
/ 4096) - 1;
643 DPRINT("Space needed for block list describing hive: 0x%x\n",
644 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
646 RegistryHive
->BlockList
= ExAllocatePool(NonPagedPool
,
647 sizeof(PHBIN
*) * RegistryHive
->BlockListSize
);
649 if (RegistryHive
->BlockList
== NULL
)
651 ExFreePool(RegistryHive
->BlockList
);
653 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
654 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
655 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 6.\n");
656 return STATUS_INSUFFICIENT_RESOURCES
;
659 RegistryHive
->BlockList
[0] = ExAllocatePool(PagedPool
,
660 RegistryHive
->FileSize
- 4096);
662 RtlZeroMemory(RegistryHive
->BlockList
[0], RegistryHive
->FileSize
- 4096);
665 if (RegistryHive
->BlockList
[0] == NULL
)
667 ExFreePool(RegistryHive
->BlockList
);
669 RtlFreeUnicodeString(&RegistryHive
->HiveFileName
);
670 RtlFreeUnicodeString(&RegistryHive
->LogFileName
);
671 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 8.\n");
672 return STATUS_INSUFFICIENT_RESOURCES
;
675 FileOffset
.u
.HighPart
= 0;
676 FileOffset
.u
.LowPart
= 4096;
678 DPRINT(" Attempting to NtReadFile(%d) for %d bytes into %p\n",
679 FileHandle
, RegistryHive
->FileSize
- 4096, (PVOID
)RegistryHive
->BlockList
[0]);
680 Status
= NtReadFile(FileHandle
,
685 (PVOID
) RegistryHive
->BlockList
[0],
686 RegistryHive
->FileSize
- 4096,
690 assertmsg(NT_SUCCESS(Status
), ("Status: 0x%X\n", Status
));
694 RegistryHive
->FreeListSize
= 0;
695 RegistryHive
->FreeListMax
= 0;
696 RegistryHive
->FreeList
= NULL
;
699 for (i
= 0; i
< RegistryHive
->BlockListSize
; i
++)
701 RegistryHive
->BlockList
[i
] = (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[0]) + BlockOffset
);
702 tmpBin
= (PHBIN
) (((ULONG_PTR
) RegistryHive
->BlockList
[i
]));
703 if (tmpBin
->BlockId
!= REG_BIN_ID
)
705 DPRINT("Bad BlockId %x, offset %x\n", tmpBin
->BlockId
, BlockOffset
);
707 return STATUS_INSUFFICIENT_RESOURCES
;
710 assertmsg((tmpBin
->BlockSize
% 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin
->BlockSize
));
712 if (tmpBin
->BlockSize
> 4096)
714 for (j
= 1; j
< tmpBin
->BlockSize
/ 4096; j
++)
716 RegistryHive
->BlockList
[i
+ j
] = RegistryHive
->BlockList
[i
];
721 /* Search free blocks and add to list */
722 FreeOffset
= REG_HBIN_DATA_OFFSET
;
723 while (FreeOffset
< tmpBin
->BlockSize
)
725 FreeBlock
= (PCELL_HEADER
) ((ULONG_PTR
) RegistryHive
->BlockList
[i
] + FreeOffset
);
726 if (FreeBlock
->CellSize
> 0)
728 Status
= CmiAddFree(RegistryHive
,
730 RegistryHive
->BlockList
[i
]->BlockOffset
+ FreeOffset
,
733 if (!NT_SUCCESS(Status
))
739 FreeOffset
+= FreeBlock
->CellSize
;
743 FreeOffset
-= FreeBlock
->CellSize
;
746 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 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
755 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
757 /* Allocate bitmap */
758 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
760 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
764 /* Initialize bitmap */
765 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
766 RegistryHive
->HiveDirty
= FALSE
;
768 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S, %d) - Finished.\n",
769 RegistryHive
, Filename
, CreateNew
);
771 return(STATUS_SUCCESS
);
776 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive
)
778 PKEY_CELL RootKeyCell
;
780 RegistryHive
->Flags
|= HIVE_VOLATILE
;
782 CmiCreateDefaultHiveHeader(RegistryHive
->HiveHeader
);
784 RootKeyCell
= (PKEY_CELL
) ExAllocatePool(NonPagedPool
, sizeof(KEY_CELL
));
786 if (RootKeyCell
== NULL
)
787 return STATUS_INSUFFICIENT_RESOURCES
;
789 CmiCreateDefaultRootKeyCell(RootKeyCell
);
791 RegistryHive
->HiveHeader
->RootKeyCell
= (BLOCK_OFFSET
) RootKeyCell
;
793 return STATUS_SUCCESS
;
798 CmiCreateRegistryHive(PWSTR Filename
,
799 PREGISTRY_HIVE
*RegistryHive
,
805 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename
);
807 *RegistryHive
= NULL
;
809 Hive
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_HIVE
));
811 return(STATUS_INSUFFICIENT_RESOURCES
);
813 DPRINT("Hive %x\n", Hive
);
815 RtlZeroMemory(Hive
, sizeof(REGISTRY_HIVE
));
817 Hive
->HiveHeader
= (PHIVE_HEADER
)
818 ExAllocatePool(NonPagedPool
, sizeof(HIVE_HEADER
));
820 if (Hive
->HiveHeader
== NULL
)
823 return(STATUS_INSUFFICIENT_RESOURCES
);
826 if (Filename
!= NULL
)
828 Status
= CmiInitNonVolatileRegistryHive(Hive
, Filename
, CreateNew
);
832 Status
= CmiInitVolatileRegistryHive(Hive
);
835 if (!NT_SUCCESS(Status
))
837 ExFreePool(Hive
->HiveHeader
);
842 ExInitializeResourceLite(&Hive
->HiveResource
);
844 /* Acquire hive list lock exclusively */
845 ExAcquireResourceExclusiveLite(&CmiHiveListLock
, TRUE
);
847 /* Add the new hive to the hive list */
848 InsertHeadList(&CmiHiveListHead
, &Hive
->HiveList
);
850 /* Release hive list lock */
851 ExReleaseResourceLite(&CmiHiveListLock
);
853 VERIFY_REGISTRY_HIVE(Hive
);
855 *RegistryHive
= Hive
;
857 DPRINT("CmiCreateRegistryHive(Filename %S) - Finished.\n", Filename
);
859 return(STATUS_SUCCESS
);
864 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive
)
866 /* Acquire hive list lock exclusively */
867 ExAcquireResourceExclusiveLite(&CmiHiveListLock
, TRUE
);
869 /* Remove hive from hive list */
870 RemoveEntryList(&RegistryHive
->HiveList
);
872 /* Release hive list lock */
873 ExReleaseResourceLite(&CmiHiveListLock
);
876 /* FIXME: Remove attached keys and values */
879 /* Release hive header */
880 ExFreePool(RegistryHive
->HiveHeader
);
883 ExFreePool(RegistryHive
);
885 return(STATUS_SUCCESS
);
890 CmiCalcChecksum(PULONG Buffer
)
895 for (i
= 0; i
< 127; i
++)
903 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive
)
905 return(STATUS_SUCCESS
);
910 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive
)
912 return(STATUS_SUCCESS
);
917 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive
)
919 OBJECT_ATTRIBUTES ObjectAttributes
;
920 IO_STATUS_BLOCK IoStatusBlock
;
922 LARGE_INTEGER FileOffset
;
928 DPRINT("CmiStartHiveUpdate() called\n");
930 /* Open hive for writing */
931 InitializeObjectAttributes(&ObjectAttributes
,
932 &RegistryHive
->HiveFileName
,
937 Status
= NtCreateFile(&FileHandle
,
942 FILE_ATTRIBUTE_NORMAL
,
945 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
948 if (!NT_SUCCESS(Status
))
950 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status
);
954 /* Update hive header */
955 RegistryHive
->HiveHeader
->UpdateCounter1
++;
956 NtQuerySystemTime((PTIME
)&RegistryHive
->HiveHeader
->DateModified
);
958 /* Update header checksum */
959 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
961 /* Write hive block */
962 FileOffset
.QuadPart
= 0ULL;
963 Status
= NtWriteFile(FileHandle
,
968 RegistryHive
->HiveHeader
,
972 if (!NT_SUCCESS(Status
))
974 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
982 BlockIndex
= RtlFindSetBits(&RegistryHive
->DirtyBitMap
,
985 if (BlockIndex
== (ULONG
)-1)
987 DPRINT("No more set bits\n");
988 Status
= STATUS_SUCCESS
;
992 DPRINT1("Block %lu is dirty\n", BlockIndex
);
994 BlockOffset
= RegistryHive
->BlockList
[BlockIndex
]->BlockOffset
;
995 DPRINT1("Block offset %lx\n", BlockOffset
);
997 BlockPtr
= RegistryHive
->BlockList
[BlockIndex
] + ((BlockIndex
* 4096) - BlockOffset
);
998 DPRINT1("BlockPtr %p\n", BlockPtr
);
1000 FileOffset
.QuadPart
= (ULONGLONG
)(BlockIndex
+ 1) * 4096ULL;
1001 DPRINT1("File offset %I64x\n", FileOffset
.QuadPart
);
1004 /* Write hive block */
1005 Status
= NtWriteFile(FileHandle
,
1014 if (!NT_SUCCESS(Status
))
1016 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1017 NtClose(FileHandle
);
1024 NtClose(FileHandle
);
1031 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive
)
1033 OBJECT_ATTRIBUTES ObjectAttributes
;
1034 IO_STATUS_BLOCK IoStatusBlock
;
1035 LARGE_INTEGER FileOffset
;
1039 DPRINT1("CmiFinishHiveUpdate() called\n");
1041 InitializeObjectAttributes(&ObjectAttributes
,
1042 &RegistryHive
->HiveFileName
,
1047 Status
= NtCreateFile(&FileHandle
,
1052 FILE_ATTRIBUTE_NORMAL
,
1055 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
1058 if (!NT_SUCCESS(Status
))
1060 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status
);
1064 /* Update hive header */
1065 RegistryHive
->HiveHeader
->UpdateCounter2
= RegistryHive
->HiveHeader
->UpdateCounter1
;
1067 /* Update header checksum */
1068 RegistryHive
->HiveHeader
->Checksum
= CmiCalcChecksum((PULONG
)RegistryHive
->HiveHeader
);
1071 /* Write hive block */
1072 FileOffset
.QuadPart
= 0ULL;
1073 Status
= NtWriteFile(FileHandle
,
1078 RegistryHive
->HiveHeader
,
1079 sizeof(HIVE_HEADER
),
1082 NtClose(FileHandle
);
1083 if (!NT_SUCCESS(Status
))
1085 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
1093 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive
)
1097 DPRINT("CmiFlushRegistryHive() called\n");
1099 if (RegistryHive
->HiveDirty
== FALSE
)
1101 return(STATUS_SUCCESS
);
1104 DPRINT1("Hive '%wZ' is dirty\n",
1105 &RegistryHive
->HiveFileName
);
1107 DPRINT1("Log file: '%wZ'\n",
1108 &RegistryHive
->LogFileName
);
1110 /* Start log update */
1111 Status
= CmiStartLogUpdate(RegistryHive
);
1112 if (!NT_SUCCESS(Status
))
1114 DPRINT1("CmiStartLogUpdate() failed (Status %lx)\n", Status
);
1118 /* Finish log update */
1119 Status
= CmiFinishLogUpdate(RegistryHive
);
1120 if (!NT_SUCCESS(Status
))
1122 DPRINT1("CmiFinishLogUpdate() failed (Status %lx)\n", Status
);
1126 /* Start hive update */
1127 Status
= CmiStartHiveUpdate(RegistryHive
);
1128 if (!NT_SUCCESS(Status
))
1130 DPRINT1("CmiStartHiveUpdate() failed (Status %lx)\n", Status
);
1134 /* Finish the hive update */
1135 Status
= CmiFinishHiveUpdate(RegistryHive
);
1136 if (!NT_SUCCESS(Status
))
1138 DPRINT1("CmiFinishHiveUpdate() failed (Status %lx)\n", Status
);
1142 /* Clear dirty bitmap and dirty flag */
1143 RtlClearAllBits(&RegistryHive
->DirtyBitMap
);
1144 RegistryHive
->HiveDirty
= FALSE
;
1146 DPRINT1("CmiFlushRegistryHive() done\n");
1148 return(STATUS_SUCCESS
);
1153 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive
,
1156 PHASH_TABLE_CELL HashBlock
;
1157 PKEY_CELL CurSubKeyCell
;
1161 VERIFY_KEY_CELL(KeyCell
);
1164 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1165 if (HashBlock
== NULL
)
1170 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1172 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
1174 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1175 HashBlock
->Table
[i
].KeyOffset
,
1177 if (MaxName
< CurSubKeyCell
->NameSize
)
1179 MaxName
= CurSubKeyCell
->NameSize
;
1181 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1185 CmiReleaseBlock(RegistryHive
, HashBlock
);
1192 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive
,
1195 PHASH_TABLE_CELL HashBlock
;
1196 PKEY_CELL CurSubKeyCell
;
1200 VERIFY_KEY_CELL(KeyCell
);
1203 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1204 if (HashBlock
== NULL
)
1209 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1211 if (HashBlock
->Table
[i
].KeyOffset
!= 0)
1213 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1214 HashBlock
->Table
[i
].KeyOffset
,
1216 if (MaxClass
< CurSubKeyCell
->ClassSize
)
1218 MaxClass
= CurSubKeyCell
->ClassSize
;
1220 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1224 CmiReleaseBlock(RegistryHive
, HashBlock
);
1231 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive
,
1234 PVALUE_LIST_CELL ValueListCell
;
1235 PVALUE_CELL CurValueCell
;
1239 VERIFY_KEY_CELL(KeyCell
);
1241 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1243 if (ValueListCell
== NULL
)
1248 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1250 CurValueCell
= CmiGetBlock(RegistryHive
,
1251 ValueListCell
->Values
[i
],
1253 if (CurValueCell
!= NULL
&&
1254 MaxValueName
< CurValueCell
->NameSize
)
1256 MaxValueName
= CurValueCell
->NameSize
;
1258 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1261 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1263 return MaxValueName
;
1268 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive
,
1271 PVALUE_LIST_CELL ValueListCell
;
1272 PVALUE_CELL CurValueCell
;
1276 VERIFY_KEY_CELL(KeyCell
);
1278 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1280 if (ValueListCell
== NULL
)
1285 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1287 CurValueCell
= CmiGetBlock(RegistryHive
,
1288 ValueListCell
->Values
[i
],NULL
);
1289 if ((CurValueCell
!= NULL
) &&
1290 (MaxValueData
< (CurValueCell
->DataSize
& LONG_MAX
)))
1292 MaxValueData
= CurValueCell
->DataSize
& LONG_MAX
;
1294 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1297 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1299 return MaxValueData
;
1304 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive
,
1305 IN PKEY_CELL KeyCell
,
1306 OUT PKEY_CELL
*SubKeyCell
,
1307 OUT BLOCK_OFFSET
*BlockOffset
,
1309 IN ACCESS_MASK DesiredAccess
,
1310 IN ULONG Attributes
)
1312 PHASH_TABLE_CELL HashBlock
;
1313 PKEY_CELL CurSubKeyCell
;
1317 VERIFY_KEY_CELL(KeyCell
);
1319 //DPRINT("Scanning for sub key %s\n", KeyName);
1321 assert(RegistryHive
);
1323 KeyLength
= strlen(KeyName
);
1325 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1327 if (HashBlock
== NULL
)
1329 return STATUS_SUCCESS
;
1332 for (i
= 0; (i
< KeyCell
->NumberOfSubKeys
)
1333 && (i
< HashBlock
->HashTableSize
); i
++)
1335 if (Attributes
& OBJ_CASE_INSENSITIVE
)
1337 if ((HashBlock
->Table
[i
].KeyOffset
!= 0) &&
1338 (HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
)-1) &&
1339 (_strnicmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4) == 0))
1341 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1342 HashBlock
->Table
[i
].KeyOffset
,
1344 if ((CurSubKeyCell
->NameSize
== KeyLength
)
1345 && (_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
) == 0))
1347 *SubKeyCell
= CurSubKeyCell
;
1348 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
1353 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1359 if (HashBlock
->Table
[i
].KeyOffset
!= 0 &&
1360 HashBlock
->Table
[i
].KeyOffset
!= (ULONG_PTR
) -1 &&
1361 !strncmp(KeyName
, (PCHAR
) &HashBlock
->Table
[i
].HashValue
, 4))
1363 CurSubKeyCell
= CmiGetBlock(RegistryHive
,
1364 HashBlock
->Table
[i
].KeyOffset
,NULL
);
1365 if (CurSubKeyCell
->NameSize
== KeyLength
1366 && !_strnicmp(KeyName
, CurSubKeyCell
->Name
, KeyLength
))
1368 *SubKeyCell
= CurSubKeyCell
;
1369 *BlockOffset
= HashBlock
->Table
[i
].KeyOffset
;
1374 CmiReleaseBlock(RegistryHive
, CurSubKeyCell
);
1380 CmiReleaseBlock(RegistryHive
, HashBlock
);
1382 return STATUS_SUCCESS
;
1387 CmiAddSubKey(PREGISTRY_HIVE RegistryHive
,
1390 PWSTR NewSubKeyName
,
1391 USHORT NewSubKeyNameSize
,
1393 PUNICODE_STRING Class
,
1394 ULONG CreateOptions
)
1396 PHASH_TABLE_CELL NewHashBlock
;
1397 PHASH_TABLE_CELL HashBlock
;
1398 BLOCK_OFFSET NKBOffset
;
1399 PKEY_CELL NewKeyCell
;
1405 KeyCell
= Parent
->KeyCell
;
1407 VERIFY_KEY_CELL(KeyCell
);
1409 if (NewSubKeyName
[0] == L
'\\')
1412 NameSize
= NewSubKeyNameSize
/ 2 - 1;
1416 NameSize
= NewSubKeyNameSize
/ 2;
1418 Status
= STATUS_SUCCESS
;
1420 NewBlockSize
= sizeof(KEY_CELL
) + NameSize
;
1421 Status
= CmiAllocateBlock(RegistryHive
,
1422 (PVOID
) &NewKeyCell
,
1426 if (NewKeyCell
== NULL
)
1428 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1432 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
1433 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
1434 ZwQuerySystemTime((PTIME
) &NewKeyCell
->LastWriteTime
);
1435 NewKeyCell
->ParentKeyOffset
= -1;
1436 NewKeyCell
->NumberOfSubKeys
= 0;
1437 NewKeyCell
->HashTableOffset
= -1;
1438 NewKeyCell
->NumberOfValues
= 0;
1439 NewKeyCell
->ValuesOffset
= -1;
1440 NewKeyCell
->SecurityKeyOffset
= -1;
1441 NewKeyCell
->NameSize
= NameSize
;
1442 wcstombs(NewKeyCell
->Name
, NewSubKeyName
, NameSize
);
1443 NewKeyCell
->ClassNameOffset
= -1;
1445 VERIFY_KEY_CELL(NewKeyCell
);
1451 NewKeyCell
->ClassSize
= Class
->Length
+ sizeof(WCHAR
);
1452 Status
= CmiAllocateBlock(RegistryHive
,
1454 NewKeyCell
->ClassSize
,
1455 &NewKeyCell
->ClassNameOffset
);
1456 wcsncpy((PWSTR
) pClass
->Data
, Class
->Buffer
, Class
->Length
);
1457 ((PWSTR
) (pClass
->Data
))[Class
->Length
] = 0;
1461 if (!NT_SUCCESS(Status
))
1466 SubKey
->KeyCell
= NewKeyCell
;
1467 SubKey
->BlockOffset
= NKBOffset
;
1469 /* Don't modify hash table if key is volatile and parent is not */
1470 if (IsVolatileHive(RegistryHive
) && (!IsVolatileHive(Parent
->RegistryHive
)))
1475 if (KeyCell
->HashTableOffset
== (ULONG_PTR
) -1)
1477 Status
= CmiAllocateHashTableBlock(RegistryHive
,
1479 &KeyCell
->HashTableOffset
,
1480 REG_INIT_HASH_TABLE_SIZE
);
1481 if (!NT_SUCCESS(Status
))
1488 HashBlock
= CmiGetBlock(RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
1489 if (((KeyCell
->NumberOfSubKeys
+ 1) >= HashBlock
->HashTableSize
))
1491 BLOCK_OFFSET HTOffset
;
1493 /* Reallocate the hash table block */
1494 Status
= CmiAllocateHashTableBlock(RegistryHive
,
1497 HashBlock
->HashTableSize
+
1498 REG_EXTEND_HASH_TABLE_SIZE
);
1499 if (!NT_SUCCESS(Status
))
1504 RtlZeroMemory(&NewHashBlock
->Table
[0],
1505 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
1506 RtlCopyMemory(&NewHashBlock
->Table
[0],
1507 &HashBlock
->Table
[0],
1508 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
1509 CmiDestroyBlock(RegistryHive
,
1511 KeyCell
->HashTableOffset
);
1512 KeyCell
->HashTableOffset
= HTOffset
;
1513 HashBlock
= NewHashBlock
;
1517 Status
= CmiAddKeyToHashTable(RegistryHive
,
1521 if (NT_SUCCESS(Status
))
1523 KeyCell
->NumberOfSubKeys
++;
1531 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive
,
1532 PKEY_OBJECT ParentKey
,
1535 PHASH_TABLE_CELL HashBlock
;
1537 DPRINT1("CmiRemoveSubKey() called\n");
1539 /* Remove the key from the parent key's hash block */
1540 if (ParentKey
->KeyCell
->HashTableOffset
!= -1)
1542 DPRINT1("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
)
1543 HashBlock
= CmiGetBlock(RegistryHive
,
1544 ParentKey
->KeyCell
->HashTableOffset
,
1546 DPRINT1("ParentKey HashBlock %p\n", HashBlock
)
1547 if (HashBlock
!= NULL
)
1549 CmiRemoveKeyFromHashTable(RegistryHive
,
1551 SubKey
->BlockOffset
);
1552 CmiMarkBlockDirty(RegistryHive
,
1553 ParentKey
->KeyCell
->HashTableOffset
);
1557 /* Remove the key's hash block */
1558 if (SubKey
->KeyCell
->HashTableOffset
!= -1)
1560 DPRINT1("SubKey HashTableOffset %lx\n", SubKey
->KeyCell
->HashTableOffset
)
1561 HashBlock
= CmiGetBlock(RegistryHive
,
1562 SubKey
->KeyCell
->HashTableOffset
,
1564 DPRINT1("SubKey HashBlock %p\n", HashBlock
)
1565 if (HashBlock
!= NULL
)
1567 CmiDestroyBlock(RegistryHive
,
1569 SubKey
->KeyCell
->HashTableOffset
);
1570 SubKey
->KeyCell
->HashTableOffset
= -1;
1574 /* Decrement the number of the parent key's sub keys */
1575 if (ParentKey
!= NULL
)
1577 DPRINT1("ParentKey %p\n", ParentKey
)
1578 ParentKey
->KeyCell
->NumberOfSubKeys
--;
1580 /* Remove the parent key's hash table */
1581 if (ParentKey
->KeyCell
->NumberOfSubKeys
== 0)
1583 DPRINT1("ParentKey HashTableOffset %lx\n", ParentKey
->KeyCell
->HashTableOffset
)
1584 HashBlock
= CmiGetBlock(RegistryHive
,
1585 ParentKey
->KeyCell
->HashTableOffset
,
1587 DPRINT1("ParentKey HashBlock %p\n", HashBlock
)
1588 if (HashBlock
!= NULL
)
1590 CmiDestroyBlock(RegistryHive
,
1592 ParentKey
->KeyCell
->HashTableOffset
);
1593 ParentKey
->KeyCell
->HashTableOffset
= -1;
1597 NtQuerySystemTime((PTIME
)&ParentKey
->KeyCell
->LastWriteTime
);
1598 CmiMarkBlockDirty(RegistryHive
,
1599 ParentKey
->BlockOffset
);
1602 /* Destroy key cell */
1603 CmiDestroyBlock(RegistryHive
,
1605 SubKey
->BlockOffset
);
1606 SubKey
->BlockOffset
= -1;
1607 SubKey
->KeyCell
= NULL
;
1609 return(STATUS_SUCCESS
);
1614 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive
,
1615 IN PKEY_CELL KeyCell
,
1616 IN PUNICODE_STRING ValueName
,
1617 OUT PVALUE_CELL
*ValueCell
,
1618 OUT BLOCK_OFFSET
*VBOffset
)
1620 PVALUE_LIST_CELL ValueListCell
;
1621 PVALUE_CELL CurValueCell
;
1624 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1628 if (ValueListCell
== NULL
)
1630 DPRINT("ValueListCell is NULL\n");
1631 return STATUS_SUCCESS
;
1634 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1636 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1638 CurValueCell
= CmiGetBlock(RegistryHive
,
1639 ValueListCell
->Values
[i
],
1642 if ((CurValueCell
!= NULL
) &&
1643 CmiComparePackedNames(ValueName
,
1645 CurValueCell
->NameSize
,
1646 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
1648 *ValueCell
= CurValueCell
;
1650 *VBOffset
= ValueListCell
->Values
[i
];
1651 //DPRINT("Found value %s\n", ValueName);
1654 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1657 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1659 return STATUS_SUCCESS
;
1664 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive
,
1665 IN PKEY_CELL KeyCell
,
1667 OUT PVALUE_CELL
*ValueCell
)
1669 PVALUE_LIST_CELL ValueListCell
;
1670 PVALUE_CELL CurValueCell
;
1672 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1676 if (ValueListCell
== NULL
)
1678 return STATUS_NO_MORE_ENTRIES
;
1681 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1683 if (Index
>= KeyCell
->NumberOfValues
)
1685 return STATUS_NO_MORE_ENTRIES
;
1688 CurValueCell
= CmiGetBlock(RegistryHive
,
1689 ValueListCell
->Values
[Index
],
1692 if (CurValueCell
!= NULL
)
1694 *ValueCell
= CurValueCell
;
1697 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1698 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1700 return STATUS_SUCCESS
;
1705 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive
,
1706 IN PKEY_CELL KeyCell
,
1707 IN PUNICODE_STRING ValueName
,
1708 OUT PVALUE_CELL
*pValueCell
,
1709 OUT BLOCK_OFFSET
*pVBOffset
)
1711 PVALUE_LIST_CELL NewValueListCell
;
1712 PVALUE_LIST_CELL ValueListCell
;
1713 PVALUE_CELL NewValueCell
;
1714 BLOCK_OFFSET VLBOffset
;
1715 BLOCK_OFFSET VBOffset
;
1718 Status
= CmiAllocateValueCell(RegistryHive
,
1722 *pVBOffset
= VBOffset
;
1724 if (!NT_SUCCESS(Status
))
1729 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1731 if (ValueListCell
== NULL
)
1733 Status
= CmiAllocateBlock(RegistryHive
,
1734 (PVOID
) &ValueListCell
,
1735 sizeof(BLOCK_OFFSET
) * 3,
1738 if (!NT_SUCCESS(Status
))
1740 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
1743 KeyCell
->ValuesOffset
= VLBOffset
;
1745 else if ((KeyCell
->NumberOfValues
1746 >= (ULONG
) ((LONG
) (ValueListCell
->CellSize
- 4)) / (LONG
) sizeof(BLOCK_OFFSET
)))
1748 Status
= CmiAllocateBlock(RegistryHive
,
1749 (PVOID
) &NewValueListCell
,
1750 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
+ REG_VALUE_LIST_CELL_MULTIPLE
),
1753 if (!NT_SUCCESS(Status
))
1755 CmiDestroyValueCell(RegistryHive
, NewValueCell
, VBOffset
);
1759 RtlCopyMemory(&NewValueListCell
->Values
[0],
1760 &ValueListCell
->Values
[0],
1761 sizeof(BLOCK_OFFSET
) * KeyCell
->NumberOfValues
);
1762 CmiDestroyBlock(RegistryHive
, ValueListCell
, KeyCell
->ValuesOffset
);
1763 KeyCell
->ValuesOffset
= VLBOffset
;
1764 ValueListCell
= NewValueListCell
;
1767 DPRINT("KeyCell->NumberOfValues %d, ValueListCell->CellSize %d (%d %x)\n",
1768 KeyCell
->NumberOfValues
, ValueListCell
->CellSize
,
1769 -(ValueListCell
->CellSize
- 4) / sizeof(BLOCK_OFFSET
),
1770 -(ValueListCell
->CellSize
- 4) / sizeof(BLOCK_OFFSET
));
1772 ValueListCell
->Values
[KeyCell
->NumberOfValues
] = VBOffset
;
1773 KeyCell
->NumberOfValues
++;
1774 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1775 CmiReleaseBlock(RegistryHive
, NewValueCell
);
1776 *pValueCell
= NewValueCell
;
1778 return STATUS_SUCCESS
;
1783 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive
,
1784 IN PKEY_CELL KeyCell
,
1785 IN BLOCK_OFFSET KeyCellOffset
,
1786 IN PUNICODE_STRING ValueName
)
1788 PVALUE_LIST_CELL ValueListCell
;
1789 PVALUE_CELL CurValueCell
;
1792 ValueListCell
= CmiGetBlock(RegistryHive
, KeyCell
->ValuesOffset
, NULL
);
1794 if (ValueListCell
== NULL
)
1796 return STATUS_SUCCESS
;
1799 VERIFY_VALUE_LIST_CELL(ValueListCell
);
1801 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1803 CurValueCell
= CmiGetBlock(RegistryHive
, ValueListCell
->Values
[i
], NULL
);
1805 if ((CurValueCell
!= NULL
) &&
1806 CmiComparePackedNames(ValueName
,
1808 CurValueCell
->NameSize
,
1809 CurValueCell
->Flags
& REG_VALUE_NAME_PACKED
))
1811 CmiDestroyValueCell(RegistryHive
, CurValueCell
, ValueListCell
->Values
[i
]);
1813 if ((KeyCell
->NumberOfValues
- 1) < i
)
1815 RtlCopyMemory(&ValueListCell
->Values
[i
],
1816 &ValueListCell
->Values
[i
+ 1],
1817 sizeof(BLOCK_OFFSET
) * (KeyCell
->NumberOfValues
- 1 - i
));
1821 RtlZeroMemory(&ValueListCell
->Values
[i
], sizeof(BLOCK_OFFSET
));
1824 KeyCell
->NumberOfValues
-= 1;
1827 CmiReleaseBlock(RegistryHive
, CurValueCell
);
1830 CmiReleaseBlock(RegistryHive
, ValueListCell
);
1832 if (KeyCell
->NumberOfValues
== 0)
1834 CmiDestroyBlock(RegistryHive
,
1836 KeyCell
->ValuesOffset
);
1840 CmiMarkBlockDirty(RegistryHive
,
1841 KeyCell
->ValuesOffset
);
1844 CmiMarkBlockDirty(RegistryHive
,
1847 return STATUS_SUCCESS
;
1852 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive
,
1853 OUT PHASH_TABLE_CELL
*HashBlock
,
1854 OUT BLOCK_OFFSET
*HBOffset
,
1855 IN ULONG HashTableSize
)
1857 PHASH_TABLE_CELL NewHashBlock
;
1861 Status
= STATUS_SUCCESS
;
1863 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
1864 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
1865 Status
= CmiAllocateBlock(RegistryHive
,
1866 (PVOID
*) &NewHashBlock
,
1870 if ((NewHashBlock
== NULL
) || (!NT_SUCCESS(Status
)))
1872 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1876 NewHashBlock
->Id
= REG_HASH_TABLE_BLOCK_ID
;
1877 NewHashBlock
->HashTableSize
= HashTableSize
;
1878 *HashBlock
= NewHashBlock
;
1886 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive
,
1887 PHASH_TABLE_CELL HashBlock
,
1890 BLOCK_OFFSET KeyOffset
;
1893 if (HashBlock
== NULL
)
1896 if (IsVolatileHive(RegistryHive
))
1898 KeyCell
= (PKEY_CELL
) HashBlock
->Table
[Index
].KeyOffset
;
1902 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
1903 KeyCell
= CmiGetBlock(RegistryHive
, KeyOffset
, NULL
);
1905 CmiLockBlock(RegistryHive
, KeyCell
);
1912 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive
,
1913 PHASH_TABLE_CELL HashBlock
,
1914 PKEY_CELL NewKeyCell
,
1915 BLOCK_OFFSET NKBOffset
)
1919 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1921 if (HashBlock
->Table
[i
].KeyOffset
== 0)
1923 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
1924 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
, NewKeyCell
->Name
, 4);
1925 return STATUS_SUCCESS
;
1929 return STATUS_UNSUCCESSFUL
;
1934 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive
,
1935 PHASH_TABLE_CELL HashBlock
,
1936 BLOCK_OFFSET NKBOffset
)
1940 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
1942 if (HashBlock
->Table
[i
].KeyOffset
== NKBOffset
)
1944 HashBlock
->Table
[i
].KeyOffset
= 0;
1945 RtlZeroMemory(&HashBlock
->Table
[i
].HashValue
, 4);
1946 return STATUS_SUCCESS
;
1950 return STATUS_UNSUCCESSFUL
;
1955 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive
,
1956 PVALUE_CELL
*ValueCell
,
1957 BLOCK_OFFSET
*VBOffset
,
1958 IN PUNICODE_STRING ValueName
)
1960 PVALUE_CELL NewValueCell
;
1966 Status
= STATUS_SUCCESS
;
1968 NameSize
= CmiGetPackedNameLength(ValueName
,
1971 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName
->Length
, NameSize
);
1973 Status
= CmiAllocateBlock(RegistryHive
,
1974 (PVOID
*) &NewValueCell
,
1975 sizeof(VALUE_CELL
) + NameSize
,
1977 if ((NewValueCell
== NULL
) || (!NT_SUCCESS(Status
)))
1979 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1983 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
1984 NewValueCell
->NameSize
= NameSize
;
1987 /* Pack the value name */
1988 for (i
= 0; i
< NameSize
; i
++)
1989 NewValueCell
->Name
[i
] = (CHAR
)ValueName
->Buffer
[i
];
1990 NewValueCell
->Flags
|= REG_VALUE_NAME_PACKED
;
1994 /* Copy the value name */
1995 RtlCopyMemory(NewValueCell
->Name
,
1998 NewValueCell
->Flags
= 0;
2000 NewValueCell
->DataType
= 0;
2001 NewValueCell
->DataSize
= 0;
2002 NewValueCell
->DataOffset
= 0xffffffff;
2003 *ValueCell
= NewValueCell
;
2011 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive
,
2012 PVALUE_CELL ValueCell
,
2013 BLOCK_OFFSET VBOffset
)
2019 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell
, VBOffset
);
2021 VERIFY_VALUE_CELL(ValueCell
);
2023 /* Destroy the data cell */
2024 if (ValueCell
->DataSize
> 4)
2026 pBlock
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, &pBin
);
2027 Status
= CmiDestroyBlock(RegistryHive
, pBlock
, ValueCell
->DataOffset
);
2028 if (!NT_SUCCESS(Status
))
2033 /* Update time of heap */
2034 if (IsPermanentHive(RegistryHive
))
2035 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2038 /* Destroy the value cell */
2039 Status
= CmiDestroyBlock(RegistryHive
, ValueCell
, VBOffset
);
2041 /* Update time of heap */
2042 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, VBOffset
, &pBin
))
2044 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2052 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
2054 BLOCK_OFFSET
*NewBlockOffset
)
2056 PCELL_HEADER tmpBlock
;
2057 PHBIN
* tmpBlockList
;
2060 tmpBin
= ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
2063 return STATUS_INSUFFICIENT_RESOURCES
;
2066 tmpBin
->BlockId
= REG_BIN_ID
;
2067 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
2068 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
2069 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
2070 tmpBin
->Unused1
= 0;
2071 ZwQuerySystemTime((PTIME
) &tmpBin
->DateModified
);
2072 tmpBin
->Unused2
= 0;
2074 /* Increase size of list of blocks */
2075 tmpBlockList
= ExAllocatePool(NonPagedPool
,
2076 sizeof(PHBIN
*) * (RegistryHive
->BlockListSize
+ 1));
2077 if (tmpBlockList
== NULL
)
2080 return STATUS_INSUFFICIENT_RESOURCES
;
2083 if (RegistryHive
->BlockListSize
> 0)
2085 memcpy(tmpBlockList
,
2086 RegistryHive
->BlockList
,
2087 sizeof(PHBIN
*)*(RegistryHive
->BlockListSize
));
2088 ExFreePool(RegistryHive
->BlockList
);
2091 RegistryHive
->BlockList
= tmpBlockList
;
2092 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
++] = tmpBin
;
2094 /* Initialize a free block in this heap : */
2095 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
2096 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
2098 /* Grow bitmap if necessary */
2099 if (IsVolatileHive(RegistryHive
) &&
2100 (RegistryHive
->BlockListSize
% (sizeof(ULONG
) * 8) == 0))
2102 PULONG BitmapBuffer
;
2105 DPRINT1("Grow hive bitmap\n");
2107 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
2108 BitmapSize
= ROUND_UP(RegistryHive
->BlockListSize
, sizeof(ULONG
) * 8) / 8;
2109 DPRINT1("RegistryHive->BlockListSize: %lu\n", RegistryHive
->BlockListSize
);
2110 DPRINT1("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize
, BitmapSize
* 8);
2111 BitmapBuffer
= (PULONG
)ExAllocatePool(PagedPool
,
2113 RtlZeroMemory(BitmapBuffer
, BitmapSize
);
2114 RtlCopyMemory(BitmapBuffer
,
2115 RegistryHive
->DirtyBitMap
.Buffer
,
2116 RegistryHive
->DirtyBitMap
.SizeOfBitMap
);
2117 ExFreePool(RegistryHive
->DirtyBitMap
.Buffer
);
2118 RtlInitializeBitMap(&RegistryHive
->DirtyBitMap
,
2123 *NewBlock
= (PVOID
) tmpBlock
;
2126 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
2128 /* Mark new bin dirty */
2129 CmiMarkBinDirty(RegistryHive
,
2130 tmpBin
->BlockOffset
);
2132 /* FIXME: set first dword to block_offset of another free bloc */
2134 return STATUS_SUCCESS
;
2139 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive
,
2142 BLOCK_OFFSET
* pBlockOffset
)
2144 PCELL_HEADER NewBlock
;
2148 Status
= STATUS_SUCCESS
;
2150 /* Round to 16 bytes multiple */
2151 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
2153 /* Handle volatile hives first */
2154 if (IsVolatileHive(RegistryHive
))
2156 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
2158 if (NewBlock
== NULL
)
2160 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2164 RtlZeroMemory(NewBlock
, BlockSize
);
2165 NewBlock
->CellSize
= BlockSize
;
2166 CmiLockBlock(RegistryHive
, NewBlock
);
2169 *pBlockOffset
= (BLOCK_OFFSET
) NewBlock
;
2176 /* first search in free blocks */
2178 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
2180 if (RegistryHive
->FreeList
[i
]->CellSize
>= BlockSize
)
2184 NewBlock
= RegistryHive
->FreeList
[i
];
2186 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
2188 /* Update time of heap */
2189 Temp
= CmiGetBlock(RegistryHive
, RegistryHive
->FreeListOffset
[i
], &pBin
);
2193 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2194 CmiMarkBlockDirty(RegistryHive
, RegistryHive
->FreeListOffset
[i
]);
2197 if ((i
+ 1) < RegistryHive
->FreeListSize
)
2199 RtlMoveMemory(&RegistryHive
->FreeList
[i
],
2200 &RegistryHive
->FreeList
[i
+ 1],
2201 sizeof(RegistryHive
->FreeList
[0])
2202 * (RegistryHive
->FreeListSize
- i
- 1));
2203 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
],
2204 &RegistryHive
->FreeListOffset
[i
+ 1],
2205 sizeof(RegistryHive
->FreeListOffset
[0])
2206 * (RegistryHive
->FreeListSize
- i
- 1));
2208 RegistryHive
->FreeListSize
--;
2213 /* Need to extend hive file : */
2214 if (NewBlock
== NULL
)
2216 /* Add a new block */
2217 Status
= CmiAddBin(RegistryHive
, (PVOID
*) &NewBlock
, pBlockOffset
);
2220 if (NT_SUCCESS(Status
))
2224 /* Split the block in two parts */
2225 if (NewBlock
->CellSize
> BlockSize
)
2227 NewBlock
= (PCELL_HEADER
) ((ULONG_PTR
) NewBlock
+BlockSize
);
2228 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- BlockSize
;
2229 CmiAddFree(RegistryHive
,
2231 *pBlockOffset
+ BlockSize
,
2233 CmiMarkBlockDirty(RegistryHive
,
2234 *pBlockOffset
+ BlockSize
);
2236 else if (NewBlock
->CellSize
< BlockSize
)
2238 return(STATUS_UNSUCCESSFUL
);
2241 RtlZeroMemory(*Block
, BlockSize
);
2242 ((PCELL_HEADER
) (*Block
))->CellSize
= -BlockSize
;
2243 CmiLockBlock(RegistryHive
, *Block
);
2252 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive
,
2254 BLOCK_OFFSET Offset
)
2259 Status
= STATUS_SUCCESS
;
2261 if (IsVolatileHive(RegistryHive
))
2263 CmiReleaseBlock(RegistryHive
, Block
);
2268 PCELL_HEADER pFree
= Block
;
2270 if (pFree
->CellSize
< 0)
2271 pFree
->CellSize
= -pFree
->CellSize
;
2273 /* Clear block (except the block size) */
2274 RtlZeroMemory(((PVOID
)pFree
) + sizeof(ULONG
),
2275 pFree
->CellSize
- sizeof(ULONG
));
2277 /* add block to the list of free blocks */
2278 CmiAddFree(RegistryHive
, Block
, Offset
, TRUE
);
2279 CmiReleaseBlock(RegistryHive
, Block
);
2281 /* Update time of heap */
2282 if (IsPermanentHive(RegistryHive
) && CmiGetBlock(RegistryHive
, Offset
,&pBin
))
2283 ZwQuerySystemTime((PTIME
) &pBin
->DateModified
);
2285 CmiMarkBlockDirty(RegistryHive
, Offset
);
2287 /* FIXME: Set first dword to block_offset of another free block ? */
2288 /* FIXME: Concatenate with previous and next block if free */
2296 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
2297 PCELL_HEADER FreeBlock
,
2298 BLOCK_OFFSET FreeOffset
)
2300 BLOCK_OFFSET BlockOffset
;
2301 BLOCK_OFFSET BinOffset
;
2307 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
2308 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
2310 CmiGetBlock(RegistryHive
,
2313 DPRINT("Bin %p\n", Bin
);
2317 BinOffset
= Bin
->BlockOffset
;
2318 BinSize
= Bin
->BlockSize
;
2319 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
2321 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
2323 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
2324 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
2325 if (BlockOffset
> BinOffset
&&
2326 BlockOffset
< BinOffset
+ BinSize
)
2328 DPRINT("Free block: Offset %lx Size %lx\n",
2329 BlockOffset
, BlockSize
);
2331 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
2332 (BlockOffset
+ BlockSize
== FreeOffset
) &&
2333 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
2335 DPRINT("Merge current block with previous and next block\n");
2337 RegistryHive
->FreeList
[i
]->CellSize
+=
2338 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
2340 FreeBlock
->CellSize
= 0;
2341 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
2344 if ((i
+ 2) < RegistryHive
->FreeListSize
)
2346 RtlMoveMemory(&RegistryHive
->FreeListOffset
[i
+ 1],
2347 &RegistryHive
->FreeListOffset
[i
+ 2],
2348 sizeof(RegistryHive
->FreeListOffset
[0])
2349 * (RegistryHive
->FreeListSize
- i
- 2));
2351 RegistryHive
->FreeListSize
--;
2353 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
2357 else if (BlockOffset
+ BlockSize
== FreeOffset
)
2359 DPRINT("Merge current block with previous block\n");
2361 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
2362 FreeBlock
->CellSize
= 0;
2364 CmiMarkBlockDirty(RegistryHive
, BlockOffset
);
2368 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
2370 DPRINT("Merge current block with next block\n");
2372 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
2373 RegistryHive
->FreeList
[i
]->CellSize
= 0;
2374 RegistryHive
->FreeList
[i
] = FreeBlock
;
2375 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
2377 CmiMarkBlockDirty(RegistryHive
, FreeOffset
);
2389 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
2390 PCELL_HEADER FreeBlock
,
2391 BLOCK_OFFSET FreeOffset
,
2392 BOOLEAN MergeFreeBlocks
)
2394 PCELL_HEADER
*tmpList
;
2395 BLOCK_OFFSET
*tmpListOffset
;
2400 assert(RegistryHive
);
2403 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
2404 FreeBlock
, FreeOffset
);
2406 /* Merge free blocks */
2407 if (MergeFreeBlocks
== TRUE
)
2409 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
2410 return(STATUS_SUCCESS
);
2413 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
2415 tmpList
= ExAllocatePool(PagedPool
,
2416 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
2417 if (tmpList
== NULL
)
2418 return STATUS_INSUFFICIENT_RESOURCES
;
2420 tmpListOffset
= ExAllocatePool(PagedPool
,
2421 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
+ 32));
2423 if (tmpListOffset
== NULL
)
2425 ExFreePool(tmpList
);
2426 return STATUS_INSUFFICIENT_RESOURCES
;
2429 if (RegistryHive
->FreeListMax
)
2431 RtlMoveMemory(tmpList
,
2432 RegistryHive
->FreeList
,
2433 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
2434 RtlMoveMemory(tmpListOffset
,
2435 RegistryHive
->FreeListOffset
,
2436 sizeof(BLOCK_OFFSET
*) * (RegistryHive
->FreeListMax
));
2437 ExFreePool(RegistryHive
->FreeList
);
2438 ExFreePool(RegistryHive
->FreeListOffset
);
2440 RegistryHive
->FreeList
= tmpList
;
2441 RegistryHive
->FreeListOffset
= tmpListOffset
;
2442 RegistryHive
->FreeListMax
+= 32;
2445 /* Add new offset to free list, maintaining list in ascending order */
2446 if ((RegistryHive
->FreeListSize
== 0)
2447 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
2449 /* Add to end of list */
2450 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
2451 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
2453 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
2455 /* Add to begin of list */
2456 RtlMoveMemory(&RegistryHive
->FreeList
[1],
2457 &RegistryHive
->FreeList
[0],
2458 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
2459 RtlMoveMemory(&RegistryHive
->FreeListOffset
[1],
2460 &RegistryHive
->FreeListOffset
[0],
2461 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
2462 RegistryHive
->FreeList
[0] = FreeBlock
;
2463 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
2464 RegistryHive
->FreeListSize
++;
2468 /* Search where to insert */
2470 maxInd
= RegistryHive
->FreeListSize
- 1;
2471 while ((maxInd
- minInd
) > 1)
2473 medInd
= (minInd
+ maxInd
) / 2;
2474 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
2480 /* Insert before maxInd */
2481 RtlMoveMemory(&RegistryHive
->FreeList
[maxInd
+1],
2482 &RegistryHive
->FreeList
[maxInd
],
2483 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
2484 RtlMoveMemory(&RegistryHive
->FreeListOffset
[maxInd
+ 1],
2485 &RegistryHive
->FreeListOffset
[maxInd
],
2486 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
2487 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
2488 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
2489 RegistryHive
->FreeListSize
++;
2492 return STATUS_SUCCESS
;
2497 CmiGetBlock(PREGISTRY_HIVE RegistryHive
,
2498 BLOCK_OFFSET BlockOffset
,
2504 if ((BlockOffset
== 0) || (BlockOffset
== (ULONG_PTR
) -1))
2507 if (IsVolatileHive(RegistryHive
))
2509 return (PVOID
) BlockOffset
;
2515 pBin
= RegistryHive
->BlockList
[BlockOffset
/ 4096];
2518 return((PVOID
)((ULONG_PTR
)pBin
+ (BlockOffset
- pBin
->BlockOffset
)));
2524 CmiLockBlock(PREGISTRY_HIVE RegistryHive
,
2527 if (IsPermanentHive(RegistryHive
))
2529 /* FIXME: Implement */
2535 CmiReleaseBlock(PREGISTRY_HIVE RegistryHive
,
2538 if (IsPermanentHive(RegistryHive
))
2540 /* FIXME: Implement */
2546 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive
,
2547 BLOCK_OFFSET BlockOffset
)
2554 if (IsVolatileHive(RegistryHive
))
2557 DPRINT1("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG
)BlockOffset
);
2559 BlockNumber
= (ULONG
)BlockOffset
/ 4096;
2561 Cell
= CmiGetBlock(RegistryHive
,
2565 CellSize
= Cell
->CellSize
;
2567 CellSize
= -CellSize
;
2569 BlockCount
= (ROUND_UP(BlockOffset
+ CellSize
, 4096) - ROUND_DOWN(BlockOffset
, 4096)) / 4096;
2571 DPRINT1(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
2574 (Cell
->CellSize
< 0) ? "used" : "free",
2577 RegistryHive
->HiveDirty
= TRUE
;
2578 RtlSetBits(&RegistryHive
->DirtyBitMap
,
2585 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive
,
2586 BLOCK_OFFSET BinOffset
)
2592 if (IsVolatileHive(RegistryHive
))
2595 DPRINT1("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG
)BinOffset
);
2597 BlockNumber
= (ULONG
)BinOffset
/ 4096;
2599 Bin
= RegistryHive
->BlockList
[BlockNumber
];
2601 BlockCount
= Bin
->BlockSize
/ 4096;
2603 DPRINT1(" BlockNumber %lu Size %lu BlockCount %lu\n",
2608 RegistryHive
->HiveDirty
= TRUE
;
2609 RtlSetBits(&RegistryHive
->DirtyBitMap
,
2616 CmiGetPackedNameLength(IN PUNICODE_STRING Name
,
2617 OUT PBOOLEAN Packable
)
2621 if (Packable
!= NULL
)
2624 for (i
= 0; i
< Name
->Length
; i
++)
2626 if (Name
->Buffer
[i
] > 0xFF)
2628 if (Packable
!= NULL
)
2630 return(Name
->Length
);
2634 return(Name
->Length
/ sizeof(WCHAR
));
2639 CmiComparePackedNames(IN PUNICODE_STRING Name
,
2640 IN PCHAR NameBuffer
,
2641 IN USHORT NameBufferSize
,
2642 IN BOOLEAN NamePacked
)
2647 if (NamePacked
== TRUE
)
2649 if (Name
->Length
!= NameBufferSize
* sizeof(WCHAR
))
2652 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
2654 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar((WCHAR
)NameBuffer
[i
]))
2660 if (Name
->Length
!= NameBufferSize
)
2663 UNameBuffer
= (PWCHAR
)NameBuffer
;
2665 for (i
= 0; i
< Name
->Length
/ sizeof(WCHAR
); i
++)
2667 if (RtlUpcaseUnicodeChar(Name
->Buffer
[i
]) != RtlUpcaseUnicodeChar(UNameBuffer
[i
]))
2677 CmiCopyPackedName(PWCHAR NameBuffer
,
2678 PCHAR PackedNameBuffer
,
2679 ULONG PackedNameSize
)
2683 for (i
= 0; i
< PackedNameSize
; i
++)
2684 NameBuffer
[i
] = (WCHAR
)PackedNameBuffer
[i
];