1 /* $Id: registry.c,v 1.25 2000/08/11 12:39:25 ekohl 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"\\SystemRoot\\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
1233 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1235 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
1245 IN HANDLE KeyHandle
,
1246 IN HANDLE FileHandle
,
1247 IN ULONG RestoreFlags
1257 IN HANDLE KeyHandle
,
1258 IN HANDLE FileHandle
1267 NtSetInformationKey (
1268 IN HANDLE KeyHandle
,
1269 IN CINT KeyInformationClass
,
1270 IN PVOID KeyInformation
,
1271 IN ULONG KeyInformationLength
1290 NtInitializeRegistry (
1300 RtlCheckRegistryKey (
1301 IN ULONG RelativeTo
,
1311 RtlCreateRegistryKey (
1312 IN ULONG RelativeTo
,
1322 RtlDeleteRegistryValue (
1323 IN ULONG RelativeTo
,
1334 RtlQueryRegistryValues (
1335 IN ULONG RelativeTo
,
1337 IN PRTL_QUERY_REGISTRY_TABLE QueryTable
,
1339 IN PVOID Environment
1348 RtlWriteRegistryValue (
1349 IN ULONG RelativeTo
,
1354 IN ULONG ValueLength
1360 /* ------------------------------------------ Private Implementation */
1365 //CmiObjectParse(PVOID ParsedObject, PWSTR *Path)
1366 static NTSTATUS
CmiObjectParse(PVOID ParsedObject
,
1368 PUNICODE_STRING FullPath
,
1372 /* FIXME: this should be allocated based on the largest subkey name */
1373 WCHAR CurKeyName
[260];
1374 PWSTR Remainder
, NextSlash
;
1375 PREGISTRY_FILE RegistryFile
;
1376 PKEY_OBJECT NewKeyObject
;
1378 PKEY_BLOCK CurKeyBlock
, SubKeyBlock
;
1380 Status
= STATUS_SUCCESS
;
1382 /* FIXME: it should probably get this from ParsedObject */
1383 RegistryFile
= CmiVolatileFile
;
1385 /* Scan key object list for key already open */
1386 NewKeyObject
= CmiScanKeyList((*Path
) + 1);
1387 if (NewKeyObject
!= NULL
)
1389 /* Return reference if found */
1390 ObReferenceObjectByPointer(NewKeyObject
,
1391 STANDARD_RIGHTS_REQUIRED
,
1396 // return NewKeyObject;
1401 CurKeyBlock
= CmiGetKeyBlock(RegistryFile
,
1402 RegistryFile
->HeaderBlock
->RootKeyBlock
);
1404 /* Loop through each key level and find the needed subkey */
1405 Remainder
= (*Path
) + 1;
1406 while (NT_SUCCESS(Status
) && *Remainder
!= 0)
1408 NextSlash
= wcschr(Remainder
, L
'\\');
1410 /* Copy just the current subkey name to a buffer */
1411 if (NextSlash
!= NULL
)
1413 wcsncpy(CurKeyName
, Remainder
, NextSlash
- Remainder
);
1414 CurKeyName
[NextSlash
- Remainder
] = 0;
1418 wcscpy(CurKeyName
, Remainder
);
1421 /* Verify existance of CurKeyName */
1422 Status
= CmiScanForSubKey(RegistryFile
,
1426 STANDARD_RIGHTS_REQUIRED
);
1427 if (!NT_SUCCESS(Status
))
1431 if (SubKeyBlock
== NULL
)
1433 Status
= STATUS_UNSUCCESSFUL
;
1436 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1437 CurKeyBlock
= SubKeyBlock
;
1439 if (NextSlash
!= NULL
)
1441 Remainder
= NextSlash
+ 1;
1449 /* Create new key object and put into linked list */
1450 NewKeyObject
= ObCreateObject(&KeyHandle
,
1451 STANDARD_RIGHTS_REQUIRED
,
1454 if (NewKeyObject
== NULL
)
1456 //FIXME : return the good error code
1457 return STATUS_UNSUCCESSFUL
;
1459 NewKeyObject
->Flags
= 0;
1460 NewKeyObject
->Name
= ExAllocatePool(NonPagedPool
,
1461 wcslen(*Path
) * sizeof(WCHAR
));
1462 wcscpy(NewKeyObject
->Name
, (*Path
) + 1);
1463 NewKeyObject
->KeyBlock
= CurKeyBlock
;
1464 NewKeyObject
->RegistryFile
= RegistryFile
;
1465 CmiAddKeyToList(NewKeyObject
);
1466 *Path
= (Remainder
!= NULL
) ? Remainder
- 1 : NULL
;
1468 NextObject
= (PVOID
)NewKeyObject
;
1469 return STATUS_SUCCESS
;
1473 CmiObjectDelete(PVOID DeletedObject
)
1475 PKEY_OBJECT KeyObject
;
1477 KeyObject
= (PKEY_OBJECT
) DeletedObject
;
1478 if (KeyObject
->Flags
& KO_MARKED_FOR_DELETE
)
1480 CmiDestroyKeyBlock(KeyObject
->RegistryFile
,
1481 KeyObject
->KeyBlock
);
1485 CmiReleaseBlock(KeyObject
->RegistryFile
,
1486 KeyObject
->KeyBlock
);
1488 ExFreePool(KeyObject
->Name
);
1489 CmiRemoveKeyFromList(KeyObject
);
1493 CmiBuildKeyPath(PWSTR
*KeyPath
, POBJECT_ATTRIBUTES ObjectAttributes
)
1499 PKEY_OBJECT KeyObject
;
1500 POBJECT_HEADER ObjectHeader
;
1502 /* FIXME: Verify ObjectAttributes is in \\Registry space and compute size for path */
1505 if (ObjectAttributes
->RootDirectory
!= NULL
)
1507 /* FIXME: determine type of object for RootDirectory */
1508 Status
= ObReferenceObjectByHandle(ObjectAttributes
->RootDirectory
,
1512 (PVOID
*)&ObjectBody
,
1514 if (!NT_SUCCESS(Status
))
1518 ObjectHeader
= BODY_TO_HEADER(ObjectBody
);
1520 if (ObjectHeader
->ObjectType
!= CmiKeyType
)
1522 /* Fail if RootDirectory != '\\' */
1523 if (ObjectBody
== NameSpaceRoot
)
1525 /* Check for 'Registry' in ObjectName, fail if missing */
1526 if (wcsncmp(ObjectAttributes
->ObjectName
->Buffer
,
1527 REG_ROOT_KEY_NAME
+ 1,
1528 wcslen(REG_ROOT_KEY_NAME
+ 1)) != 0 ||
1529 ObjectAttributes
->ObjectName
->Buffer
[wcslen(REG_ROOT_KEY_NAME
+ 1)] != L
'\\')
1531 ObDereferenceObject(ObjectBody
);
1533 return STATUS_OBJECT_PATH_INVALID
;
1536 /* Compute size of registry portion of path to KeyNameSize */
1537 KeyNameSize
= (ObjectAttributes
->ObjectName
->Length
-
1538 (wcslen(REG_ROOT_KEY_NAME
+ 1) + 1))
1541 else if (!wcscmp(ObjectHeader
->Name
.Buffer
,
1542 REG_ROOT_KEY_NAME
+ 1))
1544 /* Add size of ObjectName to KeyNameSize */
1545 KeyNameSize
= ObjectAttributes
->ObjectName
->Length
;
1549 ObDereferenceObject(ObjectBody
);
1551 return STATUS_OBJECT_PATH_INVALID
;
1556 KeyObject
= (PKEY_OBJECT
) ObjectBody
;
1558 /* Add size of Name from RootDirectory object to KeyNameSize */
1559 KeyNameSize
= wcslen(KeyObject
->Name
) * sizeof(WCHAR
);
1561 /* Add 1 to KeyNamesize for '\\' */
1562 KeyNameSize
+= sizeof(WCHAR
);
1564 /* Add size of ObjectName to KeyNameSize */
1565 KeyNameSize
+= ObjectAttributes
->ObjectName
->Length
* sizeof(WCHAR
);
1570 /* Check for \\Registry and fail if missing */
1571 if (wcsncmp(ObjectAttributes
->ObjectName
->Buffer
,
1573 wcslen(REG_ROOT_KEY_NAME
)) != 0 ||
1574 ObjectAttributes
->ObjectName
->Buffer
[wcslen(REG_ROOT_KEY_NAME
)] != L
'\\')
1576 return STATUS_OBJECT_PATH_INVALID
;
1579 /* Compute size of registry portion of path to KeyNameSize */
1580 KeyNameSize
= (ObjectAttributes
->ObjectName
->Length
-
1581 (wcslen(REG_ROOT_KEY_NAME
) + 1)) * sizeof(WCHAR
);
1584 KeyNameBuf
= ExAllocatePool(NonPagedPool
, KeyNameSize
+ sizeof(WCHAR
));
1586 /* Construct relative pathname */
1588 if (ObjectAttributes
->RootDirectory
!= NULL
)
1590 if (ObjectHeader
->ObjectType
!= CmiKeyType
)
1592 /* Fail if RootDirectory != '\\' */
1593 if (ObjectBody
== NameSpaceRoot
)
1595 /* Copy remainder of ObjectName after 'Registry' */
1596 wcscpy(KeyNameBuf
, ObjectAttributes
->ObjectName
->Buffer
+ wcslen(REG_ROOT_KEY_NAME
+ 1));
1600 /* Copy all of ObjectName */
1601 wcscpy(KeyNameBuf
, ObjectAttributes
->ObjectName
->Buffer
);
1606 KeyObject
= (PKEY_OBJECT
) ObjectBody
;
1608 /* Copy Name from RootDirectory object to KeyNameBuf */
1609 wcscpy(KeyNameBuf
, KeyObject
->Name
);
1611 /* Append '\\' onto KeyNameBuf */
1612 wcscat(KeyNameBuf
, L
"\\");
1614 /* Append ObjectName onto KeyNameBuf */
1615 wcscat(KeyNameBuf
, ObjectAttributes
->ObjectName
->Buffer
);
1620 /* Copy registry portion of path into KeyNameBuf */
1621 wcscpy(KeyNameBuf
, ObjectAttributes
->ObjectName
->Buffer
+
1622 (wcslen(REG_ROOT_KEY_NAME
) + 1));
1625 *KeyPath
= KeyNameBuf
;
1626 return STATUS_SUCCESS
;
1630 CmiAddKeyToList(PKEY_OBJECT NewKey
)
1634 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
1635 NewKey
->NextKey
= CmiKeyList
;
1636 CmiKeyList
= NewKey
;
1637 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
1641 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove
)
1646 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
1647 if (CmiKeyList
== KeyToRemove
)
1649 CmiKeyList
= CmiKeyList
->NextKey
;
1653 CurKey
= CmiKeyList
;
1654 while (CurKey
!= NULL
&& CurKey
->NextKey
!= KeyToRemove
)
1656 CurKey
= CurKey
->NextKey
;
1660 CurKey
->NextKey
= KeyToRemove
->NextKey
;
1663 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
1667 CmiScanKeyList(PWSTR KeyName
)
1672 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
1673 CurKey
= CmiKeyList
;
1674 while (CurKey
!= NULL
&& wcscmp(KeyName
, CurKey
->Name
) != 0)
1676 CurKey
= CurKey
->NextKey
;
1678 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
1683 static PREGISTRY_FILE
1684 CmiCreateRegistry(PWSTR Filename
)
1686 PREGISTRY_FILE RegistryFile
;
1687 PKEY_BLOCK RootKeyBlock
;
1689 RegistryFile
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_FILE
));
1690 if (Filename
!= NULL
)
1693 /* FIXME: Duplicate Filename */
1694 /* FIXME: if file does not exist, create new file */
1695 /* FIXME: else attempt to map the file */
1699 RegistryFile
->Filename
= NULL
;
1700 RegistryFile
->FileHandle
= NULL
;
1702 RegistryFile
->HeaderBlock
= (PHEADER_BLOCK
)
1703 ExAllocatePool(NonPagedPool
, sizeof(HEADER_BLOCK
));
1704 RtlZeroMemory(RegistryFile
->HeaderBlock
, sizeof(HEADER_BLOCK
));
1705 RegistryFile
->HeaderBlock
->BlockId
= 0x66676572;
1706 RegistryFile
->HeaderBlock
->DateModified
.QuadPart
= 0;
1707 RegistryFile
->HeaderBlock
->Unused2
= 1;
1708 RegistryFile
->HeaderBlock
->Unused3
= 3;
1709 RegistryFile
->HeaderBlock
->Unused5
= 1;
1710 RegistryFile
->HeaderBlock
->RootKeyBlock
= 0;
1711 RegistryFile
->HeaderBlock
->BlockSize
= REG_BLOCK_SIZE
;
1712 RegistryFile
->HeaderBlock
->Unused6
= 1;
1713 RegistryFile
->HeaderBlock
->Checksum
= 0;
1714 RootKeyBlock
= (PKEY_BLOCK
)
1715 ExAllocatePool(NonPagedPool
, sizeof(KEY_BLOCK
));
1716 RtlZeroMemory(RootKeyBlock
, sizeof(KEY_BLOCK
));
1717 RootKeyBlock
->SubBlockId
= REG_KEY_BLOCK_ID
;
1718 RootKeyBlock
->Type
= REG_ROOT_KEY_BLOCK_TYPE
;
1719 ZwQuerySystemTime((PTIME
) &RootKeyBlock
->LastWriteTime
);
1720 RootKeyBlock
->ParentKeyOffset
= 0;
1721 RootKeyBlock
->NumberOfSubKeys
= 0;
1722 RootKeyBlock
->HashTableOffset
= 0;
1723 RootKeyBlock
->NumberOfValues
= 0;
1724 RootKeyBlock
->ValuesOffset
= 0;
1725 RootKeyBlock
->SecurityKeyOffset
= 0;
1726 RootKeyBlock
->ClassNameOffset
= sizeof(KEY_BLOCK
);
1727 RootKeyBlock
->NameSize
= 0;
1728 RootKeyBlock
->ClassSize
= 0;
1729 RootKeyBlock
->Name
[0] = 0;
1730 RegistryFile
->HeaderBlock
->RootKeyBlock
= (BLOCK_OFFSET
) RootKeyBlock
;
1733 return RegistryFile
;
1737 CmiCreateKey(IN PREGISTRY_FILE RegistryFile
,
1738 IN PWSTR KeyNameBuf
,
1739 OUT PKEY_BLOCK
*KeyBlock
,
1740 IN ACCESS_MASK DesiredAccess
,
1741 IN ULONG TitleIndex
,
1742 IN PUNICODE_STRING Class
,
1743 IN ULONG CreateOptions
,
1744 OUT PULONG Disposition
)
1746 /* FIXME: this should be allocated based on the largest subkey name */
1748 WCHAR CurKeyName
[256];
1750 PWSTR Remainder
, NextSlash
;
1751 PKEY_BLOCK CurKeyBlock
, SubKeyBlock
;
1753 /* FIXME: Should handle search by Class/TitleIndex */
1756 /* Loop through each key level and find or build the needed subkey */
1757 Status
= STATUS_SUCCESS
;
1758 /* FIXME: this access of RootKeyBlock should be guarded by spinlock */
1759 CurKeyBlock
= CmiGetKeyBlock(RegistryFile
,
1760 RegistryFile
->HeaderBlock
->RootKeyBlock
);
1762 Remainder
= KeyNameBuf
;
1763 while (NT_SUCCESS(Status
) &&
1764 (NextSlash
= wcschr(Remainder
, L
'\\')) != NULL
)
1766 /* Copy just the current subkey name to a buffer */
1767 wcsncpy(CurKeyName
, Remainder
, NextSlash
- Remainder
);
1768 CurKeyName
[NextSlash
- Remainder
] = 0;
1770 /* Verify existance of/Create CurKeyName */
1772 Status
= CmiScanForSubKey(RegistryFile
,
1777 if (!NT_SUCCESS(Status
))
1781 if (SubKeyBlock
== NULL
)
1783 Status
= CmiAddSubKey(RegistryFile
,
1790 if (!NT_SUCCESS(Status
))
1795 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1796 CurKeyBlock
= SubKeyBlock
;
1798 Remainder
= NextSlash
+ 1;
1801 if (NT_SUCCESS(Status
))
1804 Status
= CmiScanForSubKey(RegistryFile
,
1809 if (NT_SUCCESS(Status
))
1811 if (SubKeyBlock
== NULL
)
1815 ClassName
= ExAllocatePool(NonPagedPool
, Class
->Length
+ 1);
1816 wcsncpy(ClassName
, Class
->Buffer
, Class
->Length
);
1817 ClassName
[Class
->Length
] = 0;
1823 Status
= CmiAddSubKey(RegistryFile
,
1830 if (ClassName
!= NULL
)
1832 ExFreePool(ClassName
);
1834 if (NT_SUCCESS(Status
) && Disposition
!= NULL
)
1836 *Disposition
= REG_CREATED_NEW_KEY
;
1839 else if (Disposition
!= NULL
)
1841 *Disposition
= REG_OPENED_EXISTING_KEY
;
1844 *KeyBlock
= SubKeyBlock
;
1846 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1852 CmiFindKey(IN PREGISTRY_FILE RegistryFile
,
1853 IN PWSTR KeyNameBuf
,
1854 OUT PKEY_BLOCK
*KeyBlock
,
1855 IN ACCESS_MASK DesiredAccess
,
1856 IN ULONG TitleIndex
,
1857 IN PUNICODE_STRING Class
)
1859 /* FIXME: this should be allocated based on the largest subkey name */
1861 WCHAR CurKeyName
[256];
1862 PWSTR Remainder
, NextSlash
;
1863 PKEY_BLOCK CurKeyBlock
, SubKeyBlock
;
1865 /* FIXME: Should handle search by Class/TitleIndex */
1867 /* Loop through each key level and find the needed subkey */
1868 Status
= STATUS_SUCCESS
;
1869 /* FIXME: this access of RootKeyBlock should be guarded by spinlock */
1870 CurKeyBlock
= CmiGetKeyBlock(RegistryFile
, RegistryFile
->HeaderBlock
->RootKeyBlock
);
1871 Remainder
= KeyNameBuf
;
1872 while (NT_SUCCESS(Status
) &&
1873 (NextSlash
= wcschr(Remainder
, L
'\\')) != NULL
)
1875 /* Copy just the current subkey name to a buffer */
1876 wcsncpy(CurKeyName
, Remainder
, NextSlash
- Remainder
);
1877 CurKeyName
[NextSlash
- Remainder
] = 0;
1879 /* Verify existance of CurKeyName */
1880 Status
= CmiScanForSubKey(RegistryFile
,
1885 if (!NT_SUCCESS(Status
))
1889 if (SubKeyBlock
== NULL
)
1891 Status
= STATUS_UNSUCCESSFUL
;
1894 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1895 CurKeyBlock
= SubKeyBlock
;
1897 Remainder
= NextSlash
+ 1;
1899 if (NT_SUCCESS(Status
))
1901 Status
= CmiScanForSubKey(RegistryFile
,
1906 if (NT_SUCCESS(Status
))
1908 if (SubKeyBlock
== NULL
)
1910 Status
= STATUS_UNSUCCESSFUL
;
1914 *KeyBlock
= SubKeyBlock
;
1918 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1924 CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile
,
1925 PKEY_BLOCK KeyBlock
)
1928 PHASH_TABLE_BLOCK HashBlock
;
1929 PKEY_BLOCK CurSubKeyBlock
;
1932 HashBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
1937 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
1939 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0)
1941 CurSubKeyBlock
= CmiGetKeyBlock(RegistryFile
,
1942 HashBlock
->Table
[Idx
].KeyOffset
);
1943 if (MaxName
< CurSubKeyBlock
->NameSize
)
1945 MaxName
= CurSubKeyBlock
->NameSize
;
1947 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
1951 CmiReleaseBlock(RegistryFile
, HashBlock
);
1957 CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile
,
1958 PKEY_BLOCK KeyBlock
)
1960 ULONG Idx
, MaxClass
;
1961 PHASH_TABLE_BLOCK HashBlock
;
1962 PKEY_BLOCK CurSubKeyBlock
;
1965 HashBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
1970 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
1972 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0)
1974 CurSubKeyBlock
= CmiGetKeyBlock(RegistryFile
,
1975 HashBlock
->Table
[Idx
].KeyOffset
);
1976 if (MaxClass
< CurSubKeyBlock
->ClassSize
)
1978 MaxClass
= CurSubKeyBlock
->ClassSize
;
1980 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
1984 CmiReleaseBlock(RegistryFile
, HashBlock
);
1990 CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile
,
1991 PKEY_BLOCK KeyBlock
)
1993 ULONG Idx
, MaxValueName
;
1994 PVALUE_LIST_BLOCK ValueListBlock
;
1995 PVALUE_BLOCK CurValueBlock
;
1997 ValueListBlock
= CmiGetBlock(RegistryFile
,
1998 KeyBlock
->ValuesOffset
);
2000 if (ValueListBlock
== 0)
2004 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
2006 CurValueBlock
= CmiGetBlock(RegistryFile
,
2007 ValueListBlock
->Values
[Idx
]);
2008 if (CurValueBlock
!= NULL
&&
2009 MaxValueName
< CurValueBlock
->NameSize
)
2011 MaxValueName
= CurValueBlock
->NameSize
;
2013 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
2016 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2018 return MaxValueName
;
2022 CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile
,
2023 PKEY_BLOCK KeyBlock
)
2025 ULONG Idx
, MaxValueData
;
2026 PVALUE_LIST_BLOCK ValueListBlock
;
2027 PVALUE_BLOCK CurValueBlock
;
2029 ValueListBlock
= CmiGetBlock(RegistryFile
,
2030 KeyBlock
->ValuesOffset
);
2032 if (ValueListBlock
== 0)
2036 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
2038 CurValueBlock
= CmiGetBlock(RegistryFile
,
2039 ValueListBlock
->Values
[Idx
]);
2040 if (CurValueBlock
!= NULL
&&
2041 MaxValueData
< CurValueBlock
->DataSize
)
2043 MaxValueData
= CurValueBlock
->DataSize
;
2045 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
2048 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2050 return MaxValueData
;
2054 CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile
,
2055 IN PKEY_BLOCK KeyBlock
,
2056 OUT PKEY_BLOCK
*SubKeyBlock
,
2058 IN ACCESS_MASK DesiredAccess
)
2061 PHASH_TABLE_BLOCK HashBlock
;
2062 PKEY_BLOCK CurSubKeyBlock
;
2064 HashBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
2065 *SubKeyBlock
= NULL
;
2068 return STATUS_SUCCESS
;
2070 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
2072 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0 &&
2073 !wcsncmp(KeyName
, (PWSTR
) &HashBlock
->Table
[Idx
].HashValue
, 4))
2075 CurSubKeyBlock
= CmiGetKeyBlock(RegistryFile
,
2076 HashBlock
->Table
[Idx
].KeyOffset
);
2077 if (!wcscmp(KeyName
, CurSubKeyBlock
->Name
))
2079 *SubKeyBlock
= CurSubKeyBlock
;
2084 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
2089 CmiReleaseBlock(RegistryFile
, HashBlock
);
2091 return STATUS_SUCCESS
;
2095 CmiAddSubKey(PREGISTRY_FILE RegistryFile
,
2096 PKEY_BLOCK KeyBlock
,
2097 PKEY_BLOCK
*SubKeyBlock
,
2098 PWSTR NewSubKeyName
,
2101 ULONG CreateOptions
)
2104 PHASH_TABLE_BLOCK HashBlock
, NewHashBlock
;
2105 PKEY_BLOCK NewKeyBlock
;
2107 Status
= CmiAllocateKeyBlock(RegistryFile
,
2113 if (!NT_SUCCESS(Status
))
2117 if (KeyBlock
->HashTableOffset
== 0)
2119 Status
= CmiAllocateHashTableBlock(RegistryFile
,
2121 REG_INIT_HASH_TABLE_SIZE
);
2122 if (!NT_SUCCESS(Status
))
2126 KeyBlock
->HashTableOffset
= CmiGetBlockOffset(RegistryFile
, HashBlock
);
2130 HashBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
2131 if (KeyBlock
->NumberOfSubKeys
+ 1 >= HashBlock
->HashTableSize
)
2134 /* FIXME: All Subkeys will need to be rehashed here! */
2136 /* Reallocate the hash table block */
2137 Status
= CmiAllocateHashTableBlock(RegistryFile
,
2139 HashBlock
->HashTableSize
+
2140 REG_EXTEND_HASH_TABLE_SIZE
);
2141 if (!NT_SUCCESS(Status
))
2145 RtlZeroMemory(&NewHashBlock
->Table
[0],
2146 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2147 RtlCopyMemory(&NewHashBlock
->Table
[0],
2148 &HashBlock
->Table
[0],
2149 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2150 KeyBlock
->HashTableOffset
= CmiGetBlockOffset(RegistryFile
, NewHashBlock
);
2151 CmiDestroyHashTableBlock(RegistryFile
, HashBlock
);
2152 HashBlock
= NewHashBlock
;
2155 Status
= CmiAddKeyToHashTable(RegistryFile
, HashBlock
, NewKeyBlock
);
2156 if (NT_SUCCESS(Status
))
2158 KeyBlock
->NumberOfSubKeys
++;
2159 *SubKeyBlock
= NewKeyBlock
;
2161 CmiReleaseBlock(RegistryFile
, HashBlock
);
2167 CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile
,
2168 IN PKEY_BLOCK KeyBlock
,
2170 OUT PVALUE_BLOCK
*ValueBlock
)
2173 PVALUE_LIST_BLOCK ValueListBlock
;
2174 PVALUE_BLOCK CurValueBlock
;
2176 ValueListBlock
= CmiGetBlock(RegistryFile
,
2177 KeyBlock
->ValuesOffset
);
2179 if (ValueListBlock
== 0)
2181 return STATUS_SUCCESS
;
2183 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
2185 CurValueBlock
= CmiGetBlock(RegistryFile
,
2186 ValueListBlock
->Values
[Idx
]);
2187 if (CurValueBlock
!= NULL
&&
2188 !wcscmp(CurValueBlock
->Name
, ValueName
))
2190 *ValueBlock
= CurValueBlock
;
2193 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
2196 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2198 return STATUS_SUCCESS
;
2202 CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile
,
2203 IN PKEY_BLOCK KeyBlock
,
2204 IN PWSTR ValueNameBuf
,
2210 PVALUE_LIST_BLOCK ValueListBlock
, NewValueListBlock
;
2211 PVALUE_BLOCK ValueBlock
;
2213 Status
= CmiAllocateValueBlock(RegistryFile
,
2219 if (!NT_SUCCESS(Status
))
2223 ValueListBlock
= CmiGetBlock(RegistryFile
,
2224 KeyBlock
->ValuesOffset
);
2225 if (ValueListBlock
== NULL
)
2227 Status
= CmiAllocateBlock(RegistryFile
,
2228 (PVOID
) &ValueListBlock
,
2229 sizeof(BLOCK_OFFSET
) *
2230 REG_VALUE_LIST_BLOCK_MULTIPLE
);
2231 if (!NT_SUCCESS(Status
))
2233 CmiDestroyValueBlock(RegistryFile
,
2238 else if (KeyBlock
->NumberOfValues
% REG_VALUE_LIST_BLOCK_MULTIPLE
)
2240 Status
= CmiAllocateBlock(RegistryFile
,
2241 (PVOID
) &NewValueListBlock
,
2242 sizeof(BLOCK_OFFSET
) *
2243 (KeyBlock
->NumberOfValues
+
2244 REG_VALUE_LIST_BLOCK_MULTIPLE
));
2245 if (!NT_SUCCESS(Status
))
2247 CmiDestroyValueBlock(RegistryFile
,
2251 RtlCopyMemory(NewValueListBlock
,
2253 sizeof(BLOCK_OFFSET
) * KeyBlock
->NumberOfValues
);
2254 KeyBlock
->ValuesOffset
= CmiGetBlockOffset(RegistryFile
,
2256 CmiDestroyBlock(RegistryFile
, ValueListBlock
);
2257 ValueListBlock
= NewValueListBlock
;
2259 ValueListBlock
->Values
[KeyBlock
->NumberOfValues
] =
2260 CmiGetBlockOffset(RegistryFile
, ValueBlock
);
2261 KeyBlock
->NumberOfValues
++;
2262 CmiReleaseBlock(RegistryFile
, ValueBlock
);
2263 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2265 return STATUS_SUCCESS
;
2269 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile
,
2270 IN PKEY_BLOCK KeyBlock
,
2274 PVALUE_LIST_BLOCK ValueListBlock
;
2275 PVALUE_BLOCK CurValueBlock
;
2277 ValueListBlock
= CmiGetBlock(RegistryFile
,
2278 KeyBlock
->ValuesOffset
);
2279 if (ValueListBlock
== 0)
2281 return STATUS_SUCCESS
;
2283 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
2285 CurValueBlock
= CmiGetBlock(RegistryFile
,
2286 ValueListBlock
->Values
[Idx
]);
2287 if (CurValueBlock
!= NULL
&&
2288 !wcscmp(CurValueBlock
->Name
, ValueName
))
2290 if (KeyBlock
->NumberOfValues
- 1 < Idx
)
2292 RtlCopyMemory(&ValueListBlock
->Values
[Idx
],
2293 &ValueListBlock
->Values
[Idx
+ 1],
2294 sizeof(BLOCK_OFFSET
) *
2295 (KeyBlock
->NumberOfValues
- 1 - Idx
));
2299 RtlZeroMemory(&ValueListBlock
->Values
[Idx
],
2300 sizeof(BLOCK_OFFSET
));
2302 KeyBlock
->NumberOfValues
-= 1;
2303 CmiDestroyValueBlock(RegistryFile
, CurValueBlock
);
2307 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
2310 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2312 return STATUS_SUCCESS
;
2316 CmiAllocateKeyBlock(IN PREGISTRY_FILE RegistryFile
,
2317 OUT PKEY_BLOCK
*KeyBlock
,
2319 IN ULONG TitleIndex
,
2321 IN ULONG CreateOptions
)
2325 PKEY_BLOCK NewKeyBlock
;
2327 Status
= STATUS_SUCCESS
;
2329 /* Handle volatile files first */
2330 if (RegistryFile
->Filename
== NULL
)
2332 NewKeySize
= sizeof(KEY_BLOCK
) +
2333 (wcslen(KeyName
) + 1) * sizeof(WCHAR
) +
2334 (Class
!= NULL
? (wcslen(Class
) + 1) * sizeof(WCHAR
) : 0);
2335 NewKeyBlock
= ExAllocatePool(NonPagedPool
, NewKeySize
);
2336 if (NewKeyBlock
== NULL
)
2338 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2342 RtlZeroMemory(NewKeyBlock
, NewKeySize
);
2343 NewKeyBlock
->SubBlockId
= REG_KEY_BLOCK_ID
;
2344 NewKeyBlock
->Type
= REG_KEY_BLOCK_TYPE
;
2345 ZwQuerySystemTime((PTIME
) &NewKeyBlock
->LastWriteTime
);
2346 NewKeyBlock
->ParentKeyOffset
= 0;
2347 NewKeyBlock
->NumberOfSubKeys
= 0;
2348 NewKeyBlock
->HashTableOffset
= 0;
2349 NewKeyBlock
->NumberOfValues
= 0;
2350 NewKeyBlock
->ValuesOffset
= 0;
2351 NewKeyBlock
->SecurityKeyOffset
= 0;
2352 NewKeyBlock
->ClassNameOffset
= sizeof(KEY_BLOCK
) + wcslen(KeyName
);
2353 NewKeyBlock
->NameSize
= wcslen(KeyName
);
2354 NewKeyBlock
->ClassSize
= (Class
!= NULL
) ? wcslen(Class
) : 0;
2355 wcscpy(NewKeyBlock
->Name
, KeyName
);
2358 wcscpy(&NewKeyBlock
->Name
[wcslen(KeyName
) + 1], Class
);
2360 CmiLockBlock(RegistryFile
, NewKeyBlock
);
2361 *KeyBlock
= NewKeyBlock
;
2373 CmiGetKeyBlock(PREGISTRY_FILE RegistryFile
,
2374 BLOCK_OFFSET KeyBlockOffset
)
2376 PKEY_BLOCK KeyBlock
;
2378 if (RegistryFile
->Filename
== NULL
)
2380 CmiLockBlock(RegistryFile
, (PVOID
) KeyBlockOffset
);
2382 KeyBlock
= (PKEY_BLOCK
) KeyBlockOffset
;
2393 CmiDestroyKeyBlock(PREGISTRY_FILE RegistryFile
,
2394 PKEY_BLOCK KeyBlock
)
2398 Status
= STATUS_SUCCESS
;
2400 if (RegistryFile
->Filename
== NULL
)
2402 CmiReleaseBlock(RegistryFile
, KeyBlock
);
2403 ExFreePool(KeyBlock
);
2414 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile
,
2415 OUT PHASH_TABLE_BLOCK
*HashBlock
,
2416 IN ULONG HashTableSize
)
2420 PHASH_TABLE_BLOCK NewHashBlock
;
2422 Status
= STATUS_SUCCESS
;
2424 /* Handle volatile files first */
2425 if (RegistryFile
->Filename
== NULL
)
2427 NewHashSize
= sizeof(HASH_TABLE_BLOCK
) +
2428 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
2429 NewHashBlock
= ExAllocatePool(NonPagedPool
, NewHashSize
);
2430 if (NewHashBlock
== NULL
)
2432 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2436 RtlZeroMemory(NewHashBlock
, NewHashSize
);
2437 NewHashBlock
->SubBlockId
= REG_HASH_TABLE_BLOCK_ID
;
2438 NewHashBlock
->HashTableSize
= HashTableSize
;
2439 CmiLockBlock(RegistryFile
, NewHashBlock
);
2440 *HashBlock
= NewHashBlock
;
2451 static PHASH_TABLE_BLOCK
2452 CmiGetHashTableBlock(PREGISTRY_FILE RegistryFile
,
2453 BLOCK_OFFSET HashBlockOffset
)
2455 PHASH_TABLE_BLOCK HashBlock
;
2457 if (RegistryFile
->Filename
== NULL
)
2459 CmiLockBlock(RegistryFile
, (PVOID
) HashBlockOffset
);
2461 HashBlock
= (PHASH_TABLE_BLOCK
) HashBlockOffset
;
2472 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile
,
2473 PHASH_TABLE_BLOCK HashBlock
,
2476 PKEY_BLOCK KeyBlock
;
2478 if (RegistryFile
->Filename
== NULL
)
2480 KeyBlock
= (PKEY_BLOCK
) HashBlock
->Table
[Index
].KeyOffset
;
2481 CmiLockBlock(RegistryFile
, KeyBlock
);
2492 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile
,
2493 PHASH_TABLE_BLOCK HashBlock
,
2494 PKEY_BLOCK NewKeyBlock
)
2496 HashBlock
->Table
[HashBlock
->HashTableSize
].KeyOffset
=
2497 CmiGetBlockOffset(RegistryFile
, NewKeyBlock
);
2498 RtlCopyMemory(&HashBlock
->Table
[HashBlock
->HashTableSize
].HashValue
,
2501 HashBlock
->HashTableSize
++;
2503 return STATUS_SUCCESS
;
2507 CmiDestroyHashTableBlock(PREGISTRY_FILE RegistryFile
,
2508 PHASH_TABLE_BLOCK HashBlock
)
2512 Status
= STATUS_SUCCESS
;
2514 if (RegistryFile
->Filename
== NULL
)
2516 CmiReleaseBlock(RegistryFile
, HashBlock
);
2517 ExFreePool(HashBlock
);
2521 Status
= STATUS_NOT_IMPLEMENTED
;
2528 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile
,
2529 PVALUE_BLOCK
*ValueBlock
,
2530 IN PWSTR ValueNameBuf
,
2537 PVALUE_BLOCK NewValueBlock
;
2540 Status
= STATUS_SUCCESS
;
2542 /* Handle volatile files first */
2543 if (RegistryFile
->Filename
== NULL
)
2545 NewValueSize
= sizeof(VALUE_BLOCK
) + wcslen(ValueNameBuf
);
2546 NewValueBlock
= ExAllocatePool(NonPagedPool
, NewValueSize
);
2547 if (NewValueBlock
== NULL
)
2549 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2553 RtlZeroMemory(NewValueBlock
, NewValueSize
);
2554 NewValueBlock
->SubBlockId
= REG_VALUE_BLOCK_ID
;
2555 NewValueBlock
->NameSize
= wcslen(ValueNameBuf
);
2556 wcscpy(NewValueBlock
->Name
, ValueNameBuf
);
2557 NewValueBlock
->DataType
= Type
;
2558 NewValueBlock
->DataSize
= DataSize
;
2559 Status
= CmiAllocateBlock(RegistryFile
,
2562 if (!NT_SUCCESS(Status
))
2564 ExFreePool(NewValueBlock
);
2568 RtlCopyMemory(DataBlock
, Data
, DataSize
);
2569 NewValueBlock
->DataOffset
= CmiGetBlockOffset(RegistryFile
,
2571 CmiLockBlock(RegistryFile
, NewValueBlock
);
2572 CmiReleaseBlock(RegistryFile
, DataBlock
);
2573 *ValueBlock
= NewValueBlock
;
2579 Status
= STATUS_NOT_IMPLEMENTED
;
2586 CmiReplaceValueData(IN PREGISTRY_FILE RegistryFile
,
2587 IN PVALUE_BLOCK ValueBlock
,
2593 PVOID DataBlock
, NewDataBlock
;
2595 Status
= STATUS_SUCCESS
;
2597 /* If new data size is <= current then overwrite current data */
2598 if (DataSize
<= ValueBlock
->DataSize
)
2600 DataBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
);
2601 RtlCopyMemory(DataBlock
, Data
, DataSize
);
2602 ValueBlock
->DataSize
= DataSize
;
2603 ValueBlock
->DataType
= Type
;
2604 CmiReleaseBlock(RegistryFile
, DataBlock
);
2608 /* Destroy current data block and allocate a new one */
2609 DataBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
);
2610 Status
= CmiAllocateBlock(RegistryFile
,
2613 RtlCopyMemory(NewDataBlock
, Data
, DataSize
);
2614 ValueBlock
->DataOffset
= CmiGetBlockOffset(RegistryFile
, DataBlock
);
2615 ValueBlock
->DataSize
= DataSize
;
2616 ValueBlock
->DataType
= Type
;
2617 CmiReleaseBlock(RegistryFile
, NewDataBlock
);
2618 CmiDestroyBlock(RegistryFile
, DataBlock
);
2625 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile
,
2626 PVALUE_BLOCK ValueBlock
)
2630 Status
= CmiDestroyBlock(RegistryFile
,
2631 CmiGetBlock(RegistryFile
,
2632 ValueBlock
->DataOffset
));
2633 if (!NT_SUCCESS(Status
))
2637 return CmiDestroyBlock(RegistryFile
, ValueBlock
);
2641 CmiAllocateBlock(PREGISTRY_FILE RegistryFile
,
2648 Status
= STATUS_SUCCESS
;
2650 /* Handle volatile files first */
2651 if (RegistryFile
->Filename
== NULL
)
2653 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
2654 if (NewBlock
== NULL
)
2656 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2660 RtlZeroMemory(NewBlock
, BlockSize
);
2661 CmiLockBlock(RegistryFile
, NewBlock
);
2667 Status
= STATUS_NOT_IMPLEMENTED
;
2674 CmiDestroyBlock(PREGISTRY_FILE RegistryFile
,
2679 Status
= STATUS_SUCCESS
;
2681 if (RegistryFile
->Filename
== NULL
)
2683 CmiReleaseBlock(RegistryFile
, Block
);
2688 Status
= STATUS_NOT_IMPLEMENTED
;
2695 CmiGetBlock(PREGISTRY_FILE RegistryFile
,
2696 BLOCK_OFFSET BlockOffset
)
2701 if (RegistryFile
->Filename
== NULL
)
2703 CmiLockBlock(RegistryFile
, (PVOID
) BlockOffset
);
2705 Block
= (PVOID
) BlockOffset
;
2716 CmiGetBlockOffset(PREGISTRY_FILE RegistryFile
,
2719 BLOCK_OFFSET BlockOffset
;
2721 if (RegistryFile
->Filename
== NULL
)
2723 BlockOffset
= (BLOCK_OFFSET
) Block
;
2734 CmiLockBlock(PREGISTRY_FILE RegistryFile
,
2737 if (RegistryFile
->Filename
!= NULL
)
2744 CmiReleaseBlock(PREGISTRY_FILE RegistryFile
,
2747 if (RegistryFile
->Filename
!= NULL
)