1 /* $Id: registry.c,v 1.24 2000/08/11 08:17:41 jean Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/registry.c
6 * PURPOSE: Registry functions
7 * PROGRAMMERS: Rex Jolliff
13 #undef WIN32_LEAN_AND_MEAN
15 #include <ddk/ntddk.h>
16 #include <internal/ob.h>
20 #include <internal/debug.h>
22 #define PROTO_REG 1 /* Comment out to disable */
24 /* ----------------------------------------------------- Typedefs */
26 #define ULONG_MAX 0x7fffffff
28 #define REG_BLOCK_SIZE 4096
29 #define REG_HEAP_BLOCK_DATA_OFFSET 32
30 #define REG_INIT_BLOCK_LIST_SIZE 32
31 #define REG_INIT_HASH_TABLE_SIZE 32
32 #define REG_EXTEND_HASH_TABLE_SIZE 32
33 #define REG_VALUE_LIST_BLOCK_MULTIPLE 32
34 #define REG_KEY_BLOCK_ID 0x6b6e
35 #define REG_HASH_TABLE_BLOCK_ID 0x666c
36 #define REG_VALUE_BLOCK_ID 0x6b76
37 #define REG_KEY_BLOCK_TYPE 0x20
38 #define REG_ROOT_KEY_BLOCK_TYPE 0x2c
40 #define REG_ROOT_KEY_NAME L"\\Registry"
41 #define SYSTEM_REG_FILE L"\\SystemDir\\System32\\Config\\SYSTEM.DAT"
44 // BLOCK_OFFSET = offset in file after header block
45 typedef DWORD BLOCK_OFFSET
;
47 typedef struct _HEADER_BLOCK
52 LARGE_INTEGER DateModified
;
57 BLOCK_OFFSET RootKeyBlock
;
62 } HEADER_BLOCK
, *PHEADER_BLOCK
;
64 typedef struct _HEAP_BLOCK
67 BLOCK_OFFSET BlockOffset
;
69 } HEAP_BLOCK
, *PHEAP_BLOCK
;
71 // each sub_block begin with this struct :
72 // in a free subblock, higher bit of SubBlockSize is set
73 typedef struct _FREE_SUB_BLOCK
76 } FREE_SUB_BLOCK
, *PFREE_SUB_BLOCK
;
78 typedef struct _KEY_BLOCK
82 LARGE_INTEGER LastWriteTime
;
84 BLOCK_OFFSET ParentKeyOffset
;
85 DWORD NumberOfSubKeys
;
87 BLOCK_OFFSET HashTableOffset
;
90 BLOCK_OFFSET ValuesOffset
;
91 BLOCK_OFFSET SecurityKeyOffset
;
92 BLOCK_OFFSET ClassNameOffset
;
97 } KEY_BLOCK
, *PKEY_BLOCK
;
100 // HashValue=four letters of value's name
101 typedef struct _HASH_RECORD
103 BLOCK_OFFSET KeyOffset
;
105 } HASH_RECORD
, *PHASH_RECORD
;
107 typedef struct _HASH_TABLE_BLOCK
111 HASH_RECORD Table
[0];
112 } HASH_TABLE_BLOCK
, *PHASH_TABLE_BLOCK
;
114 typedef struct _VALUE_LIST_BLOCK
116 BLOCK_OFFSET Values
[0];
117 } VALUE_LIST_BLOCK
, *PVALUE_LIST_BLOCK
;
119 typedef struct _VALUE_BLOCK
121 WORD SubBlockId
; // "kv"
122 WORD NameSize
; // length of Name
123 DWORD DataSize
; // length of datas in the subblock pinted by DataOffset
124 BLOCK_OFFSET DataOffset
; // datas are here if DataSize <=4
129 } VALUE_BLOCK
, *PVALUE_BLOCK
;
131 typedef struct _IN_MEMORY_BLOCK
136 } IN_MEMORY_BLOCK
, *PIN_MEMORY_BLOCK
;
138 typedef struct _REGISTRY_FILE
142 PHEADER_BLOCK HeaderBlock
;
143 ULONG NumberOfBlocks
;
145 PIN_MEMORY_BLOCK
*BlockList
;
147 NTSTATUS (*Extend
)(ULONG NewSize
);
148 PVOID (*Flush
)(VOID
);
149 } REGISTRY_FILE
, *PREGISTRY_FILE
;
151 /* Type defining the Object Manager Key Object */
152 typedef struct _KEY_OBJECT
159 PREGISTRY_FILE RegistryFile
;
161 struct _KEY_OBJECT
*NextKey
;
162 } KEY_OBJECT
, *PKEY_OBJECT
;
164 #define KO_MARKED_FOR_DELETE 0x00000001
166 /* ------------------------------------------------- File Statics */
169 static POBJECT_TYPE CmiKeyType
= NULL
;
170 static PREGISTRY_FILE CmiVolatileFile
= NULL
;
171 static PKEY_OBJECT CmiKeyList
= NULL
;
172 static KSPIN_LOCK CmiKeyListLock
;
173 static PREGISTRY_FILE CmiSystemFile
= NULL
;
176 /* ----------------------------------------- Forward Declarations */
179 //static PVOID CmiObjectParse(PVOID ParsedObject, PWSTR *Path);
180 static NTSTATUS
CmiObjectParse(PVOID ParsedObject
,
182 PUNICODE_STRING FullPath
,
185 static VOID
CmiObjectDelete(PVOID DeletedObject
);
186 static NTSTATUS
CmiBuildKeyPath(PWSTR
*KeyPath
,
187 POBJECT_ATTRIBUTES ObjectAttributes
);
188 static VOID
CmiAddKeyToList(PKEY_OBJECT NewKey
);
189 static VOID
CmiRemoveKeyFromList(PKEY_OBJECT NewKey
);
190 static PKEY_OBJECT
CmiScanKeyList(PWSTR KeyNameBuf
);
191 static PREGISTRY_FILE
CmiCreateRegistry(PWSTR Filename
);
192 static NTSTATUS
CmiCreateKey(IN PREGISTRY_FILE RegistryFile
,
194 OUT PKEY_BLOCK
*KeyBlock
,
195 IN ACCESS_MASK DesiredAccess
,
197 IN PUNICODE_STRING Class
,
198 IN ULONG CreateOptions
,
199 OUT PULONG Disposition
);
200 static NTSTATUS
CmiFindKey(IN PREGISTRY_FILE RegistryFile
,
202 OUT PKEY_BLOCK
*KeyBlock
,
203 IN ACCESS_MASK DesiredAccess
,
205 IN PUNICODE_STRING Class
);
206 static ULONG
CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile
,
207 PKEY_BLOCK KeyBlock
);
208 static ULONG
CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile
,
209 PKEY_BLOCK KeyBlock
);
210 static ULONG
CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile
,
211 PKEY_BLOCK KeyBlock
);
212 static ULONG
CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile
,
213 PKEY_BLOCK KeyBlock
);
214 static NTSTATUS
CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile
,
215 IN PKEY_BLOCK KeyBlock
,
216 OUT PKEY_BLOCK
*SubKeyBlock
,
218 IN ACCESS_MASK DesiredAccess
);
219 static NTSTATUS
CmiAddSubKey(IN PREGISTRY_FILE RegistryFile
,
220 IN PKEY_BLOCK CurKeyBlock
,
221 OUT PKEY_BLOCK
*SubKeyBlock
,
222 IN PWSTR NewSubKeyName
,
225 IN ULONG CreateOptions
);
226 static NTSTATUS
CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile
,
227 IN PKEY_BLOCK KeyBlock
,
229 OUT PVALUE_BLOCK
*ValueBlock
);
230 static NTSTATUS
CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile
,
231 IN PKEY_BLOCK KeyBlock
,
232 IN PWSTR ValueNameBuf
,
236 static NTSTATUS
CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile
,
237 IN PKEY_BLOCK KeyBlock
,
239 static NTSTATUS
CmiAllocateKeyBlock(IN PREGISTRY_FILE RegistryFile
,
240 OUT PKEY_BLOCK
*KeyBlock
,
241 IN PWSTR NewSubKeyName
,
244 IN ULONG CreateOptions
);
245 static PKEY_BLOCK
CmiGetKeyBlock(PREGISTRY_FILE RegistryFile
,
246 BLOCK_OFFSET KeyBlockOffset
);
247 static NTSTATUS
CmiDestroyKeyBlock(PREGISTRY_FILE RegistryFile
,
248 PKEY_BLOCK KeyBlock
);
249 static NTSTATUS
CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile
,
250 OUT PHASH_TABLE_BLOCK
*HashBlock
,
251 IN ULONG HashTableSize
);
252 static PHASH_TABLE_BLOCK
CmiGetHashTableBlock(PREGISTRY_FILE RegistryFile
,
253 BLOCK_OFFSET HashBlockOffset
);
254 static PKEY_BLOCK
CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile
,
255 PHASH_TABLE_BLOCK HashBlock
,
257 static NTSTATUS
CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile
,
258 PHASH_TABLE_BLOCK HashBlock
,
259 PKEY_BLOCK NewKeyBlock
);
260 static NTSTATUS
CmiDestroyHashTableBlock(PREGISTRY_FILE RegistryFile
,
261 PHASH_TABLE_BLOCK HashBlock
);
262 static NTSTATUS
CmiAllocateValueBlock(IN PREGISTRY_FILE RegistryFile
,
263 OUT PVALUE_BLOCK
*ValueBlock
,
264 IN PWSTR ValueNameBuf
,
268 static NTSTATUS
CmiReplaceValueData(IN PREGISTRY_FILE RegistryFile
,
269 IN PVALUE_BLOCK ValueBlock
,
273 static NTSTATUS
CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile
,
274 PVALUE_BLOCK ValueBlock
);
275 static NTSTATUS
CmiAllocateBlock(PREGISTRY_FILE RegistryFile
,
278 static NTSTATUS
CmiDestroyBlock(PREGISTRY_FILE RegistryFile
,
280 static PVOID
CmiGetBlock(PREGISTRY_FILE RegistryFile
,
281 BLOCK_OFFSET BlockOffset
);
282 static BLOCK_OFFSET
CmiGetBlockOffset(PREGISTRY_FILE RegistryFile
,
284 static VOID
CmiLockBlock(PREGISTRY_FILE RegistryFile
,
286 static VOID
CmiReleaseBlock(PREGISTRY_FILE RegistryFile
,
291 /* --------------------------------------------- Public Interface */
294 CmInitializeRegistry(VOID
)
298 HANDLE RootKeyHandle
;
299 UNICODE_STRING RootKeyName
;
300 OBJECT_ATTRIBUTES ObjectAttributes
;
303 /* Initialize the Key object type */
304 CmiKeyType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
305 CmiKeyType
->TotalObjects
= 0;
306 CmiKeyType
->TotalHandles
= 0;
307 CmiKeyType
->MaxObjects
= ULONG_MAX
;
308 CmiKeyType
->MaxHandles
= ULONG_MAX
;
309 CmiKeyType
->PagedPoolCharge
= 0;
310 CmiKeyType
->NonpagedPoolCharge
= sizeof(KEY_OBJECT
);
311 CmiKeyType
->Dump
= NULL
;
312 CmiKeyType
->Open
= NULL
;
313 CmiKeyType
->Close
= NULL
;
314 CmiKeyType
->Delete
= CmiObjectDelete
;
315 CmiKeyType
->Parse
= CmiObjectParse
;
316 CmiKeyType
->Security
= NULL
;
317 CmiKeyType
->QueryName
= NULL
;
318 CmiKeyType
->OkayToClose
= NULL
;
319 RtlInitUnicodeString(&CmiKeyType
->TypeName
, L
"Key");
321 /* Build the Root Key Object */
322 /* FIXME: This should be split into two objects, 1 system and 1 user */
323 RtlInitUnicodeString(&RootKeyName
, REG_ROOT_KEY_NAME
);
324 InitializeObjectAttributes(&ObjectAttributes
, &RootKeyName
, 0, NULL
, NULL
);
325 ObCreateObject(&RootKeyHandle
,
326 STANDARD_RIGHTS_REQUIRED
,
330 KeInitializeSpinLock(&CmiKeyListLock
);
332 /* Build volitile registry store */
334 CmiVolatileFile
= CmiCreateRegistry(NULL
);
336 /* Build system registry store */
338 CmiSystemFile
= NULL
; // CmiCreateRegistry(SYSTEM_REG_FILE);
340 /* Create initial predefined symbolic links */
341 /* HKEY_LOCAL_MACHINE */
343 Status
= CmiCreateKey(CmiVolatileFile
,
351 if (!NT_SUCCESS(Status
))
356 CmiReleaseBlock(CmiVolatileFile
, KeyBlock
);
360 Status
= CmiCreateKey(CmiVolatileFile
,
368 if (!NT_SUCCESS(Status
))
373 CmiReleaseBlock(CmiVolatileFile
, KeyBlock
);
375 /* FIXME: create remaining structure needed for default handles */
376 /* FIXME: load volatile registry data from ROSDTECT */
382 CmImportHive(PCHAR Chunk
)
384 /* FIXME: implemement this */
391 OUT PHANDLE KeyHandle
,
392 IN ACCESS_MASK DesiredAccess
,
393 IN POBJECT_ATTRIBUTES ObjectAttributes
,
395 IN PUNICODE_STRING Class
,
396 IN ULONG CreateOptions
,
397 OUT PULONG Disposition
403 PKEY_OBJECT CurKey
, NewKey
;
404 PREGISTRY_FILE FileToUse
;
407 assert(ObjectAttributes
!= NULL
);
409 FileToUse
= (CreateOptions
& REG_OPTION_VOLATILE
) ?
410 CmiVolatileFile
: CmiSystemFile
;
412 /* Construct the complete registry relative pathname */
413 Status
= CmiBuildKeyPath(&KeyNameBuf
, ObjectAttributes
);
414 if (!NT_SUCCESS(Status
))
419 /* Scan the key list to see if key already open */
420 CurKey
= CmiScanKeyList(KeyNameBuf
);
423 /* Unmark the key if the key has been marked for Delete */
424 if (CurKey
->Flags
& KO_MARKED_FOR_DELETE
)
426 CurKey
->Flags
&= ~KO_MARKED_FOR_DELETE
;
429 /* If so, return a reference to it */
430 Status
= ObCreateHandle(PsGetCurrentProcess(),
435 ExFreePool(KeyNameBuf
);
440 /* Create or open the key in the registry file */
441 Status
= CmiCreateKey(FileToUse
,
449 if (!NT_SUCCESS(Status
))
451 ExFreePool(KeyNameBuf
);
456 /* Create new key object and put into linked list */
457 NewKey
= ObCreateObject(KeyHandle
,
463 return STATUS_UNSUCCESSFUL
;
466 NewKey
->Name
= KeyNameBuf
;
467 NewKey
->KeyBlock
= KeyBlock
;
468 NewKey
->RegistryFile
= FileToUse
;
469 CmiAddKeyToList(NewKey
);
470 Status
= ObCreateHandle(PsGetCurrentProcess(),
491 PKEY_OBJECT KeyObject
;
493 /* Verify that the handle is valid and is a registry key */
494 Status
= ObReferenceObjectByHandle(KeyHandle
,
500 if (!NT_SUCCESS(Status
))
505 /* Set the marked for delete bit in the key object */
506 KeyObject
->Flags
|= KO_MARKED_FOR_DELETE
;
508 /* Dereference the object */
509 ObDeleteHandle(PsGetCurrentProcess(),KeyHandle
);
510 /* FIXME: I think that ObDeleteHandle should dereference the object */
511 ObDereferenceObject(KeyObject
);
513 return STATUS_SUCCESS
;
525 IN KEY_INFORMATION_CLASS KeyInformationClass
,
526 OUT PVOID KeyInformation
,
528 OUT PULONG ResultLength
533 PKEY_OBJECT KeyObject
;
534 PREGISTRY_FILE RegistryFile
;
535 PKEY_BLOCK KeyBlock
, SubKeyBlock
;
536 PHASH_TABLE_BLOCK HashTableBlock
;
537 PKEY_BASIC_INFORMATION BasicInformation
;
538 PKEY_NODE_INFORMATION NodeInformation
;
539 PKEY_FULL_INFORMATION FullInformation
;
541 /* Verify that the handle is valid and is a registry key */
542 Status
= ObReferenceObjectByHandle(KeyHandle
,
543 KEY_ENUMERATE_SUB_KEYS
,
548 if (!NT_SUCCESS(Status
))
553 /* Get pointer to KeyBlock */
554 KeyBlock
= KeyObject
->KeyBlock
;
555 RegistryFile
= KeyObject
->RegistryFile
;
557 /* Get pointer to SubKey */
558 HashTableBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
559 SubKeyBlock
= CmiGetKeyFromHashByIndex(RegistryFile
,
562 if (SubKeyBlock
== NULL
)
564 return STATUS_NO_MORE_ENTRIES
;
567 Status
= STATUS_SUCCESS
;
568 switch (KeyInformationClass
)
570 case KeyBasicInformation
:
571 /* Check size of buffer */
572 if (Length
< sizeof(KEY_BASIC_INFORMATION
) +
573 SubKeyBlock
->NameSize
* sizeof(WCHAR
))
575 Status
= STATUS_BUFFER_OVERFLOW
;
579 /* Fill buffer with requested info */
580 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
581 BasicInformation
->LastWriteTime
= SubKeyBlock
->LastWriteTime
;
582 BasicInformation
->TitleIndex
= Index
;
583 BasicInformation
->NameLength
= SubKeyBlock
->NameSize
;
584 wcsncpy(BasicInformation
->Name
,
586 SubKeyBlock
->NameSize
);
587 BasicInformation
->Name
[SubKeyBlock
->NameSize
] = 0;
588 *ResultLength
= sizeof(KEY_BASIC_INFORMATION
) +
589 SubKeyBlock
->NameSize
* sizeof(WCHAR
);
593 case KeyNodeInformation
:
594 /* Check size of buffer */
595 if (Length
< sizeof(KEY_NODE_INFORMATION
) +
596 SubKeyBlock
->NameSize
* sizeof(WCHAR
) +
597 (SubKeyBlock
->ClassSize
+ 1) * sizeof(WCHAR
))
599 Status
= STATUS_BUFFER_OVERFLOW
;
603 /* Fill buffer with requested info */
604 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
605 NodeInformation
->LastWriteTime
= SubKeyBlock
->LastWriteTime
;
606 NodeInformation
->TitleIndex
= Index
;
607 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
608 SubKeyBlock
->NameSize
* sizeof(WCHAR
);
609 NodeInformation
->ClassLength
= SubKeyBlock
->ClassSize
;
610 NodeInformation
->NameLength
= SubKeyBlock
->NameSize
;
611 wcsncpy(NodeInformation
->Name
,
613 SubKeyBlock
->NameSize
);
614 NodeInformation
->Name
[SubKeyBlock
->NameSize
] = 0;
615 if (SubKeyBlock
->ClassSize
!= 0)
617 wcsncpy(NodeInformation
->Name
+ SubKeyBlock
->NameSize
+ 1,
618 &SubKeyBlock
->Name
[SubKeyBlock
->NameSize
+ 1],
619 SubKeyBlock
->ClassSize
);
621 Name
[SubKeyBlock
->NameSize
+ 1 + SubKeyBlock
->ClassSize
] = 0;
623 *ResultLength
= sizeof(KEY_NODE_INFORMATION
) +
624 SubKeyBlock
->NameSize
* sizeof(WCHAR
) +
625 (SubKeyBlock
->ClassSize
+ 1) * sizeof(WCHAR
);
629 case KeyFullInformation
:
630 /* FIXME: check size of buffer */
631 if (Length
< sizeof(KEY_FULL_INFORMATION
) +
632 SubKeyBlock
->ClassSize
* sizeof(WCHAR
))
634 Status
= STATUS_BUFFER_OVERFLOW
;
638 /* FIXME: fill buffer with requested info */
639 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
640 FullInformation
->LastWriteTime
= SubKeyBlock
->LastWriteTime
;
641 FullInformation
->TitleIndex
= Index
;
642 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) -
644 FullInformation
->ClassLength
= SubKeyBlock
->ClassSize
;
645 FullInformation
->SubKeys
= SubKeyBlock
->NumberOfSubKeys
;
646 FullInformation
->MaxNameLen
=
647 CmiGetMaxNameLength(RegistryFile
, SubKeyBlock
);
648 FullInformation
->MaxClassLen
=
649 CmiGetMaxClassLength(RegistryFile
, SubKeyBlock
);
650 FullInformation
->Values
= SubKeyBlock
->NumberOfValues
;
651 FullInformation
->MaxValueNameLen
=
652 CmiGetMaxValueNameLength(RegistryFile
, SubKeyBlock
);
653 FullInformation
->MaxValueDataLen
=
654 CmiGetMaxValueDataLength(RegistryFile
, SubKeyBlock
);
655 wcsncpy(FullInformation
->Class
,
656 &SubKeyBlock
->Name
[SubKeyBlock
->NameSize
+ 1],
657 SubKeyBlock
->ClassSize
);
658 FullInformation
->Class
[SubKeyBlock
->ClassSize
] = 0;
659 *ResultLength
= sizeof(KEY_FULL_INFORMATION
) +
660 SubKeyBlock
->ClassSize
* sizeof(WCHAR
);
664 CmiReleaseBlock(RegistryFile
, SubKeyBlock
);
675 NtEnumerateValueKey (
678 IN KEY_VALUE_INFORMATION_CLASS KeyInformationClass
,
679 OUT PVOID KeyInformation
,
681 OUT PULONG ResultLength
699 return STATUS_SUCCESS
;
709 OUT PHANDLE KeyHandle
,
710 IN ACCESS_MASK DesiredAccess
,
711 IN POBJECT_ATTRIBUTES ObjectAttributes
717 PREGISTRY_FILE FileToUse
;
719 PKEY_OBJECT CurKey
, NewKey
;
721 /* Construct the complete registry relative pathname */
722 Status
= CmiBuildKeyPath(&KeyNameBuf
, ObjectAttributes
);
723 if (!NT_SUCCESS(Status
))
728 /* Scan the key list to see if key already open */
729 CurKey
= CmiScanKeyList(KeyNameBuf
);
732 /* Fail if the key has been deleted */
733 if (CurKey
->Flags
& KO_MARKED_FOR_DELETE
)
735 ExFreePool(KeyNameBuf
);
737 return STATUS_UNSUCCESSFUL
;
740 /* If so, return a reference to it */
741 Status
= ObCreateHandle(PsGetCurrentProcess(),
746 ExFreePool(KeyNameBuf
);
751 /* Open the key in the registry file */
752 FileToUse
= CmiSystemFile
;
753 Status
= CmiFindKey(FileToUse
,
759 if (!NT_SUCCESS(Status
))
761 FileToUse
= CmiVolatileFile
;
762 Status
= CmiFindKey(FileToUse
,
768 if (!NT_SUCCESS(Status
))
770 ExFreePool(KeyNameBuf
);
776 /* Create new key object and put into linked list */
777 NewKey
= ObCreateObject(KeyHandle
,
783 return STATUS_UNSUCCESSFUL
;
786 NewKey
->Name
= KeyNameBuf
;
787 NewKey
->RegistryFile
= FileToUse
;
788 NewKey
->KeyBlock
= KeyBlock
;
789 CmiAddKeyToList(NewKey
);
790 Status
= ObCreateHandle(PsGetCurrentProcess(),
807 IN KEY_INFORMATION_CLASS KeyInformationClass
,
808 OUT PVOID KeyInformation
,
810 OUT PULONG ResultLength
815 PKEY_OBJECT KeyObject
;
816 PREGISTRY_FILE RegistryFile
;
818 PKEY_BASIC_INFORMATION BasicInformation
;
819 PKEY_NODE_INFORMATION NodeInformation
;
820 PKEY_FULL_INFORMATION FullInformation
;
822 /* Verify that the handle is valid and is a registry key */
823 Status
= ObReferenceObjectByHandle(KeyHandle
,
829 if (!NT_SUCCESS(Status
))
834 /* Get pointer to KeyBlock */
835 KeyBlock
= KeyObject
->KeyBlock
;
836 RegistryFile
= KeyObject
->RegistryFile
;
838 Status
= STATUS_SUCCESS
;
839 switch (KeyInformationClass
)
841 case KeyBasicInformation
:
842 /* Check size of buffer */
843 if (Length
< sizeof(KEY_BASIC_INFORMATION
) +
844 KeyBlock
->NameSize
* sizeof(WCHAR
))
846 Status
= STATUS_BUFFER_OVERFLOW
;
850 /* Fill buffer with requested info */
851 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
852 BasicInformation
->LastWriteTime
= KeyBlock
->LastWriteTime
;
853 BasicInformation
->TitleIndex
= 0;
854 BasicInformation
->NameLength
= KeyBlock
->NameSize
;
855 wcsncpy(BasicInformation
->Name
,
858 BasicInformation
->Name
[KeyBlock
->NameSize
] = 0;
859 *ResultLength
= sizeof(KEY_BASIC_INFORMATION
) +
860 KeyBlock
->NameSize
* sizeof(WCHAR
);
864 case KeyNodeInformation
:
865 /* Check size of buffer */
866 if (Length
< sizeof(KEY_NODE_INFORMATION
) +
867 KeyBlock
->NameSize
* sizeof(WCHAR
) +
868 (KeyBlock
->ClassSize
+ 1) * sizeof(WCHAR
))
870 Status
= STATUS_BUFFER_OVERFLOW
;
874 /* Fill buffer with requested info */
875 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
876 NodeInformation
->LastWriteTime
= KeyBlock
->LastWriteTime
;
877 NodeInformation
->TitleIndex
= 0;
878 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
879 KeyBlock
->NameSize
* sizeof(WCHAR
);
880 NodeInformation
->ClassLength
= KeyBlock
->ClassSize
;
881 NodeInformation
->NameLength
= KeyBlock
->NameSize
;
882 wcsncpy(NodeInformation
->Name
,
885 NodeInformation
->Name
[KeyBlock
->NameSize
] = 0;
886 if (KeyBlock
->ClassSize
!= 0)
888 wcsncpy(NodeInformation
->Name
+ KeyBlock
->NameSize
+ 1,
889 &KeyBlock
->Name
[KeyBlock
->NameSize
+ 1],
890 KeyBlock
->ClassSize
);
892 Name
[KeyBlock
->NameSize
+ 1 + KeyBlock
->ClassSize
] = 0;
894 *ResultLength
= sizeof(KEY_NODE_INFORMATION
) +
895 KeyBlock
->NameSize
* sizeof(WCHAR
) +
896 (KeyBlock
->ClassSize
+ 1) * sizeof(WCHAR
);
900 case KeyFullInformation
:
901 /* Check size of buffer */
902 if (Length
< sizeof(KEY_FULL_INFORMATION
) +
903 KeyBlock
->ClassSize
* sizeof(WCHAR
))
905 Status
= STATUS_BUFFER_OVERFLOW
;
909 /* Fill buffer with requested info */
910 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
911 FullInformation
->LastWriteTime
= KeyBlock
->LastWriteTime
;
912 FullInformation
->TitleIndex
= 0;
913 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) -
915 FullInformation
->ClassLength
= KeyBlock
->ClassSize
;
916 FullInformation
->SubKeys
= KeyBlock
->NumberOfSubKeys
;
917 FullInformation
->MaxNameLen
=
918 CmiGetMaxNameLength(RegistryFile
, KeyBlock
);
919 FullInformation
->MaxClassLen
=
920 CmiGetMaxClassLength(RegistryFile
, KeyBlock
);
921 FullInformation
->Values
= KeyBlock
->NumberOfValues
;
922 FullInformation
->MaxValueNameLen
=
923 CmiGetMaxValueNameLength(RegistryFile
, KeyBlock
);
924 FullInformation
->MaxValueDataLen
=
925 CmiGetMaxValueDataLength(RegistryFile
, KeyBlock
);
926 wcsncpy(FullInformation
->Class
,
927 &KeyBlock
->Name
[KeyBlock
->NameSize
+ 1],
928 KeyBlock
->ClassSize
);
929 FullInformation
->Class
[KeyBlock
->ClassSize
] = 0;
930 *ResultLength
= sizeof(KEY_FULL_INFORMATION
) +
931 KeyBlock
->ClassSize
* sizeof(WCHAR
);
947 IN PUNICODE_STRING ValueName
,
948 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
949 OUT PVOID KeyValueInformation
,
951 OUT PULONG ResultLength
956 PKEY_OBJECT KeyObject
;
957 PREGISTRY_FILE RegistryFile
;
959 PVALUE_BLOCK ValueBlock
;
961 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
962 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
963 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
965 /* Verify that the handle is valid and is a registry key */
966 Status
= ObReferenceObjectByHandle(KeyHandle
,
972 if (!NT_SUCCESS(Status
))
977 /* Get pointer to KeyBlock */
978 KeyBlock
= KeyObject
->KeyBlock
;
979 RegistryFile
= KeyObject
->RegistryFile
;
981 /* Get Value block of interest */
982 Status
= CmiScanKeyForValue(RegistryFile
,
986 if (!NT_SUCCESS(Status
))
990 else if (ValueBlock
!= NULL
)
992 switch (KeyValueInformationClass
)
994 case KeyValueBasicInformation
:
995 *ResultLength
= sizeof(KEY_VALUE_BASIC_INFORMATION
) +
996 ValueBlock
->NameSize
* sizeof(WCHAR
);
997 if (Length
< *ResultLength
)
999 Status
= STATUS_BUFFER_OVERFLOW
;
1003 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1004 KeyValueInformation
;
1005 ValueBasicInformation
->TitleIndex
= 0;
1006 ValueBasicInformation
->Type
= ValueBlock
->DataType
;
1007 ValueBasicInformation
->NameLength
= ValueBlock
->NameSize
;
1008 wcscpy(ValueBasicInformation
->Name
, ValueBlock
->Name
);
1012 case KeyValuePartialInformation
:
1013 *ResultLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
1014 ValueBlock
->DataSize
;
1015 if (Length
< *ResultLength
)
1017 Status
= STATUS_BUFFER_OVERFLOW
;
1021 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1022 KeyValueInformation
;
1023 ValuePartialInformation
->TitleIndex
= 0;
1024 ValuePartialInformation
->Type
= ValueBlock
->DataType
;
1025 ValuePartialInformation
->DataLength
= ValueBlock
->DataSize
;
1026 DataBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
);
1027 RtlCopyMemory(ValuePartialInformation
->Data
,
1029 ValueBlock
->DataSize
);
1030 CmiReleaseBlock(RegistryFile
, DataBlock
);
1034 case KeyValueFullInformation
:
1035 *ResultLength
= sizeof(KEY_VALUE_FULL_INFORMATION
) +
1036 ValueBlock
->NameSize
* sizeof(WCHAR
) + ValueBlock
->DataSize
;
1037 if (Length
< *ResultLength
)
1039 Status
= STATUS_BUFFER_OVERFLOW
;
1043 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1044 KeyValueInformation
;
1045 ValueFullInformation
->TitleIndex
= 0;
1046 ValueFullInformation
->Type
= ValueBlock
->DataType
;
1047 ValueFullInformation
->DataOffset
=
1048 sizeof(KEY_VALUE_FULL_INFORMATION
) +
1049 ValueBlock
->NameSize
* sizeof(WCHAR
);
1050 ValueFullInformation
->DataLength
= ValueBlock
->DataSize
;
1051 ValueFullInformation
->NameLength
= ValueBlock
->NameSize
;
1052 wcscpy(ValueFullInformation
->Name
, ValueBlock
->Name
);
1053 DataBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
);
1054 RtlCopyMemory(&ValueFullInformation
->Name
[ValueBlock
->NameSize
+ 1],
1056 ValueBlock
->DataSize
);
1057 CmiReleaseBlock(RegistryFile
, DataBlock
);
1064 Status
= STATUS_UNSUCCESSFUL
;
1077 IN HANDLE KeyHandle
,
1078 IN PUNICODE_STRING ValueName
,
1079 IN ULONG TitleIndex
,
1087 PKEY_OBJECT KeyObject
;
1088 PREGISTRY_FILE RegistryFile
;
1089 PKEY_BLOCK KeyBlock
;
1090 PVALUE_BLOCK ValueBlock
;
1092 /* Verify that the handle is valid and is a registry key */
1093 Status
= ObReferenceObjectByHandle(KeyHandle
,
1097 (PVOID
*)&KeyObject
,
1099 if (!NT_SUCCESS(Status
))
1104 /* Get pointer to KeyBlock */
1105 KeyBlock
= KeyObject
->KeyBlock
;
1106 RegistryFile
= KeyObject
->RegistryFile
;
1107 Status
= CmiScanKeyForValue(RegistryFile
,
1111 if (!NT_SUCCESS(Status
))
1115 if (ValueBlock
== NULL
)
1117 Status
= CmiAddValueToKey(RegistryFile
,
1126 Status
= CmiReplaceValueData(RegistryFile
,
1142 IN HANDLE KeyHandle
,
1143 IN PUNICODE_STRING ValueName
1148 PKEY_OBJECT KeyObject
;
1149 PREGISTRY_FILE RegistryFile
;
1150 PKEY_BLOCK KeyBlock
;
1152 /* Verify that the handle is valid and is a registry key */
1153 Status
= ObReferenceObjectByHandle(KeyHandle
,
1157 (PVOID
*)&KeyObject
,
1159 if (!NT_SUCCESS(Status
))
1164 /* Get pointer to KeyBlock */
1165 KeyBlock
= KeyObject
->KeyBlock
;
1166 RegistryFile
= KeyObject
->RegistryFile
;
1167 Status
= CmiDeleteValueFromKey(RegistryFile
,
1181 OBJECT_ATTRIBUTES ObjectAttributes
1199 IN HANDLE KeyHandle
,
1201 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
1202 IN PVOID ApcContext OPTIONAL
,
1203 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1204 IN ULONG CompletionFilter
,
1205 IN BOOLEAN Asynchroneous
,
1206 OUT PVOID ChangeBuffer
,
1208 IN BOOLEAN WatchSubtree
1217 NtQueryMultipleValueKey (
1218 IN HANDLE KeyHandle
,
1219 IN PWVALENT ListOfValuesToQuery
,
1220 IN ULONG NumberOfItems
,
1221 OUT PVOID MultipleValueInformation
,
1223 OUT PULONG ReturnLength
)
1232 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1234 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
1244 IN HANDLE KeyHandle
,
1245 IN HANDLE FileHandle
,
1246 IN ULONG RestoreFlags
1256 IN HANDLE KeyHandle
,
1257 IN HANDLE FileHandle
1266 NtSetInformationKey (
1267 IN HANDLE KeyHandle
,
1268 IN CINT KeyInformationClass
,
1269 IN PVOID KeyInformation
,
1270 IN ULONG KeyInformationLength
1289 NtInitializeRegistry (
1299 RtlCheckRegistryKey (
1310 RtlCreateRegistryKey (
1311 IN ULONG RelativeTo
,
1321 RtlDeleteRegistryValue (
1322 IN ULONG RelativeTo
,
1333 RtlQueryRegistryValues (
1334 IN ULONG RelativeTo
,
1336 PRTL_QUERY_REGISTRY_TABLE QueryTable
,
1347 RtlWriteRegistryValue (
1359 /* ------------------------------------------ Private Implementation */
1364 //CmiObjectParse(PVOID ParsedObject, PWSTR *Path)
1365 static NTSTATUS
CmiObjectParse(PVOID ParsedObject
,
1367 PUNICODE_STRING FullPath
,
1371 /* FIXME: this should be allocated based on the largest subkey name */
1372 WCHAR CurKeyName
[260];
1373 PWSTR Remainder
, NextSlash
;
1374 PREGISTRY_FILE RegistryFile
;
1375 PKEY_OBJECT NewKeyObject
;
1377 PKEY_BLOCK CurKeyBlock
, SubKeyBlock
;
1379 Status
= STATUS_SUCCESS
;
1381 /* FIXME: it should probably get this from ParsedObject */
1382 RegistryFile
= CmiVolatileFile
;
1384 /* Scan key object list for key already open */
1385 NewKeyObject
= CmiScanKeyList((*Path
) + 1);
1386 if (NewKeyObject
!= NULL
)
1388 /* Return reference if found */
1389 ObReferenceObjectByPointer(NewKeyObject
,
1390 STANDARD_RIGHTS_REQUIRED
,
1395 // return NewKeyObject;
1400 CurKeyBlock
= CmiGetKeyBlock(RegistryFile
,
1401 RegistryFile
->HeaderBlock
->RootKeyBlock
);
1403 /* Loop through each key level and find the needed subkey */
1404 Remainder
= (*Path
) + 1;
1405 while (NT_SUCCESS(Status
) && *Remainder
!= 0)
1407 NextSlash
= wcschr(Remainder
, L
'\\');
1409 /* Copy just the current subkey name to a buffer */
1410 if (NextSlash
!= NULL
)
1412 wcsncpy(CurKeyName
, Remainder
, NextSlash
- Remainder
);
1413 CurKeyName
[NextSlash
- Remainder
] = 0;
1417 wcscpy(CurKeyName
, Remainder
);
1420 /* Verify existance of CurKeyName */
1421 Status
= CmiScanForSubKey(RegistryFile
,
1425 STANDARD_RIGHTS_REQUIRED
);
1426 if (!NT_SUCCESS(Status
))
1430 if (SubKeyBlock
== NULL
)
1432 Status
= STATUS_UNSUCCESSFUL
;
1435 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1436 CurKeyBlock
= SubKeyBlock
;
1438 if (NextSlash
!= NULL
)
1440 Remainder
= NextSlash
+ 1;
1448 /* Create new key object and put into linked list */
1449 NewKeyObject
= ObCreateObject(&KeyHandle
,
1450 STANDARD_RIGHTS_REQUIRED
,
1453 if (NewKeyObject
== NULL
)
1455 //FIXME : return the good error code
1456 return STATUS_UNSUCCESSFUL
;
1458 NewKeyObject
->Flags
= 0;
1459 NewKeyObject
->Name
= ExAllocatePool(NonPagedPool
,
1460 wcslen(*Path
) * sizeof(WCHAR
));
1461 wcscpy(NewKeyObject
->Name
, (*Path
) + 1);
1462 NewKeyObject
->KeyBlock
= CurKeyBlock
;
1463 NewKeyObject
->RegistryFile
= RegistryFile
;
1464 CmiAddKeyToList(NewKeyObject
);
1465 *Path
= (Remainder
!= NULL
) ? Remainder
- 1 : NULL
;
1467 NextObject
= (PVOID
)NewKeyObject
;
1468 return STATUS_SUCCESS
;
1472 CmiObjectDelete(PVOID DeletedObject
)
1474 PKEY_OBJECT KeyObject
;
1476 KeyObject
= (PKEY_OBJECT
) DeletedObject
;
1477 if (KeyObject
->Flags
& KO_MARKED_FOR_DELETE
)
1479 CmiDestroyKeyBlock(KeyObject
->RegistryFile
,
1480 KeyObject
->KeyBlock
);
1484 CmiReleaseBlock(KeyObject
->RegistryFile
,
1485 KeyObject
->KeyBlock
);
1487 ExFreePool(KeyObject
->Name
);
1488 CmiRemoveKeyFromList(KeyObject
);
1492 CmiBuildKeyPath(PWSTR
*KeyPath
, POBJECT_ATTRIBUTES ObjectAttributes
)
1498 PKEY_OBJECT KeyObject
;
1499 POBJECT_HEADER ObjectHeader
;
1501 /* FIXME: Verify ObjectAttributes is in \\Registry space and compute size for path */
1504 if (ObjectAttributes
->RootDirectory
!= NULL
)
1506 /* FIXME: determine type of object for RootDirectory */
1507 Status
= ObReferenceObjectByHandle(ObjectAttributes
->RootDirectory
,
1511 (PVOID
*)&ObjectBody
,
1513 if (!NT_SUCCESS(Status
))
1517 ObjectHeader
= BODY_TO_HEADER(ObjectBody
);
1519 if (ObjectHeader
->ObjectType
!= CmiKeyType
)
1521 /* Fail if RootDirectory != '\\' */
1522 if (ObjectBody
== NameSpaceRoot
)
1524 /* Check for 'Registry' in ObjectName, fail if missing */
1525 if (wcsncmp(ObjectAttributes
->ObjectName
->Buffer
,
1526 REG_ROOT_KEY_NAME
+ 1,
1527 wcslen(REG_ROOT_KEY_NAME
+ 1)) != 0 ||
1528 ObjectAttributes
->ObjectName
->Buffer
[wcslen(REG_ROOT_KEY_NAME
+ 1)] != L
'\\')
1530 ObDereferenceObject(ObjectBody
);
1532 return STATUS_OBJECT_PATH_INVALID
;
1535 /* Compute size of registry portion of path to KeyNameSize */
1536 KeyNameSize
= (ObjectAttributes
->ObjectName
->Length
-
1537 (wcslen(REG_ROOT_KEY_NAME
+ 1) + 1))
1540 else if (!wcscmp(ObjectHeader
->Name
.Buffer
,
1541 REG_ROOT_KEY_NAME
+ 1))
1543 /* Add size of ObjectName to KeyNameSize */
1544 KeyNameSize
= ObjectAttributes
->ObjectName
->Length
;
1548 ObDereferenceObject(ObjectBody
);
1550 return STATUS_OBJECT_PATH_INVALID
;
1555 KeyObject
= (PKEY_OBJECT
) ObjectBody
;
1557 /* Add size of Name from RootDirectory object to KeyNameSize */
1558 KeyNameSize
= wcslen(KeyObject
->Name
) * sizeof(WCHAR
);
1560 /* Add 1 to KeyNamesize for '\\' */
1561 KeyNameSize
+= sizeof(WCHAR
);
1563 /* Add size of ObjectName to KeyNameSize */
1564 KeyNameSize
+= ObjectAttributes
->ObjectName
->Length
* sizeof(WCHAR
);
1569 /* Check for \\Registry and fail if missing */
1570 if (wcsncmp(ObjectAttributes
->ObjectName
->Buffer
,
1572 wcslen(REG_ROOT_KEY_NAME
)) != 0 ||
1573 ObjectAttributes
->ObjectName
->Buffer
[wcslen(REG_ROOT_KEY_NAME
)] != L
'\\')
1575 return STATUS_OBJECT_PATH_INVALID
;
1578 /* Compute size of registry portion of path to KeyNameSize */
1579 KeyNameSize
= (ObjectAttributes
->ObjectName
->Length
-
1580 (wcslen(REG_ROOT_KEY_NAME
) + 1)) * sizeof(WCHAR
);
1583 KeyNameBuf
= ExAllocatePool(NonPagedPool
, KeyNameSize
+ sizeof(WCHAR
));
1585 /* Construct relative pathname */
1587 if (ObjectAttributes
->RootDirectory
!= NULL
)
1589 if (ObjectHeader
->ObjectType
!= CmiKeyType
)
1591 /* Fail if RootDirectory != '\\' */
1592 if (ObjectBody
== NameSpaceRoot
)
1594 /* Copy remainder of ObjectName after 'Registry' */
1595 wcscpy(KeyNameBuf
, ObjectAttributes
->ObjectName
->Buffer
+ wcslen(REG_ROOT_KEY_NAME
+ 1));
1599 /* Copy all of ObjectName */
1600 wcscpy(KeyNameBuf
, ObjectAttributes
->ObjectName
->Buffer
);
1605 KeyObject
= (PKEY_OBJECT
) ObjectBody
;
1607 /* Copy Name from RootDirectory object to KeyNameBuf */
1608 wcscpy(KeyNameBuf
, KeyObject
->Name
);
1610 /* Append '\\' onto KeyNameBuf */
1611 wcscat(KeyNameBuf
, L
"\\");
1613 /* Append ObjectName onto KeyNameBuf */
1614 wcscat(KeyNameBuf
, ObjectAttributes
->ObjectName
->Buffer
);
1619 /* Copy registry portion of path into KeyNameBuf */
1620 wcscpy(KeyNameBuf
, ObjectAttributes
->ObjectName
->Buffer
+
1621 (wcslen(REG_ROOT_KEY_NAME
) + 1));
1624 *KeyPath
= KeyNameBuf
;
1625 return STATUS_SUCCESS
;
1629 CmiAddKeyToList(PKEY_OBJECT NewKey
)
1633 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
1634 NewKey
->NextKey
= CmiKeyList
;
1635 CmiKeyList
= NewKey
;
1636 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
1640 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove
)
1645 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
1646 if (CmiKeyList
== KeyToRemove
)
1648 CmiKeyList
= CmiKeyList
->NextKey
;
1652 CurKey
= CmiKeyList
;
1653 while (CurKey
!= NULL
&& CurKey
->NextKey
!= KeyToRemove
)
1655 CurKey
= CurKey
->NextKey
;
1659 CurKey
->NextKey
= KeyToRemove
->NextKey
;
1662 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
1666 CmiScanKeyList(PWSTR KeyName
)
1671 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
1672 CurKey
= CmiKeyList
;
1673 while (CurKey
!= NULL
&& wcscmp(KeyName
, CurKey
->Name
) != 0)
1675 CurKey
= CurKey
->NextKey
;
1677 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
1682 static PREGISTRY_FILE
1683 CmiCreateRegistry(PWSTR Filename
)
1685 PREGISTRY_FILE RegistryFile
;
1686 PKEY_BLOCK RootKeyBlock
;
1688 RegistryFile
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_FILE
));
1689 if (Filename
!= NULL
)
1692 /* FIXME: Duplicate Filename */
1693 /* FIXME: if file does not exist, create new file */
1694 /* FIXME: else attempt to map the file */
1698 RegistryFile
->Filename
= NULL
;
1699 RegistryFile
->FileHandle
= NULL
;
1701 RegistryFile
->HeaderBlock
= (PHEADER_BLOCK
)
1702 ExAllocatePool(NonPagedPool
, sizeof(HEADER_BLOCK
));
1703 RtlZeroMemory(RegistryFile
->HeaderBlock
, sizeof(HEADER_BLOCK
));
1704 RegistryFile
->HeaderBlock
->BlockId
= 0x66676572;
1705 RegistryFile
->HeaderBlock
->DateModified
.QuadPart
= 0;
1706 RegistryFile
->HeaderBlock
->Unused2
= 1;
1707 RegistryFile
->HeaderBlock
->Unused3
= 3;
1708 RegistryFile
->HeaderBlock
->Unused5
= 1;
1709 RegistryFile
->HeaderBlock
->RootKeyBlock
= 0;
1710 RegistryFile
->HeaderBlock
->BlockSize
= REG_BLOCK_SIZE
;
1711 RegistryFile
->HeaderBlock
->Unused6
= 1;
1712 RegistryFile
->HeaderBlock
->Checksum
= 0;
1713 RootKeyBlock
= (PKEY_BLOCK
)
1714 ExAllocatePool(NonPagedPool
, sizeof(KEY_BLOCK
));
1715 RtlZeroMemory(RootKeyBlock
, sizeof(KEY_BLOCK
));
1716 RootKeyBlock
->SubBlockId
= REG_KEY_BLOCK_ID
;
1717 RootKeyBlock
->Type
= REG_ROOT_KEY_BLOCK_TYPE
;
1718 ZwQuerySystemTime((PTIME
) &RootKeyBlock
->LastWriteTime
);
1719 RootKeyBlock
->ParentKeyOffset
= 0;
1720 RootKeyBlock
->NumberOfSubKeys
= 0;
1721 RootKeyBlock
->HashTableOffset
= 0;
1722 RootKeyBlock
->NumberOfValues
= 0;
1723 RootKeyBlock
->ValuesOffset
= 0;
1724 RootKeyBlock
->SecurityKeyOffset
= 0;
1725 RootKeyBlock
->ClassNameOffset
= sizeof(KEY_BLOCK
);
1726 RootKeyBlock
->NameSize
= 0;
1727 RootKeyBlock
->ClassSize
= 0;
1728 RootKeyBlock
->Name
[0] = 0;
1729 RegistryFile
->HeaderBlock
->RootKeyBlock
= (BLOCK_OFFSET
) RootKeyBlock
;
1732 return RegistryFile
;
1736 CmiCreateKey(IN PREGISTRY_FILE RegistryFile
,
1737 IN PWSTR KeyNameBuf
,
1738 OUT PKEY_BLOCK
*KeyBlock
,
1739 IN ACCESS_MASK DesiredAccess
,
1740 IN ULONG TitleIndex
,
1741 IN PUNICODE_STRING Class
,
1742 IN ULONG CreateOptions
,
1743 OUT PULONG Disposition
)
1745 /* FIXME: this should be allocated based on the largest subkey name */
1747 WCHAR CurKeyName
[256];
1749 PWSTR Remainder
, NextSlash
;
1750 PKEY_BLOCK CurKeyBlock
, SubKeyBlock
;
1752 /* FIXME: Should handle search by Class/TitleIndex */
1755 /* Loop through each key level and find or build the needed subkey */
1756 Status
= STATUS_SUCCESS
;
1757 /* FIXME: this access of RootKeyBlock should be guarded by spinlock */
1758 CurKeyBlock
= CmiGetKeyBlock(RegistryFile
,
1759 RegistryFile
->HeaderBlock
->RootKeyBlock
);
1761 Remainder
= KeyNameBuf
;
1762 while (NT_SUCCESS(Status
) &&
1763 (NextSlash
= wcschr(Remainder
, L
'\\')) != NULL
)
1765 /* Copy just the current subkey name to a buffer */
1766 wcsncpy(CurKeyName
, Remainder
, NextSlash
- Remainder
);
1767 CurKeyName
[NextSlash
- Remainder
] = 0;
1769 /* Verify existance of/Create CurKeyName */
1771 Status
= CmiScanForSubKey(RegistryFile
,
1776 if (!NT_SUCCESS(Status
))
1780 if (SubKeyBlock
== NULL
)
1782 Status
= CmiAddSubKey(RegistryFile
,
1789 if (!NT_SUCCESS(Status
))
1794 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1795 CurKeyBlock
= SubKeyBlock
;
1797 Remainder
= NextSlash
+ 1;
1800 if (NT_SUCCESS(Status
))
1803 Status
= CmiScanForSubKey(RegistryFile
,
1808 if (NT_SUCCESS(Status
))
1810 if (SubKeyBlock
== NULL
)
1814 ClassName
= ExAllocatePool(NonPagedPool
, Class
->Length
+ 1);
1815 wcsncpy(ClassName
, Class
->Buffer
, Class
->Length
);
1816 ClassName
[Class
->Length
] = 0;
1822 Status
= CmiAddSubKey(RegistryFile
,
1829 if (ClassName
!= NULL
)
1831 ExFreePool(ClassName
);
1833 if (NT_SUCCESS(Status
) && Disposition
!= NULL
)
1835 *Disposition
= REG_CREATED_NEW_KEY
;
1838 else if (Disposition
!= NULL
)
1840 *Disposition
= REG_OPENED_EXISTING_KEY
;
1843 *KeyBlock
= SubKeyBlock
;
1845 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1851 CmiFindKey(IN PREGISTRY_FILE RegistryFile
,
1852 IN PWSTR KeyNameBuf
,
1853 OUT PKEY_BLOCK
*KeyBlock
,
1854 IN ACCESS_MASK DesiredAccess
,
1855 IN ULONG TitleIndex
,
1856 IN PUNICODE_STRING Class
)
1858 /* FIXME: this should be allocated based on the largest subkey name */
1860 WCHAR CurKeyName
[256];
1861 PWSTR Remainder
, NextSlash
;
1862 PKEY_BLOCK CurKeyBlock
, SubKeyBlock
;
1864 /* FIXME: Should handle search by Class/TitleIndex */
1866 /* Loop through each key level and find the needed subkey */
1867 Status
= STATUS_SUCCESS
;
1868 /* FIXME: this access of RootKeyBlock should be guarded by spinlock */
1869 CurKeyBlock
= CmiGetKeyBlock(RegistryFile
, RegistryFile
->HeaderBlock
->RootKeyBlock
);
1870 Remainder
= KeyNameBuf
;
1871 while (NT_SUCCESS(Status
) &&
1872 (NextSlash
= wcschr(Remainder
, L
'\\')) != NULL
)
1874 /* Copy just the current subkey name to a buffer */
1875 wcsncpy(CurKeyName
, Remainder
, NextSlash
- Remainder
);
1876 CurKeyName
[NextSlash
- Remainder
] = 0;
1878 /* Verify existance of CurKeyName */
1879 Status
= CmiScanForSubKey(RegistryFile
,
1884 if (!NT_SUCCESS(Status
))
1888 if (SubKeyBlock
== NULL
)
1890 Status
= STATUS_UNSUCCESSFUL
;
1893 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1894 CurKeyBlock
= SubKeyBlock
;
1896 Remainder
= NextSlash
+ 1;
1898 if (NT_SUCCESS(Status
))
1900 Status
= CmiScanForSubKey(RegistryFile
,
1905 if (NT_SUCCESS(Status
))
1907 if (SubKeyBlock
== NULL
)
1909 Status
= STATUS_UNSUCCESSFUL
;
1913 *KeyBlock
= SubKeyBlock
;
1917 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1923 CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile
,
1924 PKEY_BLOCK KeyBlock
)
1927 PHASH_TABLE_BLOCK HashBlock
;
1928 PKEY_BLOCK CurSubKeyBlock
;
1931 HashBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
1936 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
1938 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0)
1940 CurSubKeyBlock
= CmiGetKeyBlock(RegistryFile
,
1941 HashBlock
->Table
[Idx
].KeyOffset
);
1942 if (MaxName
< CurSubKeyBlock
->NameSize
)
1944 MaxName
= CurSubKeyBlock
->NameSize
;
1946 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
1950 CmiReleaseBlock(RegistryFile
, HashBlock
);
1956 CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile
,
1957 PKEY_BLOCK KeyBlock
)
1959 ULONG Idx
, MaxClass
;
1960 PHASH_TABLE_BLOCK HashBlock
;
1961 PKEY_BLOCK CurSubKeyBlock
;
1964 HashBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
1969 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
1971 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0)
1973 CurSubKeyBlock
= CmiGetKeyBlock(RegistryFile
,
1974 HashBlock
->Table
[Idx
].KeyOffset
);
1975 if (MaxClass
< CurSubKeyBlock
->ClassSize
)
1977 MaxClass
= CurSubKeyBlock
->ClassSize
;
1979 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
1983 CmiReleaseBlock(RegistryFile
, HashBlock
);
1989 CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile
,
1990 PKEY_BLOCK KeyBlock
)
1992 ULONG Idx
, MaxValueName
;
1993 PVALUE_LIST_BLOCK ValueListBlock
;
1994 PVALUE_BLOCK CurValueBlock
;
1996 ValueListBlock
= CmiGetBlock(RegistryFile
,
1997 KeyBlock
->ValuesOffset
);
1999 if (ValueListBlock
== 0)
2003 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
2005 CurValueBlock
= CmiGetBlock(RegistryFile
,
2006 ValueListBlock
->Values
[Idx
]);
2007 if (CurValueBlock
!= NULL
&&
2008 MaxValueName
< CurValueBlock
->NameSize
)
2010 MaxValueName
= CurValueBlock
->NameSize
;
2012 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
2015 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2017 return MaxValueName
;
2021 CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile
,
2022 PKEY_BLOCK KeyBlock
)
2024 ULONG Idx
, MaxValueData
;
2025 PVALUE_LIST_BLOCK ValueListBlock
;
2026 PVALUE_BLOCK CurValueBlock
;
2028 ValueListBlock
= CmiGetBlock(RegistryFile
,
2029 KeyBlock
->ValuesOffset
);
2031 if (ValueListBlock
== 0)
2035 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
2037 CurValueBlock
= CmiGetBlock(RegistryFile
,
2038 ValueListBlock
->Values
[Idx
]);
2039 if (CurValueBlock
!= NULL
&&
2040 MaxValueData
< CurValueBlock
->DataSize
)
2042 MaxValueData
= CurValueBlock
->DataSize
;
2044 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
2047 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2049 return MaxValueData
;
2053 CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile
,
2054 IN PKEY_BLOCK KeyBlock
,
2055 OUT PKEY_BLOCK
*SubKeyBlock
,
2057 IN ACCESS_MASK DesiredAccess
)
2060 PHASH_TABLE_BLOCK HashBlock
;
2061 PKEY_BLOCK CurSubKeyBlock
;
2063 HashBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
2064 *SubKeyBlock
= NULL
;
2067 return STATUS_SUCCESS
;
2069 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
2071 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0 &&
2072 !wcsncmp(KeyName
, (PWSTR
) &HashBlock
->Table
[Idx
].HashValue
, 4))
2074 CurSubKeyBlock
= CmiGetKeyBlock(RegistryFile
,
2075 HashBlock
->Table
[Idx
].KeyOffset
);
2076 if (!wcscmp(KeyName
, CurSubKeyBlock
->Name
))
2078 *SubKeyBlock
= CurSubKeyBlock
;
2083 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
2088 CmiReleaseBlock(RegistryFile
, HashBlock
);
2090 return STATUS_SUCCESS
;
2094 CmiAddSubKey(PREGISTRY_FILE RegistryFile
,
2095 PKEY_BLOCK KeyBlock
,
2096 PKEY_BLOCK
*SubKeyBlock
,
2097 PWSTR NewSubKeyName
,
2100 ULONG CreateOptions
)
2103 PHASH_TABLE_BLOCK HashBlock
, NewHashBlock
;
2104 PKEY_BLOCK NewKeyBlock
;
2106 Status
= CmiAllocateKeyBlock(RegistryFile
,
2112 if (!NT_SUCCESS(Status
))
2116 if (KeyBlock
->HashTableOffset
== 0)
2118 Status
= CmiAllocateHashTableBlock(RegistryFile
,
2120 REG_INIT_HASH_TABLE_SIZE
);
2121 if (!NT_SUCCESS(Status
))
2125 KeyBlock
->HashTableOffset
= CmiGetBlockOffset(RegistryFile
, HashBlock
);
2129 HashBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
2130 if (KeyBlock
->NumberOfSubKeys
+ 1 >= HashBlock
->HashTableSize
)
2133 /* FIXME: All Subkeys will need to be rehashed here! */
2135 /* Reallocate the hash table block */
2136 Status
= CmiAllocateHashTableBlock(RegistryFile
,
2138 HashBlock
->HashTableSize
+
2139 REG_EXTEND_HASH_TABLE_SIZE
);
2140 if (!NT_SUCCESS(Status
))
2144 RtlZeroMemory(&NewHashBlock
->Table
[0],
2145 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2146 RtlCopyMemory(&NewHashBlock
->Table
[0],
2147 &HashBlock
->Table
[0],
2148 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2149 KeyBlock
->HashTableOffset
= CmiGetBlockOffset(RegistryFile
, NewHashBlock
);
2150 CmiDestroyHashTableBlock(RegistryFile
, HashBlock
);
2151 HashBlock
= NewHashBlock
;
2154 Status
= CmiAddKeyToHashTable(RegistryFile
, HashBlock
, NewKeyBlock
);
2155 if (NT_SUCCESS(Status
))
2157 KeyBlock
->NumberOfSubKeys
++;
2158 *SubKeyBlock
= NewKeyBlock
;
2160 CmiReleaseBlock(RegistryFile
, HashBlock
);
2166 CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile
,
2167 IN PKEY_BLOCK KeyBlock
,
2169 OUT PVALUE_BLOCK
*ValueBlock
)
2172 PVALUE_LIST_BLOCK ValueListBlock
;
2173 PVALUE_BLOCK CurValueBlock
;
2175 ValueListBlock
= CmiGetBlock(RegistryFile
,
2176 KeyBlock
->ValuesOffset
);
2178 if (ValueListBlock
== 0)
2180 return STATUS_SUCCESS
;
2182 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
2184 CurValueBlock
= CmiGetBlock(RegistryFile
,
2185 ValueListBlock
->Values
[Idx
]);
2186 if (CurValueBlock
!= NULL
&&
2187 !wcscmp(CurValueBlock
->Name
, ValueName
))
2189 *ValueBlock
= CurValueBlock
;
2192 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
2195 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2197 return STATUS_SUCCESS
;
2201 CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile
,
2202 IN PKEY_BLOCK KeyBlock
,
2203 IN PWSTR ValueNameBuf
,
2209 PVALUE_LIST_BLOCK ValueListBlock
, NewValueListBlock
;
2210 PVALUE_BLOCK ValueBlock
;
2212 Status
= CmiAllocateValueBlock(RegistryFile
,
2218 if (!NT_SUCCESS(Status
))
2222 ValueListBlock
= CmiGetBlock(RegistryFile
,
2223 KeyBlock
->ValuesOffset
);
2224 if (ValueListBlock
== NULL
)
2226 Status
= CmiAllocateBlock(RegistryFile
,
2227 (PVOID
) &ValueListBlock
,
2228 sizeof(BLOCK_OFFSET
) *
2229 REG_VALUE_LIST_BLOCK_MULTIPLE
);
2230 if (!NT_SUCCESS(Status
))
2232 CmiDestroyValueBlock(RegistryFile
,
2237 else if (KeyBlock
->NumberOfValues
% REG_VALUE_LIST_BLOCK_MULTIPLE
)
2239 Status
= CmiAllocateBlock(RegistryFile
,
2240 (PVOID
) &NewValueListBlock
,
2241 sizeof(BLOCK_OFFSET
) *
2242 (KeyBlock
->NumberOfValues
+
2243 REG_VALUE_LIST_BLOCK_MULTIPLE
));
2244 if (!NT_SUCCESS(Status
))
2246 CmiDestroyValueBlock(RegistryFile
,
2250 RtlCopyMemory(NewValueListBlock
,
2252 sizeof(BLOCK_OFFSET
) * KeyBlock
->NumberOfValues
);
2253 KeyBlock
->ValuesOffset
= CmiGetBlockOffset(RegistryFile
,
2255 CmiDestroyBlock(RegistryFile
, ValueListBlock
);
2256 ValueListBlock
= NewValueListBlock
;
2258 ValueListBlock
->Values
[KeyBlock
->NumberOfValues
] =
2259 CmiGetBlockOffset(RegistryFile
, ValueBlock
);
2260 KeyBlock
->NumberOfValues
++;
2261 CmiReleaseBlock(RegistryFile
, ValueBlock
);
2262 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2264 return STATUS_SUCCESS
;
2268 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile
,
2269 IN PKEY_BLOCK KeyBlock
,
2273 PVALUE_LIST_BLOCK ValueListBlock
;
2274 PVALUE_BLOCK CurValueBlock
;
2276 ValueListBlock
= CmiGetBlock(RegistryFile
,
2277 KeyBlock
->ValuesOffset
);
2278 if (ValueListBlock
== 0)
2280 return STATUS_SUCCESS
;
2282 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
2284 CurValueBlock
= CmiGetBlock(RegistryFile
,
2285 ValueListBlock
->Values
[Idx
]);
2286 if (CurValueBlock
!= NULL
&&
2287 !wcscmp(CurValueBlock
->Name
, ValueName
))
2289 if (KeyBlock
->NumberOfValues
- 1 < Idx
)
2291 RtlCopyMemory(&ValueListBlock
->Values
[Idx
],
2292 &ValueListBlock
->Values
[Idx
+ 1],
2293 sizeof(BLOCK_OFFSET
) *
2294 (KeyBlock
->NumberOfValues
- 1 - Idx
));
2298 RtlZeroMemory(&ValueListBlock
->Values
[Idx
],
2299 sizeof(BLOCK_OFFSET
));
2301 KeyBlock
->NumberOfValues
-= 1;
2302 CmiDestroyValueBlock(RegistryFile
, CurValueBlock
);
2306 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
2309 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2311 return STATUS_SUCCESS
;
2315 CmiAllocateKeyBlock(IN PREGISTRY_FILE RegistryFile
,
2316 OUT PKEY_BLOCK
*KeyBlock
,
2318 IN ULONG TitleIndex
,
2320 IN ULONG CreateOptions
)
2324 PKEY_BLOCK NewKeyBlock
;
2326 Status
= STATUS_SUCCESS
;
2328 /* Handle volatile files first */
2329 if (RegistryFile
->Filename
== NULL
)
2331 NewKeySize
= sizeof(KEY_BLOCK
) +
2332 (wcslen(KeyName
) + 1) * sizeof(WCHAR
) +
2333 (Class
!= NULL
? (wcslen(Class
) + 1) * sizeof(WCHAR
) : 0);
2334 NewKeyBlock
= ExAllocatePool(NonPagedPool
, NewKeySize
);
2335 if (NewKeyBlock
== NULL
)
2337 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2341 RtlZeroMemory(NewKeyBlock
, NewKeySize
);
2342 NewKeyBlock
->SubBlockId
= REG_KEY_BLOCK_ID
;
2343 NewKeyBlock
->Type
= REG_KEY_BLOCK_TYPE
;
2344 ZwQuerySystemTime((PTIME
) &NewKeyBlock
->LastWriteTime
);
2345 NewKeyBlock
->ParentKeyOffset
= 0;
2346 NewKeyBlock
->NumberOfSubKeys
= 0;
2347 NewKeyBlock
->HashTableOffset
= 0;
2348 NewKeyBlock
->NumberOfValues
= 0;
2349 NewKeyBlock
->ValuesOffset
= 0;
2350 NewKeyBlock
->SecurityKeyOffset
= 0;
2351 NewKeyBlock
->ClassNameOffset
= sizeof(KEY_BLOCK
) + wcslen(KeyName
);
2352 NewKeyBlock
->NameSize
= wcslen(KeyName
);
2353 NewKeyBlock
->ClassSize
= (Class
!= NULL
) ? wcslen(Class
) : 0;
2354 wcscpy(NewKeyBlock
->Name
, KeyName
);
2357 wcscpy(&NewKeyBlock
->Name
[wcslen(KeyName
) + 1], Class
);
2359 CmiLockBlock(RegistryFile
, NewKeyBlock
);
2360 *KeyBlock
= NewKeyBlock
;
2372 CmiGetKeyBlock(PREGISTRY_FILE RegistryFile
,
2373 BLOCK_OFFSET KeyBlockOffset
)
2375 PKEY_BLOCK KeyBlock
;
2377 if (RegistryFile
->Filename
== NULL
)
2379 CmiLockBlock(RegistryFile
, (PVOID
) KeyBlockOffset
);
2381 KeyBlock
= (PKEY_BLOCK
) KeyBlockOffset
;
2392 CmiDestroyKeyBlock(PREGISTRY_FILE RegistryFile
,
2393 PKEY_BLOCK KeyBlock
)
2397 Status
= STATUS_SUCCESS
;
2399 if (RegistryFile
->Filename
== NULL
)
2401 CmiReleaseBlock(RegistryFile
, KeyBlock
);
2402 ExFreePool(KeyBlock
);
2413 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile
,
2414 OUT PHASH_TABLE_BLOCK
*HashBlock
,
2415 IN ULONG HashTableSize
)
2419 PHASH_TABLE_BLOCK NewHashBlock
;
2421 Status
= STATUS_SUCCESS
;
2423 /* Handle volatile files first */
2424 if (RegistryFile
->Filename
== NULL
)
2426 NewHashSize
= sizeof(HASH_TABLE_BLOCK
) +
2427 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
2428 NewHashBlock
= ExAllocatePool(NonPagedPool
, NewHashSize
);
2429 if (NewHashBlock
== NULL
)
2431 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2435 RtlZeroMemory(NewHashBlock
, NewHashSize
);
2436 NewHashBlock
->SubBlockId
= REG_HASH_TABLE_BLOCK_ID
;
2437 NewHashBlock
->HashTableSize
= HashTableSize
;
2438 CmiLockBlock(RegistryFile
, NewHashBlock
);
2439 *HashBlock
= NewHashBlock
;
2450 static PHASH_TABLE_BLOCK
2451 CmiGetHashTableBlock(PREGISTRY_FILE RegistryFile
,
2452 BLOCK_OFFSET HashBlockOffset
)
2454 PHASH_TABLE_BLOCK HashBlock
;
2456 if (RegistryFile
->Filename
== NULL
)
2458 CmiLockBlock(RegistryFile
, (PVOID
) HashBlockOffset
);
2460 HashBlock
= (PHASH_TABLE_BLOCK
) HashBlockOffset
;
2471 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile
,
2472 PHASH_TABLE_BLOCK HashBlock
,
2475 PKEY_BLOCK KeyBlock
;
2477 if (RegistryFile
->Filename
== NULL
)
2479 KeyBlock
= (PKEY_BLOCK
) HashBlock
->Table
[Index
].KeyOffset
;
2480 CmiLockBlock(RegistryFile
, KeyBlock
);
2491 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile
,
2492 PHASH_TABLE_BLOCK HashBlock
,
2493 PKEY_BLOCK NewKeyBlock
)
2495 HashBlock
->Table
[HashBlock
->HashTableSize
].KeyOffset
=
2496 CmiGetBlockOffset(RegistryFile
, NewKeyBlock
);
2497 RtlCopyMemory(&HashBlock
->Table
[HashBlock
->HashTableSize
].HashValue
,
2500 HashBlock
->HashTableSize
++;
2502 return STATUS_SUCCESS
;
2506 CmiDestroyHashTableBlock(PREGISTRY_FILE RegistryFile
,
2507 PHASH_TABLE_BLOCK HashBlock
)
2511 Status
= STATUS_SUCCESS
;
2513 if (RegistryFile
->Filename
== NULL
)
2515 CmiReleaseBlock(RegistryFile
, HashBlock
);
2516 ExFreePool(HashBlock
);
2520 Status
= STATUS_NOT_IMPLEMENTED
;
2527 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile
,
2528 PVALUE_BLOCK
*ValueBlock
,
2529 IN PWSTR ValueNameBuf
,
2536 PVALUE_BLOCK NewValueBlock
;
2539 Status
= STATUS_SUCCESS
;
2541 /* Handle volatile files first */
2542 if (RegistryFile
->Filename
== NULL
)
2544 NewValueSize
= sizeof(VALUE_BLOCK
) + wcslen(ValueNameBuf
);
2545 NewValueBlock
= ExAllocatePool(NonPagedPool
, NewValueSize
);
2546 if (NewValueBlock
== NULL
)
2548 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2552 RtlZeroMemory(NewValueBlock
, NewValueSize
);
2553 NewValueBlock
->SubBlockId
= REG_VALUE_BLOCK_ID
;
2554 NewValueBlock
->NameSize
= wcslen(ValueNameBuf
);
2555 wcscpy(NewValueBlock
->Name
, ValueNameBuf
);
2556 NewValueBlock
->DataType
= Type
;
2557 NewValueBlock
->DataSize
= DataSize
;
2558 Status
= CmiAllocateBlock(RegistryFile
,
2561 if (!NT_SUCCESS(Status
))
2563 ExFreePool(NewValueBlock
);
2567 RtlCopyMemory(DataBlock
, Data
, DataSize
);
2568 NewValueBlock
->DataOffset
= CmiGetBlockOffset(RegistryFile
,
2570 CmiLockBlock(RegistryFile
, NewValueBlock
);
2571 CmiReleaseBlock(RegistryFile
, DataBlock
);
2572 *ValueBlock
= NewValueBlock
;
2578 Status
= STATUS_NOT_IMPLEMENTED
;
2585 CmiReplaceValueData(IN PREGISTRY_FILE RegistryFile
,
2586 IN PVALUE_BLOCK ValueBlock
,
2592 PVOID DataBlock
, NewDataBlock
;
2594 Status
= STATUS_SUCCESS
;
2596 /* If new data size is <= current then overwrite current data */
2597 if (DataSize
<= ValueBlock
->DataSize
)
2599 DataBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
);
2600 RtlCopyMemory(DataBlock
, Data
, DataSize
);
2601 ValueBlock
->DataSize
= DataSize
;
2602 ValueBlock
->DataType
= Type
;
2603 CmiReleaseBlock(RegistryFile
, DataBlock
);
2607 /* Destroy current data block and allocate a new one */
2608 DataBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
);
2609 Status
= CmiAllocateBlock(RegistryFile
,
2612 RtlCopyMemory(NewDataBlock
, Data
, DataSize
);
2613 ValueBlock
->DataOffset
= CmiGetBlockOffset(RegistryFile
, DataBlock
);
2614 ValueBlock
->DataSize
= DataSize
;
2615 ValueBlock
->DataType
= Type
;
2616 CmiReleaseBlock(RegistryFile
, NewDataBlock
);
2617 CmiDestroyBlock(RegistryFile
, DataBlock
);
2624 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile
,
2625 PVALUE_BLOCK ValueBlock
)
2629 Status
= CmiDestroyBlock(RegistryFile
,
2630 CmiGetBlock(RegistryFile
,
2631 ValueBlock
->DataOffset
));
2632 if (!NT_SUCCESS(Status
))
2636 return CmiDestroyBlock(RegistryFile
, ValueBlock
);
2640 CmiAllocateBlock(PREGISTRY_FILE RegistryFile
,
2647 Status
= STATUS_SUCCESS
;
2649 /* Handle volatile files first */
2650 if (RegistryFile
->Filename
== NULL
)
2652 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
2653 if (NewBlock
== NULL
)
2655 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2659 RtlZeroMemory(NewBlock
, BlockSize
);
2660 CmiLockBlock(RegistryFile
, NewBlock
);
2666 Status
= STATUS_NOT_IMPLEMENTED
;
2673 CmiDestroyBlock(PREGISTRY_FILE RegistryFile
,
2678 Status
= STATUS_SUCCESS
;
2680 if (RegistryFile
->Filename
== NULL
)
2682 CmiReleaseBlock(RegistryFile
, Block
);
2687 Status
= STATUS_NOT_IMPLEMENTED
;
2694 CmiGetBlock(PREGISTRY_FILE RegistryFile
,
2695 BLOCK_OFFSET BlockOffset
)
2700 if (RegistryFile
->Filename
== NULL
)
2702 CmiLockBlock(RegistryFile
, (PVOID
) BlockOffset
);
2704 Block
= (PVOID
) BlockOffset
;
2715 CmiGetBlockOffset(PREGISTRY_FILE RegistryFile
,
2718 BLOCK_OFFSET BlockOffset
;
2720 if (RegistryFile
->Filename
== NULL
)
2722 BlockOffset
= (BLOCK_OFFSET
) Block
;
2733 CmiLockBlock(PREGISTRY_FILE RegistryFile
,
2736 if (RegistryFile
->Filename
!= NULL
)
2743 CmiReleaseBlock(PREGISTRY_FILE RegistryFile
,
2746 if (RegistryFile
->Filename
!= NULL
)