1 /* $Id: registry.c,v 1.18 1999/08/29 06:59:05 ea 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 */
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"
43 typedef DWORD BLOCK_OFFSET
;
45 typedef struct _HEADER_BLOCK
50 LARGE_INTEGER DateModified
;
55 BLOCK_OFFSET RootKeyBlock
;
60 } HEADER_BLOCK
, *PHEADER_BLOCK
;
62 typedef struct _HEAP_BLOCK
65 BLOCK_OFFSET PreviousHeapBlock
;
66 BLOCK_OFFSET NextHeapBlock
;
68 } HEAP_BLOCK
, *PHEAP_BLOCK
;
70 typedef struct _FREE_SUB_BLOCK
73 } FREE_SUB_BLOCK
, *PFREE_SUB_BLOCK
;
75 typedef struct _KEY_BLOCK
79 LARGE_INTEGER LastWriteTime
;
80 BLOCK_OFFSET ParentKeyOffset
;
81 DWORD NumberOfSubKeys
;
82 BLOCK_OFFSET HashTableOffset
;
84 BLOCK_OFFSET ValuesOffset
;
85 BLOCK_OFFSET SecurityKeyOffset
;
86 BLOCK_OFFSET ClassNameOffset
;
91 } KEY_BLOCK
, *PKEY_BLOCK
;
93 typedef struct _HASH_RECORD
95 BLOCK_OFFSET KeyOffset
;
97 } HASH_RECORD
, *PHASH_RECORD
;
99 typedef struct _HASH_TABLE_BLOCK
103 HASH_RECORD Table
[1];
104 } HASH_TABLE_BLOCK
, *PHASH_TABLE_BLOCK
;
106 typedef struct _VALUE_LIST_BLOCK
108 BLOCK_OFFSET Values
[1];
109 } VALUE_LIST_BLOCK
, *PVALUE_LIST_BLOCK
;
111 typedef struct _VALUE_BLOCK
116 BLOCK_OFFSET DataOffset
;
121 } VALUE_BLOCK
, *PVALUE_BLOCK
;
123 typedef struct _IN_MEMORY_BLOCK
128 } IN_MEMORY_BLOCK
, *PIN_MEMORY_BLOCK
;
130 typedef struct _REGISTRY_FILE
134 PHEADER_BLOCK HeaderBlock
;
135 ULONG NumberOfBlocks
;
137 PIN_MEMORY_BLOCK
*BlockList
;
139 NTSTATUS (*Extend
)(ULONG NewSize
);
140 PVOID (*Flush
)(VOID
);
141 } REGISTRY_FILE
, *PREGISTRY_FILE
;
143 /* Type defining the Object Manager Key Object */
144 typedef struct _KEY_OBJECT
151 PREGISTRY_FILE RegistryFile
;
153 struct _KEY_OBJECT
*NextKey
;
154 } KEY_OBJECT
, *PKEY_OBJECT
;
156 #define KO_MARKED_FOR_DELETE 0x00000001
158 /* ------------------------------------------------- File Statics */
160 static POBJECT_TYPE CmiKeyType
= NULL
;
161 static PKEY_OBJECT CmiKeyList
= NULL
;
162 static KSPIN_LOCK CmiKeyListLock
;
163 static PREGISTRY_FILE CmiVolatileFile
= NULL
;
164 static PREGISTRY_FILE CmiSystemFile
= NULL
;
166 /* ----------------------------------------- Forward Declarations */
168 static PVOID
CmiObjectParse(PVOID ParsedObject
, PWSTR
*Path
);
169 static VOID
CmiObjectDelete(PVOID DeletedObject
);
170 static NTSTATUS
CmiBuildKeyPath(PWSTR
*KeyPath
,
171 POBJECT_ATTRIBUTES ObjectAttributes
);
172 static VOID
CmiAddKeyToList(PKEY_OBJECT NewKey
);
173 static VOID
CmiRemoveKeyFromList(PKEY_OBJECT NewKey
);
174 static PKEY_OBJECT
CmiScanKeyList(PWSTR KeyNameBuf
);
175 static PREGISTRY_FILE
CmiCreateRegistry(PWSTR Filename
);
176 static NTSTATUS
CmiCreateKey(IN PREGISTRY_FILE RegistryFile
,
178 OUT PKEY_BLOCK
*KeyBlock
,
179 IN ACCESS_MASK DesiredAccess
,
181 IN PUNICODE_STRING Class
,
182 IN ULONG CreateOptions
,
183 OUT PULONG Disposition
);
184 static NTSTATUS
CmiFindKey(IN PREGISTRY_FILE RegistryFile
,
186 OUT PKEY_BLOCK
*KeyBlock
,
187 IN ACCESS_MASK DesiredAccess
,
189 IN PUNICODE_STRING Class
);
190 static ULONG
CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile
,
191 PKEY_BLOCK KeyBlock
);
192 static ULONG
CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile
,
193 PKEY_BLOCK KeyBlock
);
194 static ULONG
CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile
,
195 PKEY_BLOCK KeyBlock
);
196 static ULONG
CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile
,
197 PKEY_BLOCK KeyBlock
);
198 static NTSTATUS
CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile
,
199 IN PKEY_BLOCK KeyBlock
,
200 OUT PKEY_BLOCK
*SubKeyBlock
,
202 IN ACCESS_MASK DesiredAccess
);
203 static NTSTATUS
CmiAddSubKey(IN PREGISTRY_FILE RegistryFile
,
204 IN PKEY_BLOCK CurKeyBlock
,
205 OUT PKEY_BLOCK
*SubKeyBlock
,
206 IN PWSTR NewSubKeyName
,
209 IN ULONG CreateOptions
);
210 static NTSTATUS
CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile
,
211 IN PKEY_BLOCK KeyBlock
,
213 OUT PVALUE_BLOCK
*ValueBlock
);
214 static NTSTATUS
CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile
,
215 IN PKEY_BLOCK KeyBlock
,
216 IN PWSTR ValueNameBuf
,
220 static NTSTATUS
CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile
,
221 IN PKEY_BLOCK KeyBlock
,
223 static NTSTATUS
CmiAllocateKeyBlock(IN PREGISTRY_FILE RegistryFile
,
224 OUT PKEY_BLOCK
*KeyBlock
,
225 IN PWSTR NewSubKeyName
,
228 IN ULONG CreateOptions
);
229 static PKEY_BLOCK
CmiGetKeyBlock(PREGISTRY_FILE RegistryFile
,
230 BLOCK_OFFSET KeyBlockOffset
);
231 static NTSTATUS
CmiDestroyKeyBlock(PREGISTRY_FILE RegistryFile
,
232 PKEY_BLOCK KeyBlock
);
233 static NTSTATUS
CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile
,
234 OUT PHASH_TABLE_BLOCK
*HashBlock
,
235 IN ULONG HashTableSize
);
236 static PHASH_TABLE_BLOCK
CmiGetHashTableBlock(PREGISTRY_FILE RegistryFile
,
237 BLOCK_OFFSET HashBlockOffset
);
238 static PKEY_BLOCK
CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile
,
239 PHASH_TABLE_BLOCK HashBlock
,
241 static NTSTATUS
CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile
,
242 PHASH_TABLE_BLOCK HashBlock
,
243 PKEY_BLOCK NewKeyBlock
);
244 static NTSTATUS
CmiDestroyHashTableBlock(PREGISTRY_FILE RegistryFile
,
245 PHASH_TABLE_BLOCK HashBlock
);
246 static NTSTATUS
CmiAllocateValueBlock(IN PREGISTRY_FILE RegistryFile
,
247 OUT PVALUE_BLOCK
*ValueBlock
,
248 IN PWSTR ValueNameBuf
,
252 static NTSTATUS
CmiReplaceValueData(IN PREGISTRY_FILE RegistryFile
,
253 IN PVALUE_BLOCK ValueBlock
,
257 static NTSTATUS
CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile
,
258 PVALUE_BLOCK ValueBlock
);
259 static NTSTATUS
CmiAllocateBlock(PREGISTRY_FILE RegistryFile
,
262 static NTSTATUS
CmiDestroyBlock(PREGISTRY_FILE RegistryFile
,
264 static PVOID
CmiGetBlock(PREGISTRY_FILE RegistryFile
,
265 BLOCK_OFFSET BlockOffset
);
266 static BLOCK_OFFSET
CmiGetBlockOffset(PREGISTRY_FILE RegistryFile
,
268 static VOID
CmiLockBlock(PREGISTRY_FILE RegistryFile
,
270 static VOID
CmiReleaseBlock(PREGISTRY_FILE RegistryFile
,
275 /* --------------------------------------------- Public Interface */
278 CmInitializeRegistry(VOID
)
282 HANDLE RootKeyHandle
;
283 UNICODE_STRING RootKeyName
;
284 OBJECT_ATTRIBUTES ObjectAttributes
;
287 /* Initialize the Key object type */
288 CmiKeyType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
289 CmiKeyType
->TotalObjects
= 0;
290 CmiKeyType
->TotalHandles
= 0;
291 CmiKeyType
->MaxObjects
= ULONG_MAX
;
292 CmiKeyType
->MaxHandles
= ULONG_MAX
;
293 CmiKeyType
->PagedPoolCharge
= 0;
294 CmiKeyType
->NonpagedPoolCharge
= sizeof(KEY_OBJECT
);
295 CmiKeyType
->Dump
= NULL
;
296 CmiKeyType
->Open
= NULL
;
297 CmiKeyType
->Close
= NULL
;
298 CmiKeyType
->Delete
= CmiObjectDelete
;
299 CmiKeyType
->Parse
= CmiObjectParse
;
300 CmiKeyType
->Security
= NULL
;
301 CmiKeyType
->QueryName
= NULL
;
302 CmiKeyType
->OkayToClose
= NULL
;
303 RtlInitUnicodeString(&CmiKeyType
->TypeName
, L
"Key");
305 /* Build the Root Key Object */
306 /* FIXME: This should be split into two objects, 1 system and 1 user */
307 RtlInitUnicodeString(&RootKeyName
, REG_ROOT_KEY_NAME
);
308 InitializeObjectAttributes(&ObjectAttributes
, &RootKeyName
, 0, NULL
, NULL
);
309 ObCreateObject(&RootKeyHandle
,
310 STANDARD_RIGHTS_REQUIRED
,
314 KeInitializeSpinLock(&CmiKeyListLock
);
316 /* Build volitile registry store */
318 CmiVolatileFile
= CmiCreateRegistry(NULL
);
320 /* Build system registry store */
322 CmiSystemFile
= NULL
; // CmiCreateRegistry(SYSTEM_REG_FILE);
324 /* Create initial predefined symbolic links */
325 /* HKEY_LOCAL_MACHINE */
327 Status
= CmiCreateKey(CmiVolatileFile
,
335 if (!NT_SUCCESS(Status
))
340 CmiReleaseBlock(CmiVolatileFile
, KeyBlock
);
344 Status
= CmiCreateKey(CmiVolatileFile
,
352 if (!NT_SUCCESS(Status
))
357 CmiReleaseBlock(CmiVolatileFile
, KeyBlock
);
359 /* FIXME: create remaining structure needed for default handles */
360 /* FIXME: load volatile registry data from ROSDTECT */
369 OUT PHANDLE KeyHandle
,
370 IN ACCESS_MASK DesiredAccess
,
371 IN POBJECT_ATTRIBUTES ObjectAttributes
,
373 IN PUNICODE_STRING Class
,
374 IN ULONG CreateOptions
,
375 OUT PULONG Disposition
381 PKEY_OBJECT CurKey
, NewKey
;
382 PREGISTRY_FILE FileToUse
;
385 assert(ObjectAttributes
!= NULL
);
387 FileToUse
= (CreateOptions
& REG_OPTION_VOLATILE
) ?
388 CmiVolatileFile
: CmiSystemFile
;
390 /* Construct the complete registry relative pathname */
391 Status
= CmiBuildKeyPath(&KeyNameBuf
, ObjectAttributes
);
392 if (!NT_SUCCESS(Status
))
397 /* Scan the key list to see if key already open */
398 CurKey
= CmiScanKeyList(KeyNameBuf
);
401 /* Unmark the key if the key has been marked for Delete */
402 if (CurKey
->Flags
& KO_MARKED_FOR_DELETE
)
404 CurKey
->Flags
&= ~KO_MARKED_FOR_DELETE
;
407 /* If so, return a reference to it */
408 Status
= ObCreateHandle(PsGetCurrentProcess(),
413 ExFreePool(KeyNameBuf
);
418 /* Create or open the key in the registry file */
419 Status
= CmiCreateKey(FileToUse
,
427 if (!NT_SUCCESS(Status
))
429 ExFreePool(KeyNameBuf
);
434 /* Create new key object and put into linked list */
435 NewKey
= ObCreateObject(KeyHandle
,
441 return STATUS_UNSUCCESSFUL
;
444 NewKey
->Name
= KeyNameBuf
;
445 NewKey
->KeyBlock
= KeyBlock
;
446 NewKey
->RegistryFile
= FileToUse
;
447 CmiAddKeyToList(NewKey
);
448 Status
= ObCreateHandle(PsGetCurrentProcess(),
469 PKEY_OBJECT KeyObject
;
471 /* Verify that the handle is valid and is a registry key */
472 Status
= ObReferenceObjectByHandle(KeyHandle
,
478 if (!NT_SUCCESS(Status
))
483 /* Set the marked for delete bit in the key object */
484 KeyObject
->Flags
|= KO_MARKED_FOR_DELETE
;
486 /* Dereference the object */
487 ObDeleteHandle(KeyHandle
);
488 /* FIXME: I think that ObDeleteHandle should dereference the object */
489 ObDereferenceObject(KeyObject
);
491 return STATUS_SUCCESS
;
503 IN KEY_INFORMATION_CLASS KeyInformationClass
,
504 OUT PVOID KeyInformation
,
506 OUT PULONG ResultLength
511 PKEY_OBJECT KeyObject
;
512 PREGISTRY_FILE RegistryFile
;
513 PKEY_BLOCK KeyBlock
, SubKeyBlock
;
514 PHASH_TABLE_BLOCK HashTableBlock
;
515 PKEY_BASIC_INFORMATION BasicInformation
;
516 PKEY_NODE_INFORMATION NodeInformation
;
517 PKEY_FULL_INFORMATION FullInformation
;
519 /* Verify that the handle is valid and is a registry key */
520 Status
= ObReferenceObjectByHandle(KeyHandle
,
521 KEY_ENUMERATE_SUB_KEYS
,
526 if (!NT_SUCCESS(Status
))
531 /* Get pointer to KeyBlock */
532 KeyBlock
= KeyObject
->KeyBlock
;
533 RegistryFile
= KeyObject
->RegistryFile
;
535 /* Get pointer to SubKey */
536 HashTableBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
537 SubKeyBlock
= CmiGetKeyFromHashByIndex(RegistryFile
,
540 if (SubKeyBlock
== NULL
)
542 return STATUS_NO_MORE_ENTRIES
;
545 Status
= STATUS_SUCCESS
;
546 switch (KeyInformationClass
)
548 case KeyBasicInformation
:
549 /* Check size of buffer */
550 if (Length
< sizeof(KEY_BASIC_INFORMATION
) +
551 SubKeyBlock
->NameSize
* sizeof(WCHAR
))
553 Status
= STATUS_BUFFER_OVERFLOW
;
557 /* Fill buffer with requested info */
558 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
559 BasicInformation
->LastWriteTime
= SubKeyBlock
->LastWriteTime
;
560 BasicInformation
->TitleIndex
= Index
;
561 BasicInformation
->NameLength
= SubKeyBlock
->NameSize
;
562 wcsncpy(BasicInformation
->Name
,
564 SubKeyBlock
->NameSize
);
565 BasicInformation
->Name
[SubKeyBlock
->NameSize
] = 0;
566 *ResultLength
= sizeof(KEY_BASIC_INFORMATION
) +
567 SubKeyBlock
->NameSize
* sizeof(WCHAR
);
571 case KeyNodeInformation
:
572 /* Check size of buffer */
573 if (Length
< sizeof(KEY_NODE_INFORMATION
) +
574 SubKeyBlock
->NameSize
* sizeof(WCHAR
) +
575 (SubKeyBlock
->ClassSize
+ 1) * sizeof(WCHAR
))
577 Status
= STATUS_BUFFER_OVERFLOW
;
581 /* Fill buffer with requested info */
582 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
583 NodeInformation
->LastWriteTime
= SubKeyBlock
->LastWriteTime
;
584 NodeInformation
->TitleIndex
= Index
;
585 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
586 SubKeyBlock
->NameSize
* sizeof(WCHAR
);
587 NodeInformation
->ClassLength
= SubKeyBlock
->ClassSize
;
588 NodeInformation
->NameLength
= SubKeyBlock
->NameSize
;
589 wcsncpy(NodeInformation
->Name
,
591 SubKeyBlock
->NameSize
);
592 NodeInformation
->Name
[SubKeyBlock
->NameSize
] = 0;
593 if (SubKeyBlock
->ClassSize
!= 0)
595 wcsncpy(NodeInformation
->Name
+ SubKeyBlock
->NameSize
+ 1,
596 &SubKeyBlock
->Name
[SubKeyBlock
->NameSize
+ 1],
597 SubKeyBlock
->ClassSize
);
599 Name
[SubKeyBlock
->NameSize
+ 1 + SubKeyBlock
->ClassSize
] = 0;
601 *ResultLength
= sizeof(KEY_NODE_INFORMATION
) +
602 SubKeyBlock
->NameSize
* sizeof(WCHAR
) +
603 (SubKeyBlock
->ClassSize
+ 1) * sizeof(WCHAR
);
607 case KeyFullInformation
:
608 /* FIXME: check size of buffer */
609 if (Length
< sizeof(KEY_FULL_INFORMATION
) +
610 SubKeyBlock
->ClassSize
* sizeof(WCHAR
))
612 Status
= STATUS_BUFFER_OVERFLOW
;
616 /* FIXME: fill buffer with requested info */
617 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
618 FullInformation
->LastWriteTime
= SubKeyBlock
->LastWriteTime
;
619 FullInformation
->TitleIndex
= Index
;
620 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) -
622 FullInformation
->ClassLength
= SubKeyBlock
->ClassSize
;
623 FullInformation
->SubKeys
= SubKeyBlock
->NumberOfSubKeys
;
624 FullInformation
->MaxNameLen
=
625 CmiGetMaxNameLength(RegistryFile
, SubKeyBlock
);
626 FullInformation
->MaxClassLen
=
627 CmiGetMaxClassLength(RegistryFile
, SubKeyBlock
);
628 FullInformation
->Values
= SubKeyBlock
->NumberOfValues
;
629 FullInformation
->MaxValueNameLen
=
630 CmiGetMaxValueNameLength(RegistryFile
, SubKeyBlock
);
631 FullInformation
->MaxValueDataLen
=
632 CmiGetMaxValueDataLength(RegistryFile
, SubKeyBlock
);
633 wcsncpy(FullInformation
->Class
,
634 &SubKeyBlock
->Name
[SubKeyBlock
->NameSize
+ 1],
635 SubKeyBlock
->ClassSize
);
636 FullInformation
->Class
[SubKeyBlock
->ClassSize
] = 0;
637 *ResultLength
= sizeof(KEY_FULL_INFORMATION
) +
638 SubKeyBlock
->ClassSize
* sizeof(WCHAR
);
642 CmiReleaseBlock(RegistryFile
, SubKeyBlock
);
653 NtEnumerateValueKey (
656 IN KEY_VALUE_INFORMATION_CLASS KeyInformationClass
,
657 OUT PVOID KeyInformation
,
659 OUT PULONG ResultLength
677 return STATUS_SUCCESS
;
687 OUT PHANDLE KeyHandle
,
688 IN ACCESS_MASK DesiredAccess
,
689 IN POBJECT_ATTRIBUTES ObjectAttributes
695 PREGISTRY_FILE FileToUse
;
697 PKEY_OBJECT CurKey
, NewKey
;
699 /* Construct the complete registry relative pathname */
700 Status
= CmiBuildKeyPath(&KeyNameBuf
, ObjectAttributes
);
701 if (!NT_SUCCESS(Status
))
706 /* Scan the key list to see if key already open */
707 CurKey
= CmiScanKeyList(KeyNameBuf
);
710 /* Fail if the key has been deleted */
711 if (CurKey
->Flags
& KO_MARKED_FOR_DELETE
)
713 ExFreePool(KeyNameBuf
);
715 return STATUS_UNSUCCESSFUL
;
718 /* If so, return a reference to it */
719 Status
= ObCreateHandle(PsGetCurrentProcess(),
724 ExFreePool(KeyNameBuf
);
729 /* Open the key in the registry file */
730 FileToUse
= CmiSystemFile
;
731 Status
= CmiFindKey(FileToUse
,
737 if (!NT_SUCCESS(Status
))
739 FileToUse
= CmiVolatileFile
;
740 Status
= CmiFindKey(FileToUse
,
746 if (!NT_SUCCESS(Status
))
748 ExFreePool(KeyNameBuf
);
754 /* Create new key object and put into linked list */
755 NewKey
= ObCreateObject(KeyHandle
,
761 return STATUS_UNSUCCESSFUL
;
764 NewKey
->Name
= KeyNameBuf
;
765 NewKey
->RegistryFile
= FileToUse
;
766 NewKey
->KeyBlock
= KeyBlock
;
767 CmiAddKeyToList(NewKey
);
768 Status
= ObCreateHandle(PsGetCurrentProcess(),
785 IN KEY_INFORMATION_CLASS KeyInformationClass
,
786 OUT PVOID KeyInformation
,
788 OUT PULONG ResultLength
793 PKEY_OBJECT KeyObject
;
794 PREGISTRY_FILE RegistryFile
;
796 PKEY_BASIC_INFORMATION BasicInformation
;
797 PKEY_NODE_INFORMATION NodeInformation
;
798 PKEY_FULL_INFORMATION FullInformation
;
800 /* Verify that the handle is valid and is a registry key */
801 Status
= ObReferenceObjectByHandle(KeyHandle
,
807 if (!NT_SUCCESS(Status
))
812 /* Get pointer to KeyBlock */
813 KeyBlock
= KeyObject
->KeyBlock
;
814 RegistryFile
= KeyObject
->RegistryFile
;
816 Status
= STATUS_SUCCESS
;
817 switch (KeyInformationClass
)
819 case KeyBasicInformation
:
820 /* Check size of buffer */
821 if (Length
< sizeof(KEY_BASIC_INFORMATION
) +
822 KeyBlock
->NameSize
* sizeof(WCHAR
))
824 Status
= STATUS_BUFFER_OVERFLOW
;
828 /* Fill buffer with requested info */
829 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
830 BasicInformation
->LastWriteTime
= KeyBlock
->LastWriteTime
;
831 BasicInformation
->TitleIndex
= 0;
832 BasicInformation
->NameLength
= KeyBlock
->NameSize
;
833 wcsncpy(BasicInformation
->Name
,
836 BasicInformation
->Name
[KeyBlock
->NameSize
] = 0;
837 *ResultLength
= sizeof(KEY_BASIC_INFORMATION
) +
838 KeyBlock
->NameSize
* sizeof(WCHAR
);
842 case KeyNodeInformation
:
843 /* Check size of buffer */
844 if (Length
< sizeof(KEY_NODE_INFORMATION
) +
845 KeyBlock
->NameSize
* sizeof(WCHAR
) +
846 (KeyBlock
->ClassSize
+ 1) * sizeof(WCHAR
))
848 Status
= STATUS_BUFFER_OVERFLOW
;
852 /* Fill buffer with requested info */
853 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
854 NodeInformation
->LastWriteTime
= KeyBlock
->LastWriteTime
;
855 NodeInformation
->TitleIndex
= 0;
856 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
857 KeyBlock
->NameSize
* sizeof(WCHAR
);
858 NodeInformation
->ClassLength
= KeyBlock
->ClassSize
;
859 NodeInformation
->NameLength
= KeyBlock
->NameSize
;
860 wcsncpy(NodeInformation
->Name
,
863 NodeInformation
->Name
[KeyBlock
->NameSize
] = 0;
864 if (KeyBlock
->ClassSize
!= 0)
866 wcsncpy(NodeInformation
->Name
+ KeyBlock
->NameSize
+ 1,
867 &KeyBlock
->Name
[KeyBlock
->NameSize
+ 1],
868 KeyBlock
->ClassSize
);
870 Name
[KeyBlock
->NameSize
+ 1 + KeyBlock
->ClassSize
] = 0;
872 *ResultLength
= sizeof(KEY_NODE_INFORMATION
) +
873 KeyBlock
->NameSize
* sizeof(WCHAR
) +
874 (KeyBlock
->ClassSize
+ 1) * sizeof(WCHAR
);
878 case KeyFullInformation
:
879 /* Check size of buffer */
880 if (Length
< sizeof(KEY_FULL_INFORMATION
) +
881 KeyBlock
->ClassSize
* sizeof(WCHAR
))
883 Status
= STATUS_BUFFER_OVERFLOW
;
887 /* Fill buffer with requested info */
888 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
889 FullInformation
->LastWriteTime
= KeyBlock
->LastWriteTime
;
890 FullInformation
->TitleIndex
= 0;
891 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) -
893 FullInformation
->ClassLength
= KeyBlock
->ClassSize
;
894 FullInformation
->SubKeys
= KeyBlock
->NumberOfSubKeys
;
895 FullInformation
->MaxNameLen
=
896 CmiGetMaxNameLength(RegistryFile
, KeyBlock
);
897 FullInformation
->MaxClassLen
=
898 CmiGetMaxClassLength(RegistryFile
, KeyBlock
);
899 FullInformation
->Values
= KeyBlock
->NumberOfValues
;
900 FullInformation
->MaxValueNameLen
=
901 CmiGetMaxValueNameLength(RegistryFile
, KeyBlock
);
902 FullInformation
->MaxValueDataLen
=
903 CmiGetMaxValueDataLength(RegistryFile
, KeyBlock
);
904 wcsncpy(FullInformation
->Class
,
905 &KeyBlock
->Name
[KeyBlock
->NameSize
+ 1],
906 KeyBlock
->ClassSize
);
907 FullInformation
->Class
[KeyBlock
->ClassSize
] = 0;
908 *ResultLength
= sizeof(KEY_FULL_INFORMATION
) +
909 KeyBlock
->ClassSize
* sizeof(WCHAR
);
925 IN PUNICODE_STRING ValueName
,
926 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
927 OUT PVOID KeyValueInformation
,
929 OUT PULONG ResultLength
934 PKEY_OBJECT KeyObject
;
935 PREGISTRY_FILE RegistryFile
;
937 PVALUE_BLOCK ValueBlock
;
939 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
940 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
941 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
943 /* Verify that the handle is valid and is a registry key */
944 Status
= ObReferenceObjectByHandle(KeyHandle
,
950 if (!NT_SUCCESS(Status
))
955 /* Get pointer to KeyBlock */
956 KeyBlock
= KeyObject
->KeyBlock
;
957 RegistryFile
= KeyObject
->RegistryFile
;
959 /* Get Value block of interest */
960 Status
= CmiScanKeyForValue(RegistryFile
,
964 if (!NT_SUCCESS(Status
))
968 else if (ValueBlock
!= NULL
)
970 switch (KeyValueInformationClass
)
972 case KeyValueBasicInformation
:
973 *ResultLength
= sizeof(KEY_VALUE_BASIC_INFORMATION
) +
974 ValueBlock
->NameSize
* sizeof(WCHAR
);
975 if (Length
< *ResultLength
)
977 Status
= STATUS_BUFFER_OVERFLOW
;
981 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
983 ValueBasicInformation
->TitleIndex
= 0;
984 ValueBasicInformation
->Type
= ValueBlock
->DataType
;
985 ValueBasicInformation
->NameLength
= ValueBlock
->NameSize
;
986 wcscpy(ValueBasicInformation
->Name
, ValueBlock
->Name
);
990 case KeyValuePartialInformation
:
991 *ResultLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
992 ValueBlock
->DataSize
;
993 if (Length
< *ResultLength
)
995 Status
= STATUS_BUFFER_OVERFLOW
;
999 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1000 KeyValueInformation
;
1001 ValuePartialInformation
->TitleIndex
= 0;
1002 ValuePartialInformation
->Type
= ValueBlock
->DataType
;
1003 ValuePartialInformation
->DataLength
= ValueBlock
->DataSize
;
1004 DataBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
);
1005 RtlCopyMemory(ValuePartialInformation
->Data
,
1007 ValueBlock
->DataSize
);
1008 CmiReleaseBlock(RegistryFile
, DataBlock
);
1012 case KeyValueFullInformation
:
1013 *ResultLength
= sizeof(KEY_VALUE_FULL_INFORMATION
) +
1014 ValueBlock
->NameSize
* sizeof(WCHAR
) + ValueBlock
->DataSize
;
1015 if (Length
< *ResultLength
)
1017 Status
= STATUS_BUFFER_OVERFLOW
;
1021 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1022 KeyValueInformation
;
1023 ValueFullInformation
->TitleIndex
= 0;
1024 ValueFullInformation
->Type
= ValueBlock
->DataType
;
1025 ValueFullInformation
->DataOffset
=
1026 sizeof(KEY_VALUE_FULL_INFORMATION
) +
1027 ValueBlock
->NameSize
* sizeof(WCHAR
);
1028 ValueFullInformation
->DataLength
= ValueBlock
->DataSize
;
1029 ValueFullInformation
->NameLength
= ValueBlock
->NameSize
;
1030 wcscpy(ValueFullInformation
->Name
, ValueBlock
->Name
);
1031 DataBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
);
1032 RtlCopyMemory(&ValueFullInformation
->Name
[ValueBlock
->NameSize
+ 1],
1034 ValueBlock
->DataSize
);
1035 CmiReleaseBlock(RegistryFile
, DataBlock
);
1042 Status
= STATUS_UNSUCCESSFUL
;
1055 IN HANDLE KeyHandle
,
1056 IN PUNICODE_STRING ValueName
,
1057 IN ULONG TitleIndex
,
1065 PKEY_OBJECT KeyObject
;
1066 PREGISTRY_FILE RegistryFile
;
1067 PKEY_BLOCK KeyBlock
;
1068 PVALUE_BLOCK ValueBlock
;
1070 /* Verify that the handle is valid and is a registry key */
1071 Status
= ObReferenceObjectByHandle(KeyHandle
,
1075 (PVOID
*)&KeyObject
,
1077 if (!NT_SUCCESS(Status
))
1082 /* Get pointer to KeyBlock */
1083 KeyBlock
= KeyObject
->KeyBlock
;
1084 RegistryFile
= KeyObject
->RegistryFile
;
1085 Status
= CmiScanKeyForValue(RegistryFile
,
1089 if (!NT_SUCCESS(Status
))
1093 if (ValueBlock
== NULL
)
1095 Status
= CmiAddValueToKey(RegistryFile
,
1104 Status
= CmiReplaceValueData(RegistryFile
,
1120 IN HANDLE KeyHandle
,
1121 IN PUNICODE_STRING ValueName
1126 PKEY_OBJECT KeyObject
;
1127 PREGISTRY_FILE RegistryFile
;
1128 PKEY_BLOCK KeyBlock
;
1130 /* Verify that the handle is valid and is a registry key */
1131 Status
= ObReferenceObjectByHandle(KeyHandle
,
1135 (PVOID
*)&KeyObject
,
1137 if (!NT_SUCCESS(Status
))
1142 /* Get pointer to KeyBlock */
1143 KeyBlock
= KeyObject
->KeyBlock
;
1144 RegistryFile
= KeyObject
->RegistryFile
;
1145 Status
= CmiDeleteValueFromKey(RegistryFile
,
1159 OBJECT_ATTRIBUTES ObjectAttributes
1177 IN HANDLE KeyHandle
,
1179 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
1180 IN PVOID ApcContext OPTIONAL
,
1181 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1182 IN ULONG CompletionFilter
,
1183 IN BOOLEAN Asynchroneous
,
1184 OUT PVOID ChangeBuffer
,
1186 IN BOOLEAN WatchSubtree
1195 NtQueryMultipleValueKey (
1196 IN HANDLE KeyHandle
,
1197 IN PVALENT ListOfValuesToQuery
,
1198 IN ULONG NumberOfItems
,
1199 OUT PVOID MultipleValueInformation
,
1201 OUT PULONG ReturnLength
)
1210 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1212 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
1222 IN HANDLE KeyHandle
,
1223 IN HANDLE FileHandle
,
1224 IN ULONG RestoreFlags
1234 IN HANDLE KeyHandle
,
1235 IN HANDLE FileHandle
1244 NtSetInformationKey (
1245 IN HANDLE KeyHandle
,
1246 IN CINT KeyInformationClass
,
1247 IN PVOID KeyInformation
,
1248 IN ULONG KeyInformationLength
1267 NtInitializeRegistry (
1277 RtlCheckRegistryKey (
1288 RtlCreateRegistryKey (
1289 IN ULONG RelativeTo
,
1299 RtlDeleteRegistryValue (
1300 IN ULONG RelativeTo
,
1311 RtlQueryRegistryValues (
1312 IN ULONG RelativeTo
,
1314 PRTL_QUERY_REGISTRY_TABLE QueryTable
,
1325 RtlWriteRegistryValue (
1337 /* ------------------------------------------ Private Implementation */
1342 CmiObjectParse(PVOID ParsedObject
, PWSTR
*Path
)
1345 /* FIXME: this should be allocated based on the largest subkey name */
1346 WCHAR CurKeyName
[256];
1347 PWSTR Remainder
, NextSlash
;
1348 PREGISTRY_FILE RegistryFile
;
1349 PKEY_OBJECT NewKeyObject
;
1351 PKEY_BLOCK CurKeyBlock
, SubKeyBlock
;
1353 Status
= STATUS_SUCCESS
;
1355 /* FIXME: it should probably get this from ParsedObject */
1356 RegistryFile
= CmiVolatileFile
;
1358 /* Scan key object list for key already open */
1359 NewKeyObject
= CmiScanKeyList((*Path
) + 1);
1360 if (NewKeyObject
!= NULL
)
1362 /* Return reference if found */
1363 ObReferenceObjectByPointer(NewKeyObject
,
1364 STANDARD_RIGHTS_REQUIRED
,
1369 return NewKeyObject
;
1372 /* FIXME: this access of RootKeyBlock should be guarded by spinlock */
1373 CurKeyBlock
= CmiGetKeyBlock(RegistryFile
,
1374 RegistryFile
->HeaderBlock
->RootKeyBlock
);
1376 /* Loop through each key level and find the needed subkey */
1377 Remainder
= (*Path
) + 1;
1378 while (NT_SUCCESS(Status
) && *Remainder
!= 0)
1380 NextSlash
= wcschr(Remainder
, L
'\\');
1382 /* Copy just the current subkey name to a buffer */
1383 if (NextSlash
!= NULL
)
1385 wcsncpy(CurKeyName
, Remainder
, NextSlash
- Remainder
);
1386 CurKeyName
[NextSlash
- Remainder
] = 0;
1390 wcscpy(CurKeyName
, Remainder
);
1393 /* Verify existance of CurKeyName */
1394 Status
= CmiScanForSubKey(RegistryFile
,
1398 STANDARD_RIGHTS_REQUIRED
);
1399 if (!NT_SUCCESS(Status
))
1403 if (SubKeyBlock
== NULL
)
1405 Status
= STATUS_UNSUCCESSFUL
;
1408 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1409 CurKeyBlock
= SubKeyBlock
;
1411 if (NextSlash
!= NULL
)
1413 Remainder
= NextSlash
+ 1;
1421 /* Create new key object and put into linked list */
1422 NewKeyObject
= ObCreateObject(&KeyHandle
,
1423 STANDARD_RIGHTS_REQUIRED
,
1426 if (NewKeyObject
== NULL
)
1430 NewKeyObject
->Flags
= 0;
1431 NewKeyObject
->Name
= ExAllocatePool(NonPagedPool
,
1432 wcslen(*Path
) * sizeof(WCHAR
));
1433 wcscpy(NewKeyObject
->Name
, (*Path
) + 1);
1434 NewKeyObject
->KeyBlock
= CurKeyBlock
;
1435 NewKeyObject
->RegistryFile
= RegistryFile
;
1436 CmiAddKeyToList(NewKeyObject
);
1437 *Path
= (Remainder
!= NULL
) ? Remainder
- 1 : NULL
;
1439 return NewKeyObject
;
1443 CmiObjectDelete(PVOID DeletedObject
)
1445 PKEY_OBJECT KeyObject
;
1447 KeyObject
= (PKEY_OBJECT
) DeletedObject
;
1448 if (KeyObject
->Flags
& KO_MARKED_FOR_DELETE
)
1450 CmiDestroyKeyBlock(KeyObject
->RegistryFile
,
1451 KeyObject
->KeyBlock
);
1455 CmiReleaseBlock(KeyObject
->RegistryFile
,
1456 KeyObject
->KeyBlock
);
1458 ExFreePool(KeyObject
->Name
);
1459 CmiRemoveKeyFromList(KeyObject
);
1463 CmiBuildKeyPath(PWSTR
*KeyPath
, POBJECT_ATTRIBUTES ObjectAttributes
)
1469 PKEY_OBJECT KeyObject
;
1470 POBJECT_HEADER ObjectHeader
;
1472 /* FIXME: Verify ObjectAttributes is in \\Registry space and compute size for path */
1475 if (ObjectAttributes
->RootDirectory
!= NULL
)
1477 /* FIXME: determine type of object for RootDirectory */
1478 Status
= ObReferenceObjectByHandle(ObjectAttributes
->RootDirectory
,
1482 (PVOID
*)&ObjectBody
,
1484 if (!NT_SUCCESS(Status
))
1488 ObjectHeader
= BODY_TO_HEADER(ObjectBody
);
1490 if (ObjectHeader
->ObjectType
!= CmiKeyType
)
1492 /* Fail if RootDirectory != '\\' */
1493 if (ObjectBody
== NameSpaceRoot
)
1495 /* Check for 'Registry' in ObjectName, fail if missing */
1496 if (wcsncmp(ObjectAttributes
->ObjectName
->Buffer
,
1497 REG_ROOT_KEY_NAME
+ 1,
1498 wcslen(REG_ROOT_KEY_NAME
+ 1)) != 0 ||
1499 ObjectAttributes
->ObjectName
->Buffer
[wcslen(REG_ROOT_KEY_NAME
+ 1)] != L
'\\')
1501 ObDereferenceObject(ObjectBody
);
1503 return STATUS_OBJECT_PATH_INVALID
;
1506 /* Compute size of registry portion of path to KeyNameSize */
1507 KeyNameSize
= (ObjectAttributes
->ObjectName
->Length
-
1508 (wcslen(REG_ROOT_KEY_NAME
+ 1) + 1))
1511 else if (!wcscmp(ObjectHeader
->Name
.Buffer
,
1512 REG_ROOT_KEY_NAME
+ 1))
1514 /* Add size of ObjectName to KeyNameSize */
1515 KeyNameSize
= ObjectAttributes
->ObjectName
->Length
;
1519 ObDereferenceObject(ObjectBody
);
1521 return STATUS_OBJECT_PATH_INVALID
;
1526 KeyObject
= (PKEY_OBJECT
) ObjectBody
;
1528 /* Add size of Name from RootDirectory object to KeyNameSize */
1529 KeyNameSize
= wcslen(KeyObject
->Name
) * sizeof(WCHAR
);
1531 /* Add 1 to KeyNamesize for '\\' */
1532 KeyNameSize
+= sizeof(WCHAR
);
1534 /* Add size of ObjectName to KeyNameSize */
1535 KeyNameSize
+= ObjectAttributes
->ObjectName
->Length
* sizeof(WCHAR
);
1540 /* Check for \\Registry and fail if missing */
1541 if (wcsncmp(ObjectAttributes
->ObjectName
->Buffer
,
1543 wcslen(REG_ROOT_KEY_NAME
)) != 0 ||
1544 ObjectAttributes
->ObjectName
->Buffer
[wcslen(REG_ROOT_KEY_NAME
)] != L
'\\')
1546 return STATUS_OBJECT_PATH_INVALID
;
1549 /* Compute size of registry portion of path to KeyNameSize */
1550 KeyNameSize
= (ObjectAttributes
->ObjectName
->Length
-
1551 (wcslen(REG_ROOT_KEY_NAME
) + 1)) * sizeof(WCHAR
);
1554 KeyNameBuf
= ExAllocatePool(NonPagedPool
, KeyNameSize
+ sizeof(WCHAR
));
1556 /* Construct relative pathname */
1558 if (ObjectAttributes
->RootDirectory
!= NULL
)
1560 if (ObjectHeader
->ObjectType
!= CmiKeyType
)
1562 /* Fail if RootDirectory != '\\' */
1563 if (ObjectBody
== NameSpaceRoot
)
1565 /* Copy remainder of ObjectName after 'Registry' */
1566 wcscpy(KeyNameBuf
, ObjectAttributes
->ObjectName
->Buffer
+ wcslen(REG_ROOT_KEY_NAME
+ 1));
1570 /* Copy all of ObjectName */
1571 wcscpy(KeyNameBuf
, ObjectAttributes
->ObjectName
->Buffer
);
1576 KeyObject
= (PKEY_OBJECT
) ObjectBody
;
1578 /* Copy Name from RootDirectory object to KeyNameBuf */
1579 wcscpy(KeyNameBuf
, KeyObject
->Name
);
1581 /* Append '\\' onto KeyNameBuf */
1582 wcscat(KeyNameBuf
, L
"\\");
1584 /* Append ObjectName onto KeyNameBuf */
1585 wcscat(KeyNameBuf
, ObjectAttributes
->ObjectName
->Buffer
);
1590 /* Copy registry portion of path into KeyNameBuf */
1591 wcscpy(KeyNameBuf
, ObjectAttributes
->ObjectName
->Buffer
+
1592 (wcslen(REG_ROOT_KEY_NAME
) + 1));
1595 *KeyPath
= KeyNameBuf
;
1596 return STATUS_SUCCESS
;
1600 CmiAddKeyToList(PKEY_OBJECT NewKey
)
1604 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
1605 NewKey
->NextKey
= CmiKeyList
;
1606 CmiKeyList
= NewKey
;
1607 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
1611 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove
)
1616 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
1617 if (CmiKeyList
== KeyToRemove
)
1619 CmiKeyList
= CmiKeyList
->NextKey
;
1623 CurKey
= CmiKeyList
;
1624 while (CurKey
!= NULL
&& CurKey
->NextKey
!= KeyToRemove
)
1626 CurKey
= CurKey
->NextKey
;
1630 CurKey
->NextKey
= KeyToRemove
->NextKey
;
1633 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
1637 CmiScanKeyList(PWSTR KeyName
)
1642 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
1643 CurKey
= CmiKeyList
;
1644 while (CurKey
!= NULL
&& wcscmp(KeyName
, CurKey
->Name
) != 0)
1646 CurKey
= CurKey
->NextKey
;
1648 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
1653 static PREGISTRY_FILE
1654 CmiCreateRegistry(PWSTR Filename
)
1656 PREGISTRY_FILE RegistryFile
;
1657 PKEY_BLOCK RootKeyBlock
;
1659 RegistryFile
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_FILE
));
1660 if (Filename
!= NULL
)
1663 /* FIXME: Duplicate Filename */
1664 /* FIXME: if file does not exist, create new file */
1665 /* FIXME: else attempt to map the file */
1669 RegistryFile
->Filename
= NULL
;
1670 RegistryFile
->FileHandle
= NULL
;
1672 RegistryFile
->HeaderBlock
= (PHEADER_BLOCK
)
1673 ExAllocatePool(NonPagedPool
, sizeof(HEADER_BLOCK
));
1674 RtlZeroMemory(RegistryFile
->HeaderBlock
, sizeof(HEADER_BLOCK
));
1675 RegistryFile
->HeaderBlock
->BlockId
= 0x66676572;
1676 RegistryFile
->HeaderBlock
->DateModified
.QuadPart
= 0;
1677 RegistryFile
->HeaderBlock
->Unused2
= 1;
1678 RegistryFile
->HeaderBlock
->Unused3
= 3;
1679 RegistryFile
->HeaderBlock
->Unused5
= 1;
1680 RegistryFile
->HeaderBlock
->RootKeyBlock
= 0;
1681 RegistryFile
->HeaderBlock
->BlockSize
= REG_BLOCK_SIZE
;
1682 RegistryFile
->HeaderBlock
->Unused6
= 1;
1683 RegistryFile
->HeaderBlock
->Checksum
= 0;
1684 RootKeyBlock
= (PKEY_BLOCK
)
1685 ExAllocatePool(NonPagedPool
, sizeof(KEY_BLOCK
));
1686 RtlZeroMemory(RootKeyBlock
, sizeof(KEY_BLOCK
));
1687 RootKeyBlock
->SubBlockId
= REG_KEY_BLOCK_ID
;
1688 RootKeyBlock
->Type
= REG_ROOT_KEY_BLOCK_TYPE
;
1689 ZwQuerySystemTime((PTIME
) &RootKeyBlock
->LastWriteTime
);
1690 RootKeyBlock
->ParentKeyOffset
= 0;
1691 RootKeyBlock
->NumberOfSubKeys
= 0;
1692 RootKeyBlock
->HashTableOffset
= 0;
1693 RootKeyBlock
->NumberOfValues
= 0;
1694 RootKeyBlock
->ValuesOffset
= 0;
1695 RootKeyBlock
->SecurityKeyOffset
= 0;
1696 RootKeyBlock
->ClassNameOffset
= sizeof(KEY_BLOCK
);
1697 RootKeyBlock
->NameSize
= 0;
1698 RootKeyBlock
->ClassSize
= 0;
1699 RootKeyBlock
->Name
[0] = 0;
1700 RegistryFile
->HeaderBlock
->RootKeyBlock
= (BLOCK_OFFSET
) RootKeyBlock
;
1703 return RegistryFile
;
1707 CmiCreateKey(IN PREGISTRY_FILE RegistryFile
,
1708 IN PWSTR KeyNameBuf
,
1709 OUT PKEY_BLOCK
*KeyBlock
,
1710 IN ACCESS_MASK DesiredAccess
,
1711 IN ULONG TitleIndex
,
1712 IN PUNICODE_STRING Class
,
1713 IN ULONG CreateOptions
,
1714 OUT PULONG Disposition
)
1716 /* FIXME: this should be allocated based on the largest subkey name */
1718 WCHAR CurKeyName
[256];
1720 PWSTR Remainder
, NextSlash
;
1721 PKEY_BLOCK CurKeyBlock
, SubKeyBlock
;
1723 /* FIXME: Should handle search by Class/TitleIndex */
1726 /* Loop through each key level and find or build the needed subkey */
1727 Status
= STATUS_SUCCESS
;
1728 /* FIXME: this access of RootKeyBlock should be guarded by spinlock */
1729 CurKeyBlock
= CmiGetKeyBlock(RegistryFile
,
1730 RegistryFile
->HeaderBlock
->RootKeyBlock
);
1732 Remainder
= KeyNameBuf
;
1733 while (NT_SUCCESS(Status
) &&
1734 (NextSlash
= wcschr(Remainder
, L
'\\')) != NULL
)
1736 /* Copy just the current subkey name to a buffer */
1737 wcsncpy(CurKeyName
, Remainder
, NextSlash
- Remainder
);
1738 CurKeyName
[NextSlash
- Remainder
] = 0;
1740 /* Verify existance of/Create CurKeyName */
1742 Status
= CmiScanForSubKey(RegistryFile
,
1747 if (!NT_SUCCESS(Status
))
1751 if (SubKeyBlock
== NULL
)
1753 Status
= CmiAddSubKey(RegistryFile
,
1760 if (!NT_SUCCESS(Status
))
1765 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1766 CurKeyBlock
= SubKeyBlock
;
1768 Remainder
= NextSlash
+ 1;
1771 if (NT_SUCCESS(Status
))
1774 Status
= CmiScanForSubKey(RegistryFile
,
1779 if (NT_SUCCESS(Status
))
1781 if (SubKeyBlock
== NULL
)
1785 ClassName
= ExAllocatePool(NonPagedPool
, Class
->Length
+ 1);
1786 wcsncpy(ClassName
, Class
->Buffer
, Class
->Length
);
1787 ClassName
[Class
->Length
] = 0;
1793 Status
= CmiAddSubKey(RegistryFile
,
1800 if (ClassName
!= NULL
)
1802 ExFreePool(ClassName
);
1804 if (NT_SUCCESS(Status
) && Disposition
!= NULL
)
1806 *Disposition
= REG_CREATED_NEW_KEY
;
1809 else if (Disposition
!= NULL
)
1811 *Disposition
= REG_OPENED_EXISTING_KEY
;
1814 *KeyBlock
= SubKeyBlock
;
1816 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1822 CmiFindKey(IN PREGISTRY_FILE RegistryFile
,
1823 IN PWSTR KeyNameBuf
,
1824 OUT PKEY_BLOCK
*KeyBlock
,
1825 IN ACCESS_MASK DesiredAccess
,
1826 IN ULONG TitleIndex
,
1827 IN PUNICODE_STRING Class
)
1829 /* FIXME: this should be allocated based on the largest subkey name */
1831 WCHAR CurKeyName
[256];
1832 PWSTR Remainder
, NextSlash
;
1833 PKEY_BLOCK CurKeyBlock
, SubKeyBlock
;
1835 /* FIXME: Should handle search by Class/TitleIndex */
1837 /* Loop through each key level and find the needed subkey */
1838 Status
= STATUS_SUCCESS
;
1839 /* FIXME: this access of RootKeyBlock should be guarded by spinlock */
1840 CurKeyBlock
= CmiGetKeyBlock(RegistryFile
, RegistryFile
->HeaderBlock
->RootKeyBlock
);
1841 Remainder
= KeyNameBuf
;
1842 while (NT_SUCCESS(Status
) &&
1843 (NextSlash
= wcschr(Remainder
, L
'\\')) != NULL
)
1845 /* Copy just the current subkey name to a buffer */
1846 wcsncpy(CurKeyName
, Remainder
, NextSlash
- Remainder
);
1847 CurKeyName
[NextSlash
- Remainder
] = 0;
1849 /* Verify existance of CurKeyName */
1850 Status
= CmiScanForSubKey(RegistryFile
,
1855 if (!NT_SUCCESS(Status
))
1859 if (SubKeyBlock
== NULL
)
1861 Status
= STATUS_UNSUCCESSFUL
;
1864 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1865 CurKeyBlock
= SubKeyBlock
;
1867 Remainder
= NextSlash
+ 1;
1869 if (NT_SUCCESS(Status
))
1871 Status
= CmiScanForSubKey(RegistryFile
,
1876 if (NT_SUCCESS(Status
))
1878 if (SubKeyBlock
== NULL
)
1880 Status
= STATUS_UNSUCCESSFUL
;
1884 *KeyBlock
= SubKeyBlock
;
1888 CmiReleaseBlock(RegistryFile
, CurKeyBlock
);
1894 CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile
,
1895 PKEY_BLOCK KeyBlock
)
1898 PHASH_TABLE_BLOCK HashBlock
;
1899 PKEY_BLOCK CurSubKeyBlock
;
1902 HashBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
1907 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
1909 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0)
1911 CurSubKeyBlock
= CmiGetKeyBlock(RegistryFile
,
1912 HashBlock
->Table
[Idx
].KeyOffset
);
1913 if (MaxName
< CurSubKeyBlock
->NameSize
)
1915 MaxName
= CurSubKeyBlock
->NameSize
;
1917 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
1921 CmiReleaseBlock(RegistryFile
, HashBlock
);
1927 CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile
,
1928 PKEY_BLOCK KeyBlock
)
1930 ULONG Idx
, MaxClass
;
1931 PHASH_TABLE_BLOCK HashBlock
;
1932 PKEY_BLOCK CurSubKeyBlock
;
1935 HashBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
1940 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
1942 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0)
1944 CurSubKeyBlock
= CmiGetKeyBlock(RegistryFile
,
1945 HashBlock
->Table
[Idx
].KeyOffset
);
1946 if (MaxClass
< CurSubKeyBlock
->ClassSize
)
1948 MaxClass
= CurSubKeyBlock
->ClassSize
;
1950 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
1954 CmiReleaseBlock(RegistryFile
, HashBlock
);
1960 CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile
,
1961 PKEY_BLOCK KeyBlock
)
1963 ULONG Idx
, MaxValueName
;
1964 PVALUE_LIST_BLOCK ValueListBlock
;
1965 PVALUE_BLOCK CurValueBlock
;
1967 ValueListBlock
= CmiGetBlock(RegistryFile
,
1968 KeyBlock
->ValuesOffset
);
1970 if (ValueListBlock
== 0)
1974 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
1976 CurValueBlock
= CmiGetBlock(RegistryFile
,
1977 ValueListBlock
->Values
[Idx
]);
1978 if (CurValueBlock
!= NULL
&&
1979 MaxValueName
< CurValueBlock
->NameSize
)
1981 MaxValueName
= CurValueBlock
->NameSize
;
1983 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
1986 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
1988 return MaxValueName
;
1992 CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile
,
1993 PKEY_BLOCK KeyBlock
)
1995 ULONG Idx
, MaxValueData
;
1996 PVALUE_LIST_BLOCK ValueListBlock
;
1997 PVALUE_BLOCK CurValueBlock
;
1999 ValueListBlock
= CmiGetBlock(RegistryFile
,
2000 KeyBlock
->ValuesOffset
);
2002 if (ValueListBlock
== 0)
2006 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
2008 CurValueBlock
= CmiGetBlock(RegistryFile
,
2009 ValueListBlock
->Values
[Idx
]);
2010 if (CurValueBlock
!= NULL
&&
2011 MaxValueData
< CurValueBlock
->DataSize
)
2013 MaxValueData
= CurValueBlock
->DataSize
;
2015 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
2018 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2020 return MaxValueData
;
2024 CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile
,
2025 IN PKEY_BLOCK KeyBlock
,
2026 OUT PKEY_BLOCK
*SubKeyBlock
,
2028 IN ACCESS_MASK DesiredAccess
)
2031 PHASH_TABLE_BLOCK HashBlock
;
2032 PKEY_BLOCK CurSubKeyBlock
;
2034 HashBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
2035 *SubKeyBlock
= NULL
;
2038 return STATUS_SUCCESS
;
2040 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
2042 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0 &&
2043 !wcsncmp(KeyName
, (PWSTR
) &HashBlock
->Table
[Idx
].HashValue
, 4))
2045 CurSubKeyBlock
= CmiGetKeyBlock(RegistryFile
,
2046 HashBlock
->Table
[Idx
].KeyOffset
);
2047 if (!wcscmp(KeyName
, CurSubKeyBlock
->Name
))
2049 *SubKeyBlock
= CurSubKeyBlock
;
2054 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
2059 CmiReleaseBlock(RegistryFile
, HashBlock
);
2061 return STATUS_SUCCESS
;
2065 CmiAddSubKey(PREGISTRY_FILE RegistryFile
,
2066 PKEY_BLOCK KeyBlock
,
2067 PKEY_BLOCK
*SubKeyBlock
,
2068 PWSTR NewSubKeyName
,
2071 ULONG CreateOptions
)
2074 PHASH_TABLE_BLOCK HashBlock
, NewHashBlock
;
2075 PKEY_BLOCK NewKeyBlock
;
2077 Status
= CmiAllocateKeyBlock(RegistryFile
,
2083 if (!NT_SUCCESS(Status
))
2087 if (KeyBlock
->HashTableOffset
== 0)
2089 Status
= CmiAllocateHashTableBlock(RegistryFile
,
2091 REG_INIT_HASH_TABLE_SIZE
);
2092 if (!NT_SUCCESS(Status
))
2096 KeyBlock
->HashTableOffset
= CmiGetBlockOffset(RegistryFile
, HashBlock
);
2100 HashBlock
= CmiGetHashTableBlock(RegistryFile
, KeyBlock
->HashTableOffset
);
2101 if (KeyBlock
->NumberOfSubKeys
+ 1 >= HashBlock
->HashTableSize
)
2104 /* FIXME: All Subkeys will need to be rehashed here! */
2106 /* Reallocate the hash table block */
2107 Status
= CmiAllocateHashTableBlock(RegistryFile
,
2109 HashBlock
->HashTableSize
+
2110 REG_EXTEND_HASH_TABLE_SIZE
);
2111 if (!NT_SUCCESS(Status
))
2115 RtlZeroMemory(&NewHashBlock
->Table
[0],
2116 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
2117 RtlCopyMemory(&NewHashBlock
->Table
[0],
2118 &HashBlock
->Table
[0],
2119 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
2120 KeyBlock
->HashTableOffset
= CmiGetBlockOffset(RegistryFile
, NewHashBlock
);
2121 CmiDestroyHashTableBlock(RegistryFile
, HashBlock
);
2122 HashBlock
= NewHashBlock
;
2125 Status
= CmiAddKeyToHashTable(RegistryFile
, HashBlock
, NewKeyBlock
);
2126 if (NT_SUCCESS(Status
))
2128 KeyBlock
->NumberOfSubKeys
++;
2129 *SubKeyBlock
= NewKeyBlock
;
2131 CmiReleaseBlock(RegistryFile
, HashBlock
);
2137 CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile
,
2138 IN PKEY_BLOCK KeyBlock
,
2140 OUT PVALUE_BLOCK
*ValueBlock
)
2143 PVALUE_LIST_BLOCK ValueListBlock
;
2144 PVALUE_BLOCK CurValueBlock
;
2146 ValueListBlock
= CmiGetBlock(RegistryFile
,
2147 KeyBlock
->ValuesOffset
);
2149 if (ValueListBlock
== 0)
2151 return STATUS_SUCCESS
;
2153 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
2155 CurValueBlock
= CmiGetBlock(RegistryFile
,
2156 ValueListBlock
->Values
[Idx
]);
2157 if (CurValueBlock
!= NULL
&&
2158 !wcscmp(CurValueBlock
->Name
, ValueName
))
2160 *ValueBlock
= CurValueBlock
;
2163 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
2166 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2168 return STATUS_SUCCESS
;
2172 CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile
,
2173 IN PKEY_BLOCK KeyBlock
,
2174 IN PWSTR ValueNameBuf
,
2180 PVALUE_LIST_BLOCK ValueListBlock
, NewValueListBlock
;
2181 PVALUE_BLOCK ValueBlock
;
2183 Status
= CmiAllocateValueBlock(RegistryFile
,
2189 if (!NT_SUCCESS(Status
))
2193 ValueListBlock
= CmiGetBlock(RegistryFile
,
2194 KeyBlock
->ValuesOffset
);
2195 if (ValueListBlock
== NULL
)
2197 Status
= CmiAllocateBlock(RegistryFile
,
2198 (PVOID
) &ValueListBlock
,
2199 sizeof(BLOCK_OFFSET
) *
2200 REG_VALUE_LIST_BLOCK_MULTIPLE
);
2201 if (!NT_SUCCESS(Status
))
2203 CmiDestroyValueBlock(RegistryFile
,
2208 else if (KeyBlock
->NumberOfValues
% REG_VALUE_LIST_BLOCK_MULTIPLE
)
2210 Status
= CmiAllocateBlock(RegistryFile
,
2211 (PVOID
) &NewValueListBlock
,
2212 sizeof(BLOCK_OFFSET
) *
2213 (KeyBlock
->NumberOfValues
+
2214 REG_VALUE_LIST_BLOCK_MULTIPLE
));
2215 if (!NT_SUCCESS(Status
))
2217 CmiDestroyValueBlock(RegistryFile
,
2221 RtlCopyMemory(NewValueListBlock
,
2223 sizeof(BLOCK_OFFSET
) * KeyBlock
->NumberOfValues
);
2224 KeyBlock
->ValuesOffset
= CmiGetBlockOffset(RegistryFile
,
2226 CmiDestroyBlock(RegistryFile
, ValueListBlock
);
2227 ValueListBlock
= NewValueListBlock
;
2229 ValueListBlock
->Values
[KeyBlock
->NumberOfValues
] =
2230 CmiGetBlockOffset(RegistryFile
, ValueBlock
);
2231 KeyBlock
->NumberOfValues
++;
2232 CmiReleaseBlock(RegistryFile
, ValueBlock
);
2233 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2235 return STATUS_SUCCESS
;
2239 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile
,
2240 IN PKEY_BLOCK KeyBlock
,
2244 PVALUE_LIST_BLOCK ValueListBlock
;
2245 PVALUE_BLOCK CurValueBlock
;
2247 ValueListBlock
= CmiGetBlock(RegistryFile
,
2248 KeyBlock
->ValuesOffset
);
2249 if (ValueListBlock
== 0)
2251 return STATUS_SUCCESS
;
2253 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
2255 CurValueBlock
= CmiGetBlock(RegistryFile
,
2256 ValueListBlock
->Values
[Idx
]);
2257 if (CurValueBlock
!= NULL
&&
2258 !wcscmp(CurValueBlock
->Name
, ValueName
))
2260 if (KeyBlock
->NumberOfValues
- 1 < Idx
)
2262 RtlCopyMemory(&ValueListBlock
->Values
[Idx
],
2263 &ValueListBlock
->Values
[Idx
+ 1],
2264 sizeof(BLOCK_OFFSET
) *
2265 (KeyBlock
->NumberOfValues
- 1 - Idx
));
2269 RtlZeroMemory(&ValueListBlock
->Values
[Idx
],
2270 sizeof(BLOCK_OFFSET
));
2272 KeyBlock
->NumberOfValues
-= 1;
2273 CmiDestroyValueBlock(RegistryFile
, CurValueBlock
);
2277 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
2280 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
2282 return STATUS_SUCCESS
;
2286 CmiAllocateKeyBlock(IN PREGISTRY_FILE RegistryFile
,
2287 OUT PKEY_BLOCK
*KeyBlock
,
2289 IN ULONG TitleIndex
,
2291 IN ULONG CreateOptions
)
2295 PKEY_BLOCK NewKeyBlock
;
2297 Status
= STATUS_SUCCESS
;
2299 /* Handle volatile files first */
2300 if (RegistryFile
->Filename
== NULL
)
2302 NewKeySize
= sizeof(KEY_BLOCK
) +
2303 (wcslen(KeyName
) + 1) * sizeof(WCHAR
) +
2304 (Class
!= NULL
? (wcslen(Class
) + 1) * sizeof(WCHAR
) : 0);
2305 NewKeyBlock
= ExAllocatePool(NonPagedPool
, NewKeySize
);
2306 if (NewKeyBlock
== NULL
)
2308 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2312 RtlZeroMemory(NewKeyBlock
, NewKeySize
);
2313 NewKeyBlock
->SubBlockId
= REG_KEY_BLOCK_ID
;
2314 NewKeyBlock
->Type
= REG_KEY_BLOCK_TYPE
;
2315 ZwQuerySystemTime((PTIME
) &NewKeyBlock
->LastWriteTime
);
2316 NewKeyBlock
->ParentKeyOffset
= 0;
2317 NewKeyBlock
->NumberOfSubKeys
= 0;
2318 NewKeyBlock
->HashTableOffset
= 0;
2319 NewKeyBlock
->NumberOfValues
= 0;
2320 NewKeyBlock
->ValuesOffset
= 0;
2321 NewKeyBlock
->SecurityKeyOffset
= 0;
2322 NewKeyBlock
->ClassNameOffset
= sizeof(KEY_BLOCK
) + wcslen(KeyName
);
2323 NewKeyBlock
->NameSize
= wcslen(KeyName
);
2324 NewKeyBlock
->ClassSize
= (Class
!= NULL
) ? wcslen(Class
) : 0;
2325 wcscpy(NewKeyBlock
->Name
, KeyName
);
2328 wcscpy(&NewKeyBlock
->Name
[wcslen(KeyName
) + 1], Class
);
2330 CmiLockBlock(RegistryFile
, NewKeyBlock
);
2331 *KeyBlock
= NewKeyBlock
;
2343 CmiGetKeyBlock(PREGISTRY_FILE RegistryFile
,
2344 BLOCK_OFFSET KeyBlockOffset
)
2346 PKEY_BLOCK KeyBlock
;
2348 if (RegistryFile
->Filename
== NULL
)
2350 CmiLockBlock(RegistryFile
, (PVOID
) KeyBlockOffset
);
2352 KeyBlock
= (PKEY_BLOCK
) KeyBlockOffset
;
2363 CmiDestroyKeyBlock(PREGISTRY_FILE RegistryFile
,
2364 PKEY_BLOCK KeyBlock
)
2368 Status
= STATUS_SUCCESS
;
2370 if (RegistryFile
->Filename
== NULL
)
2372 CmiReleaseBlock(RegistryFile
, KeyBlock
);
2373 ExFreePool(KeyBlock
);
2384 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile
,
2385 OUT PHASH_TABLE_BLOCK
*HashBlock
,
2386 IN ULONG HashTableSize
)
2390 PHASH_TABLE_BLOCK NewHashBlock
;
2392 Status
= STATUS_SUCCESS
;
2394 /* Handle volatile files first */
2395 if (RegistryFile
->Filename
== NULL
)
2397 NewHashSize
= sizeof(HASH_TABLE_BLOCK
) +
2398 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
2399 NewHashBlock
= ExAllocatePool(NonPagedPool
, NewHashSize
);
2400 if (NewHashBlock
== NULL
)
2402 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2406 RtlZeroMemory(NewHashBlock
, NewHashSize
);
2407 NewHashBlock
->SubBlockId
= REG_HASH_TABLE_BLOCK_ID
;
2408 NewHashBlock
->HashTableSize
= HashTableSize
;
2409 CmiLockBlock(RegistryFile
, NewHashBlock
);
2410 *HashBlock
= NewHashBlock
;
2421 static PHASH_TABLE_BLOCK
2422 CmiGetHashTableBlock(PREGISTRY_FILE RegistryFile
,
2423 BLOCK_OFFSET HashBlockOffset
)
2425 PHASH_TABLE_BLOCK HashBlock
;
2427 if (RegistryFile
->Filename
== NULL
)
2429 CmiLockBlock(RegistryFile
, (PVOID
) HashBlockOffset
);
2431 HashBlock
= (PHASH_TABLE_BLOCK
) HashBlockOffset
;
2442 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile
,
2443 PHASH_TABLE_BLOCK HashBlock
,
2446 PKEY_BLOCK KeyBlock
;
2448 if (RegistryFile
->Filename
== NULL
)
2450 KeyBlock
= (PKEY_BLOCK
) HashBlock
->Table
[Index
].KeyOffset
;
2451 CmiLockBlock(RegistryFile
, KeyBlock
);
2462 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile
,
2463 PHASH_TABLE_BLOCK HashBlock
,
2464 PKEY_BLOCK NewKeyBlock
)
2466 HashBlock
->Table
[HashBlock
->HashTableSize
].KeyOffset
=
2467 CmiGetBlockOffset(RegistryFile
, NewKeyBlock
);
2468 RtlCopyMemory(&HashBlock
->Table
[HashBlock
->HashTableSize
].HashValue
,
2471 HashBlock
->HashTableSize
++;
2473 return STATUS_SUCCESS
;
2477 CmiDestroyHashTableBlock(PREGISTRY_FILE RegistryFile
,
2478 PHASH_TABLE_BLOCK HashBlock
)
2482 Status
= STATUS_SUCCESS
;
2484 if (RegistryFile
->Filename
== NULL
)
2486 CmiReleaseBlock(RegistryFile
, HashBlock
);
2487 ExFreePool(HashBlock
);
2491 Status
= STATUS_NOT_IMPLEMENTED
;
2498 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile
,
2499 PVALUE_BLOCK
*ValueBlock
,
2500 IN PWSTR ValueNameBuf
,
2507 PVALUE_BLOCK NewValueBlock
;
2510 Status
= STATUS_SUCCESS
;
2512 /* Handle volatile files first */
2513 if (RegistryFile
->Filename
== NULL
)
2515 NewValueSize
= sizeof(VALUE_BLOCK
) + wcslen(ValueNameBuf
);
2516 NewValueBlock
= ExAllocatePool(NonPagedPool
, NewValueSize
);
2517 if (NewValueBlock
== NULL
)
2519 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2523 RtlZeroMemory(NewValueBlock
, NewValueSize
);
2524 NewValueBlock
->SubBlockId
= REG_VALUE_BLOCK_ID
;
2525 NewValueBlock
->NameSize
= wcslen(ValueNameBuf
);
2526 wcscpy(NewValueBlock
->Name
, ValueNameBuf
);
2527 NewValueBlock
->DataType
= Type
;
2528 NewValueBlock
->DataSize
= DataSize
;
2529 Status
= CmiAllocateBlock(RegistryFile
,
2532 if (!NT_SUCCESS(Status
))
2534 ExFreePool(NewValueBlock
);
2538 RtlCopyMemory(DataBlock
, Data
, DataSize
);
2539 NewValueBlock
->DataOffset
= CmiGetBlockOffset(RegistryFile
,
2541 CmiLockBlock(RegistryFile
, NewValueBlock
);
2542 CmiReleaseBlock(RegistryFile
, DataBlock
);
2543 *ValueBlock
= NewValueBlock
;
2549 Status
= STATUS_NOT_IMPLEMENTED
;
2556 CmiReplaceValueData(IN PREGISTRY_FILE RegistryFile
,
2557 IN PVALUE_BLOCK ValueBlock
,
2563 PVOID DataBlock
, NewDataBlock
;
2565 Status
= STATUS_SUCCESS
;
2567 /* If new data size is <= current then overwrite current data */
2568 if (DataSize
<= ValueBlock
->DataSize
)
2570 DataBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
);
2571 RtlCopyMemory(DataBlock
, Data
, DataSize
);
2572 ValueBlock
->DataSize
= DataSize
;
2573 ValueBlock
->DataType
= Type
;
2574 CmiReleaseBlock(RegistryFile
, DataBlock
);
2578 /* Destroy current data block and allocate a new one */
2579 DataBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
);
2580 Status
= CmiAllocateBlock(RegistryFile
,
2583 RtlCopyMemory(NewDataBlock
, Data
, DataSize
);
2584 ValueBlock
->DataOffset
= CmiGetBlockOffset(RegistryFile
, DataBlock
);
2585 ValueBlock
->DataSize
= DataSize
;
2586 ValueBlock
->DataType
= Type
;
2587 CmiReleaseBlock(RegistryFile
, NewDataBlock
);
2588 CmiDestroyBlock(RegistryFile
, DataBlock
);
2595 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile
,
2596 PVALUE_BLOCK ValueBlock
)
2600 Status
= CmiDestroyBlock(RegistryFile
,
2601 CmiGetBlock(RegistryFile
,
2602 ValueBlock
->DataOffset
));
2603 if (!NT_SUCCESS(Status
))
2607 return CmiDestroyBlock(RegistryFile
, ValueBlock
);
2611 CmiAllocateBlock(PREGISTRY_FILE RegistryFile
,
2618 Status
= STATUS_SUCCESS
;
2620 /* Handle volatile files first */
2621 if (RegistryFile
->Filename
== NULL
)
2623 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
2624 if (NewBlock
== NULL
)
2626 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2630 RtlZeroMemory(NewBlock
, BlockSize
);
2631 CmiLockBlock(RegistryFile
, NewBlock
);
2637 Status
= STATUS_NOT_IMPLEMENTED
;
2644 CmiDestroyBlock(PREGISTRY_FILE RegistryFile
,
2649 Status
= STATUS_SUCCESS
;
2651 if (RegistryFile
->Filename
== NULL
)
2653 CmiReleaseBlock(RegistryFile
, Block
);
2658 Status
= STATUS_NOT_IMPLEMENTED
;
2665 CmiGetBlock(PREGISTRY_FILE RegistryFile
,
2666 BLOCK_OFFSET BlockOffset
)
2671 if (RegistryFile
->Filename
== NULL
)
2673 CmiLockBlock(RegistryFile
, (PVOID
) BlockOffset
);
2675 Block
= (PVOID
) BlockOffset
;
2686 CmiGetBlockOffset(PREGISTRY_FILE RegistryFile
,
2689 BLOCK_OFFSET BlockOffset
;
2691 if (RegistryFile
->Filename
== NULL
)
2693 BlockOffset
= (BLOCK_OFFSET
) Block
;
2704 CmiLockBlock(PREGISTRY_FILE RegistryFile
,
2707 if (RegistryFile
->Filename
!= NULL
)
2714 CmiReleaseBlock(PREGISTRY_FILE RegistryFile
,
2717 if (RegistryFile
->Filename
!= NULL
)