2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/ntfunc.c
5 * PURPOSE: Ntxxx function for registry access
9 /* INCLUDES *****************************************************************/
13 #include <internal/debug.h>
18 /* GLOBALS ******************************************************************/
20 extern POBJECT_TYPE CmiKeyType
;
21 extern PREGISTRY_HIVE CmiVolatileHive
;
23 static BOOLEAN CmiRegistryInitialized
= FALSE
;
26 /* FUNCTIONS ****************************************************************/
32 CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function
,
34 IN OUT PLARGE_INTEGER Cookie
38 return STATUS_NOT_IMPLEMENTED
;
46 CmUnRegisterCallback(IN LARGE_INTEGER Cookie
)
49 return STATUS_NOT_IMPLEMENTED
;
54 NtCreateKey(OUT PHANDLE KeyHandle
,
55 IN ACCESS_MASK DesiredAccess
,
56 IN POBJECT_ATTRIBUTES ObjectAttributes
,
58 IN PUNICODE_STRING Class
,
59 IN ULONG CreateOptions
,
60 OUT PULONG Disposition
)
62 UNICODE_STRING RemainingPath
;
63 PKEY_OBJECT KeyObject
;
69 DPRINT("NtCreateKey (Name %wZ KeyHandle %x Root %x)\n",
70 ObjectAttributes
->ObjectName
,
72 ObjectAttributes
->RootDirectory
);
74 Status
= ObFindObject(ObjectAttributes
,
78 if (!NT_SUCCESS(Status
))
83 DPRINT("RemainingPath %wZ\n", &RemainingPath
);
85 if ((RemainingPath
.Buffer
== NULL
) || (RemainingPath
.Buffer
[0] == 0))
87 /* Fail if the key has been deleted */
88 if (((PKEY_OBJECT
) Object
)->Flags
& KO_MARKED_FOR_DELETE
)
90 ObDereferenceObject(Object
);
91 RtlFreeUnicodeString(&RemainingPath
);
92 return(STATUS_UNSUCCESSFUL
);
96 *Disposition
= REG_OPENED_EXISTING_KEY
;
98 Status
= ObCreateHandle(PsGetCurrentProcess(),
104 DPRINT("Status %x\n", Status
);
105 ObDereferenceObject(Object
);
106 RtlFreeUnicodeString(&RemainingPath
);
110 /* If RemainingPath contains \ we must return error
111 because NtCreateKey don't create trees */
112 Start
= RemainingPath
.Buffer
;
116 End
= wcschr(Start
, L
'\\');
119 ObDereferenceObject(Object
);
120 RtlFreeUnicodeString(&RemainingPath
);
121 return STATUS_OBJECT_NAME_NOT_FOUND
;
124 DPRINT("RemainingPath %S ParentObject %x\n", RemainingPath
.Buffer
, Object
);
126 Status
= ObCreateObject(ExGetPreviousMode(),
135 if (!NT_SUCCESS(Status
))
140 Status
= ObInsertObject((PVOID
)KeyObject
,
146 if (!NT_SUCCESS(Status
))
148 ObDereferenceObject(KeyObject
);
149 RtlFreeUnicodeString(&RemainingPath
);
153 KeyObject
->ParentKey
= Object
;
155 if (CreateOptions
& REG_OPTION_VOLATILE
)
156 KeyObject
->RegistryHive
= CmiVolatileHive
;
158 KeyObject
->RegistryHive
= KeyObject
->ParentKey
->RegistryHive
;
160 KeyObject
->Flags
= 0;
161 KeyObject
->NumberOfSubKeys
= 0;
162 KeyObject
->SizeOfSubKeys
= 0;
163 KeyObject
->SubKeys
= NULL
;
165 /* Acquire hive lock */
166 KeEnterCriticalRegion();
167 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
169 /* add key to subkeys of parent if needed */
170 Status
= CmiAddSubKey(KeyObject
->RegistryHive
,
171 KeyObject
->ParentKey
,
177 if (!NT_SUCCESS(Status
))
179 DPRINT("CmiAddSubKey() failed (Status %lx)\n", Status
);
180 /* Release hive lock */
181 ExReleaseResourceLite(&CmiRegistryLock
);
182 KeLeaveCriticalRegion();
183 ObDereferenceObject(KeyObject
);
184 ObDereferenceObject(Object
);
185 RtlFreeUnicodeString(&RemainingPath
);
186 return STATUS_UNSUCCESSFUL
;
189 if (Start
== RemainingPath
.Buffer
)
191 KeyObject
->Name
= RemainingPath
;
195 RtlCreateUnicodeString(&KeyObject
->Name
,
197 RtlFreeUnicodeString(&RemainingPath
);
200 if (KeyObject
->RegistryHive
== KeyObject
->ParentKey
->RegistryHive
)
202 KeyObject
->KeyCell
->ParentKeyOffset
= KeyObject
->ParentKey
->KeyCellOffset
;
203 KeyObject
->KeyCell
->SecurityKeyOffset
= KeyObject
->ParentKey
->KeyCell
->SecurityKeyOffset
;
207 KeyObject
->KeyCell
->ParentKeyOffset
= -1;
208 KeyObject
->KeyCell
->SecurityKeyOffset
= -1;
209 /* This key must remain in memory unless it is deleted
210 or file is unloaded */
211 ObReferenceObjectByPointer(KeyObject
,
212 STANDARD_RIGHTS_REQUIRED
,
217 CmiAddKeyToList(KeyObject
->ParentKey
, KeyObject
);
219 VERIFY_KEY_OBJECT(KeyObject
);
221 /* Release hive lock */
222 ExReleaseResourceLite(&CmiRegistryLock
);
223 KeLeaveCriticalRegion();
225 ObDereferenceObject(KeyObject
);
226 ObDereferenceObject(Object
);
229 *Disposition
= REG_CREATED_NEW_KEY
;
238 NtDeleteKey(IN HANDLE KeyHandle
)
240 PKEY_OBJECT KeyObject
;
243 DPRINT1("NtDeleteKey(KeyHandle %x) called\n", KeyHandle
);
245 /* Verify that the handle is valid and is a registry key */
246 Status
= ObReferenceObjectByHandle(KeyHandle
,
252 if (!NT_SUCCESS(Status
))
254 DPRINT1("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
258 /* Acquire hive lock */
259 KeEnterCriticalRegion();
260 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
262 VERIFY_KEY_OBJECT(KeyObject
);
264 /* Check for subkeys */
265 if (KeyObject
->NumberOfSubKeys
!= 0)
267 Status
= STATUS_CANNOT_DELETE
;
271 /* Set the marked for delete bit in the key object */
272 KeyObject
->Flags
|= KO_MARKED_FOR_DELETE
;
273 Status
= STATUS_SUCCESS
;
276 /* Release hive lock */
277 ExReleaseResourceLite(&CmiRegistryLock
);
278 KeLeaveCriticalRegion();
280 DPRINT1("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
282 /* Dereference the object */
283 ObDereferenceObject(KeyObject
);
284 if (KeyObject
->RegistryHive
!= KeyObject
->ParentKey
->RegistryHive
)
285 ObDereferenceObject(KeyObject
);
287 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
288 DPRINT("HandleCount %lu\n", ObGetObjectHandleCount((PVOID
)KeyObject
));
292 * Hive-Synchronization will not be triggered here. This is done in
293 * CmiObjectDelete() (in regobj.c) after all key-related structures
294 * have been released.
302 NtEnumerateKey(IN HANDLE KeyHandle
,
304 IN KEY_INFORMATION_CLASS KeyInformationClass
,
305 OUT PVOID KeyInformation
,
307 OUT PULONG ResultLength
)
309 PKEY_OBJECT KeyObject
;
310 PKEY_OBJECT SubKeyObject
;
311 PREGISTRY_HIVE RegistryHive
;
312 PKEY_CELL KeyCell
, SubKeyCell
;
313 PHASH_TABLE_CELL HashTableBlock
;
314 PKEY_BASIC_INFORMATION BasicInformation
;
315 PKEY_NODE_INFORMATION NodeInformation
;
316 PKEY_FULL_INFORMATION FullInformation
;
317 PDATA_CELL ClassCell
;
318 ULONG NameSize
, ClassSize
;
321 DPRINT("KH %x I %d KIC %x KI %x L %d RL %x\n",
329 /* Verify that the handle is valid and is a registry key */
330 Status
= ObReferenceObjectByHandle(KeyHandle
,
331 KEY_ENUMERATE_SUB_KEYS
,
334 (PVOID
*) &KeyObject
,
336 if (!NT_SUCCESS(Status
))
338 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
342 /* Acquire hive lock */
343 KeEnterCriticalRegion();
344 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
346 VERIFY_KEY_OBJECT(KeyObject
);
348 /* Get pointer to KeyCell */
349 KeyCell
= KeyObject
->KeyCell
;
350 RegistryHive
= KeyObject
->RegistryHive
;
354 /* Check for hightest possible sub key index */
355 if (Index
>= KeyCell
->NumberOfSubKeys
+ KeyObject
->NumberOfSubKeys
)
357 ExReleaseResourceLite(&CmiRegistryLock
);
358 KeLeaveCriticalRegion();
359 ObDereferenceObject(KeyObject
);
360 DPRINT("No more volatile entries\n");
361 return STATUS_NO_MORE_ENTRIES
;
364 /* Get pointer to SubKey */
365 if (Index
>= KeyCell
->NumberOfSubKeys
)
367 PKEY_OBJECT CurKey
= NULL
;
371 /* Search for volatile or 'foreign' keys */
372 j
= KeyCell
->NumberOfSubKeys
;
373 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
375 CurKey
= KeyObject
->SubKeys
[i
];
376 if (CurKey
->RegistryHive
== CmiVolatileHive
||
377 CurKey
->RegistryHive
!= RegistryHive
)
385 if (i
>= KeyObject
->NumberOfSubKeys
)
387 ExReleaseResourceLite(&CmiRegistryLock
);
388 KeLeaveCriticalRegion();
389 ObDereferenceObject(KeyObject
);
390 DPRINT("No more non-volatile entries\n");
391 return STATUS_NO_MORE_ENTRIES
;
394 SubKeyObject
= CurKey
;
395 SubKeyCell
= CurKey
->KeyCell
;
399 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
401 ExReleaseResourceLite(&CmiRegistryLock
);
402 KeLeaveCriticalRegion();
403 ObDereferenceObject(KeyObject
);
404 return STATUS_NO_MORE_ENTRIES
;
407 HashTableBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
408 if (HashTableBlock
== NULL
)
410 DPRINT("CmiGetBlock() failed\n");
411 ExReleaseResourceLite(&CmiRegistryLock
);
412 KeLeaveCriticalRegion();
413 ObDereferenceObject(KeyObject
);
414 return STATUS_UNSUCCESSFUL
;
417 SubKeyCell
= CmiGetKeyFromHashByIndex(RegistryHive
,
422 if (SubKeyCell
== NULL
)
424 ExReleaseResourceLite(&CmiRegistryLock
);
425 KeLeaveCriticalRegion();
426 ObDereferenceObject(KeyObject
);
427 DPRINT("No more entries\n");
428 return STATUS_NO_MORE_ENTRIES
;
431 Status
= STATUS_SUCCESS
;
432 switch (KeyInformationClass
)
434 case KeyBasicInformation
:
435 /* Check size of buffer */
436 if (SubKeyObject
!= NULL
)
438 NameSize
= SubKeyObject
->Name
.Length
;
442 NameSize
= SubKeyCell
->NameSize
;
443 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
445 NameSize
*= sizeof(WCHAR
);
449 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) + NameSize
;
452 * NOTE: It's perfetly valid to call NtEnumerateKey to get
453 * all the information but name. Actually the NT4 sound
454 * framework does that while querying parameters from registry.
455 * -- Filip Navara, 19/07/2004
457 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
459 Status
= STATUS_BUFFER_TOO_SMALL
;
463 /* Fill buffer with requested info */
464 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
465 BasicInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
466 BasicInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
467 BasicInformation
->TitleIndex
= Index
;
468 BasicInformation
->NameLength
= NameSize
;
470 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) < NameSize
)
472 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
473 Status
= STATUS_BUFFER_OVERFLOW
;
477 if (SubKeyObject
!= NULL
)
479 RtlCopyMemory(BasicInformation
->Name
,
480 SubKeyObject
->Name
.Buffer
,
485 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
487 CmiCopyPackedName(BasicInformation
->Name
,
489 NameSize
/ sizeof(WCHAR
));
493 RtlCopyMemory(BasicInformation
->Name
,
501 case KeyNodeInformation
:
502 /* Check size of buffer */
503 if (SubKeyObject
!= NULL
)
505 NameSize
= SubKeyObject
->Name
.Length
;
509 NameSize
= SubKeyCell
->NameSize
;
510 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
512 NameSize
*= sizeof(WCHAR
);
515 ClassSize
= SubKeyCell
->ClassSize
;
517 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
518 NameSize
+ ClassSize
;
520 if (Length
< FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]))
522 Status
= STATUS_BUFFER_TOO_SMALL
;
526 /* Fill buffer with requested info */
527 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
528 NodeInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
529 NodeInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
530 NodeInformation
->TitleIndex
= Index
;
531 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) + NameSize
;
532 NodeInformation
->ClassLength
= SubKeyCell
->ClassSize
;
533 NodeInformation
->NameLength
= NameSize
;
535 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
537 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
539 Status
= STATUS_BUFFER_OVERFLOW
;
542 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
543 NameSize
< ClassSize
)
545 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
547 Status
= STATUS_BUFFER_OVERFLOW
;
551 if (SubKeyObject
!= NULL
)
553 RtlCopyMemory(NodeInformation
->Name
,
554 SubKeyObject
->Name
.Buffer
,
559 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
561 CmiCopyPackedName(NodeInformation
->Name
,
563 NameSize
/ sizeof(WCHAR
));
567 RtlCopyMemory(NodeInformation
->Name
,
575 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
576 SubKeyCell
->ClassNameOffset
,
578 RtlCopyMemory (NodeInformation
->Name
+ SubKeyCell
->NameSize
,
585 case KeyFullInformation
:
586 ClassSize
= SubKeyCell
->ClassSize
;
588 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) +
591 /* Check size of buffer */
592 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]))
594 Status
= STATUS_BUFFER_TOO_SMALL
;
598 /* Fill buffer with requested info */
599 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
600 FullInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
601 FullInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
602 FullInformation
->TitleIndex
= Index
;
603 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) -
605 FullInformation
->ClassLength
= SubKeyCell
->ClassSize
;
606 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //SubKeyCell->NumberOfSubKeys;
607 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
608 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
609 FullInformation
->Values
= SubKeyCell
->NumberOfValues
;
610 FullInformation
->MaxValueNameLen
=
611 CmiGetMaxValueNameLength(RegistryHive
, SubKeyCell
);
612 FullInformation
->MaxValueDataLen
=
613 CmiGetMaxValueDataLength(RegistryHive
, SubKeyCell
);
615 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
617 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
618 Status
= STATUS_BUFFER_OVERFLOW
;
624 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
625 SubKeyCell
->ClassNameOffset
,
627 RtlCopyMemory (FullInformation
->Class
,
635 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
639 ExReleaseResourceLite(&CmiRegistryLock
);
640 KeLeaveCriticalRegion();
641 ObDereferenceObject(KeyObject
);
643 DPRINT("Returning status %x\n", Status
);
650 NtEnumerateValueKey(IN HANDLE KeyHandle
,
652 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
653 OUT PVOID KeyValueInformation
,
655 OUT PULONG ResultLength
)
658 PKEY_OBJECT KeyObject
;
659 PREGISTRY_HIVE RegistryHive
;
661 PVALUE_CELL ValueCell
;
663 ULONG NameSize
, DataSize
;
664 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
665 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
666 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
668 DPRINT("KH %x I %d KVIC %x KVI %x L %d RL %x\n",
671 KeyValueInformationClass
,
676 /* Verify that the handle is valid and is a registry key */
677 Status
= ObReferenceObjectByHandle(KeyHandle
,
681 (PVOID
*) &KeyObject
,
684 if (!NT_SUCCESS(Status
))
689 /* Acquire hive lock */
690 KeEnterCriticalRegion();
691 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
693 VERIFY_KEY_OBJECT(KeyObject
);
695 /* Get pointer to KeyCell */
696 KeyCell
= KeyObject
->KeyCell
;
697 RegistryHive
= KeyObject
->RegistryHive
;
699 /* Get Value block of interest */
700 Status
= CmiGetValueFromKeyByIndex(RegistryHive
,
705 if (!NT_SUCCESS(Status
))
707 ExReleaseResourceLite(&CmiRegistryLock
);
708 KeLeaveCriticalRegion();
709 ObDereferenceObject(KeyObject
);
713 if (ValueCell
!= NULL
)
715 switch (KeyValueInformationClass
)
717 case KeyValueBasicInformation
:
718 NameSize
= ValueCell
->NameSize
;
719 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
721 NameSize
*= sizeof(WCHAR
);
724 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) + NameSize
;
726 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
728 Status
= STATUS_BUFFER_TOO_SMALL
;
732 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
734 ValueBasicInformation
->TitleIndex
= 0;
735 ValueBasicInformation
->Type
= ValueCell
->DataType
;
736 ValueBasicInformation
->NameLength
= NameSize
;
738 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
741 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
742 Status
= STATUS_BUFFER_OVERFLOW
;
746 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
748 CmiCopyPackedName(ValueBasicInformation
->Name
,
750 NameSize
/ sizeof(WCHAR
));
754 RtlCopyMemory(ValueBasicInformation
->Name
,
761 case KeyValuePartialInformation
:
762 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
764 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
767 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
769 Status
= STATUS_BUFFER_TOO_SMALL
;
773 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
775 ValuePartialInformation
->TitleIndex
= 0;
776 ValuePartialInformation
->Type
= ValueCell
->DataType
;
777 ValuePartialInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
779 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
782 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
783 Status
= STATUS_BUFFER_OVERFLOW
;
787 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
789 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
790 RtlCopyMemory(ValuePartialInformation
->Data
,
796 RtlCopyMemory(ValuePartialInformation
->Data
,
797 &ValueCell
->DataOffset
,
803 case KeyValueFullInformation
:
804 NameSize
= ValueCell
->NameSize
;
805 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
807 NameSize
*= sizeof(WCHAR
);
809 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
811 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
812 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
814 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
816 Status
= STATUS_BUFFER_TOO_SMALL
;
820 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
822 ValueFullInformation
->TitleIndex
= 0;
823 ValueFullInformation
->Type
= ValueCell
->DataType
;
824 ValueFullInformation
->NameLength
= NameSize
;
825 ValueFullInformation
->DataOffset
=
826 (ULONG_PTR
)ValueFullInformation
->Name
-
827 (ULONG_PTR
)ValueFullInformation
+
828 ValueFullInformation
->NameLength
;
829 ValueFullInformation
->DataOffset
=
830 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
831 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
833 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
836 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
838 Status
= STATUS_BUFFER_OVERFLOW
;
841 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
842 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
844 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) - NameSize
, sizeof(PVOID
));
845 Status
= STATUS_BUFFER_OVERFLOW
;
849 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
851 CmiCopyPackedName(ValueFullInformation
->Name
,
853 NameSize
/ sizeof(WCHAR
));
857 RtlCopyMemory(ValueFullInformation
->Name
,
862 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
864 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
865 RtlCopyMemory((PCHAR
) ValueFullInformation
866 + ValueFullInformation
->DataOffset
,
867 DataCell
->Data
, DataSize
);
871 RtlCopyMemory((PCHAR
) ValueFullInformation
872 + ValueFullInformation
->DataOffset
,
873 &ValueCell
->DataOffset
, DataSize
);
879 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
885 Status
= STATUS_UNSUCCESSFUL
;
888 ExReleaseResourceLite(&CmiRegistryLock
);
889 KeLeaveCriticalRegion();
890 ObDereferenceObject(KeyObject
);
897 NtFlushKey(IN HANDLE KeyHandle
)
900 PKEY_OBJECT KeyObject
;
901 PREGISTRY_HIVE RegistryHive
;
903 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle
);
905 /* Verify that the handle is valid and is a registry key */
906 Status
= ObReferenceObjectByHandle(KeyHandle
,
912 if (!NT_SUCCESS(Status
))
917 VERIFY_KEY_OBJECT(KeyObject
);
919 RegistryHive
= KeyObject
->RegistryHive
;
921 /* Acquire hive lock */
922 KeEnterCriticalRegion();
923 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
925 if (IsNoFileHive(RegistryHive
))
927 Status
= STATUS_SUCCESS
;
931 /* Flush non-volatile hive */
932 Status
= CmiFlushRegistryHive(RegistryHive
);
935 ExReleaseResourceLite(&CmiRegistryLock
);
936 KeLeaveCriticalRegion();
938 ObDereferenceObject(KeyObject
);
940 return STATUS_SUCCESS
;
945 NtOpenKey(OUT PHANDLE KeyHandle
,
946 IN ACCESS_MASK DesiredAccess
,
947 IN POBJECT_ATTRIBUTES ObjectAttributes
)
949 UNICODE_STRING RemainingPath
;
953 DPRINT("NtOpenKey(KH %x DA %x OA %x OA->ON '%wZ'\n",
957 ObjectAttributes
? ObjectAttributes
->ObjectName
: NULL
);
959 RemainingPath
.Buffer
= NULL
;
960 Status
= ObFindObject(ObjectAttributes
,
964 if (!NT_SUCCESS(Status
))
969 VERIFY_KEY_OBJECT((PKEY_OBJECT
) Object
);
971 DPRINT("RemainingPath '%wZ'\n", &RemainingPath
);
973 if ((RemainingPath
.Buffer
!= NULL
) && (RemainingPath
.Buffer
[0] != 0))
975 ObDereferenceObject(Object
);
976 RtlFreeUnicodeString(&RemainingPath
);
977 return STATUS_OBJECT_NAME_NOT_FOUND
;
980 RtlFreeUnicodeString(&RemainingPath
);
982 /* Fail if the key has been deleted */
983 if (((PKEY_OBJECT
)Object
)->Flags
& KO_MARKED_FOR_DELETE
)
985 ObDereferenceObject(Object
);
986 return(STATUS_UNSUCCESSFUL
);
989 Status
= ObCreateHandle(PsGetCurrentProcess(),
994 ObDereferenceObject(Object
);
996 if (!NT_SUCCESS(Status
))
1001 return(STATUS_SUCCESS
);
1006 NtQueryKey(IN HANDLE KeyHandle
,
1007 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1008 OUT PVOID KeyInformation
,
1010 OUT PULONG ResultLength
)
1012 PKEY_BASIC_INFORMATION BasicInformation
;
1013 PKEY_NODE_INFORMATION NodeInformation
;
1014 PKEY_FULL_INFORMATION FullInformation
;
1015 PREGISTRY_HIVE RegistryHive
;
1016 PDATA_CELL ClassCell
;
1017 PKEY_OBJECT KeyObject
;
1019 ULONG NameSize
, ClassSize
;
1022 DPRINT("NtQueryKey(KH %x KIC %x KI %x L %d RL %x)\n",
1024 KeyInformationClass
,
1029 /* Verify that the handle is valid and is a registry key */
1030 Status
= ObReferenceObjectByHandle(KeyHandle
,
1034 (PVOID
*) &KeyObject
,
1036 if (!NT_SUCCESS(Status
))
1041 /* Acquire hive lock */
1042 KeEnterCriticalRegion();
1043 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1045 VERIFY_KEY_OBJECT(KeyObject
);
1047 /* Get pointer to KeyCell */
1048 KeyCell
= KeyObject
->KeyCell
;
1049 RegistryHive
= KeyObject
->RegistryHive
;
1051 Status
= STATUS_SUCCESS
;
1052 switch (KeyInformationClass
)
1054 case KeyBasicInformation
:
1055 NameSize
= KeyObject
->Name
.Length
;
1057 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1059 /* Check size of buffer */
1060 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
1062 Status
= STATUS_BUFFER_TOO_SMALL
;
1066 /* Fill buffer with requested info */
1067 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
1068 BasicInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1069 BasicInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1070 BasicInformation
->TitleIndex
= 0;
1071 BasicInformation
->NameLength
= KeyObject
->Name
.Length
;
1073 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) <
1076 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1077 Status
= STATUS_BUFFER_OVERFLOW
;
1081 RtlCopyMemory(BasicInformation
->Name
,
1082 KeyObject
->Name
.Buffer
,
1087 case KeyNodeInformation
:
1088 NameSize
= KeyObject
->Name
.Length
;
1089 ClassSize
= KeyCell
->ClassSize
;
1091 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
1092 NameSize
+ ClassSize
;
1094 /* Check size of buffer */
1095 if (Length
< *ResultLength
)
1097 Status
= STATUS_BUFFER_TOO_SMALL
;
1101 /* Fill buffer with requested info */
1102 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
1103 NodeInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1104 NodeInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1105 NodeInformation
->TitleIndex
= 0;
1106 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
1107 KeyObject
->Name
.Length
;
1108 NodeInformation
->ClassLength
= KeyCell
->ClassSize
;
1109 NodeInformation
->NameLength
= KeyObject
->Name
.Length
;
1111 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
1113 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
1115 Status
= STATUS_BUFFER_OVERFLOW
;
1118 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1119 NameSize
< ClassSize
)
1121 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1123 Status
= STATUS_BUFFER_OVERFLOW
;
1127 RtlCopyMemory(NodeInformation
->Name
,
1128 KeyObject
->Name
.Buffer
,
1133 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1134 KeyCell
->ClassNameOffset
,
1136 RtlCopyMemory (NodeInformation
->Name
+ KeyObject
->Name
.Length
,
1143 case KeyFullInformation
:
1144 ClassSize
= KeyCell
->ClassSize
;
1146 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
1149 /* Check size of buffer */
1150 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
))
1152 Status
= STATUS_BUFFER_TOO_SMALL
;
1156 /* Fill buffer with requested info */
1157 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
1158 FullInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1159 FullInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1160 FullInformation
->TitleIndex
= 0;
1161 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) - sizeof(WCHAR
);
1162 FullInformation
->ClassLength
= KeyCell
->ClassSize
;
1163 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //KeyCell->NumberOfSubKeys;
1164 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
1165 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
1166 FullInformation
->Values
= KeyCell
->NumberOfValues
;
1167 FullInformation
->MaxValueNameLen
=
1168 CmiGetMaxValueNameLength(RegistryHive
, KeyCell
);
1169 FullInformation
->MaxValueDataLen
=
1170 CmiGetMaxValueDataLength(RegistryHive
, KeyCell
);
1172 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
1174 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
1175 Status
= STATUS_BUFFER_OVERFLOW
;
1181 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1182 KeyCell
->ClassNameOffset
,
1184 RtlCopyMemory (FullInformation
->Class
,
1185 ClassCell
->Data
, ClassSize
);
1191 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
1192 Status
= STATUS_INVALID_INFO_CLASS
;
1196 ExReleaseResourceLite(&CmiRegistryLock
);
1197 KeLeaveCriticalRegion();
1198 ObDereferenceObject(KeyObject
);
1205 NtQueryValueKey(IN HANDLE KeyHandle
,
1206 IN PUNICODE_STRING ValueName
,
1207 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1208 OUT PVOID KeyValueInformation
,
1210 OUT PULONG ResultLength
)
1213 ULONG NameSize
, DataSize
;
1214 PKEY_OBJECT KeyObject
;
1215 PREGISTRY_HIVE RegistryHive
;
1217 PVALUE_CELL ValueCell
;
1218 PDATA_CELL DataCell
;
1219 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
1220 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
1221 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
1223 DPRINT("NtQueryValueKey(KeyHandle %x ValueName %S Length %x)\n",
1224 KeyHandle
, ValueName
->Buffer
, Length
);
1226 /* Verify that the handle is valid and is a registry key */
1227 Status
= ObReferenceObjectByHandle(KeyHandle
,
1231 (PVOID
*)&KeyObject
,
1234 if (!NT_SUCCESS(Status
))
1236 DPRINT1("ObReferenceObjectByHandle() failed with status %x\n", Status
);
1240 /* Acquire hive lock */
1241 KeEnterCriticalRegion();
1242 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1244 VERIFY_KEY_OBJECT(KeyObject
);
1246 /* Get pointer to KeyCell */
1247 KeyCell
= KeyObject
->KeyCell
;
1248 RegistryHive
= KeyObject
->RegistryHive
;
1250 /* Get value cell by name */
1251 Status
= CmiScanKeyForValue(RegistryHive
,
1256 if (!NT_SUCCESS(Status
))
1258 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
1262 Status
= STATUS_SUCCESS
;
1263 switch (KeyValueInformationClass
)
1265 case KeyValueBasicInformation
:
1266 NameSize
= ValueCell
->NameSize
;
1267 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1269 NameSize
*= sizeof(WCHAR
);
1272 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) +
1275 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1277 Status
= STATUS_BUFFER_TOO_SMALL
;
1281 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1282 KeyValueInformation
;
1283 ValueBasicInformation
->TitleIndex
= 0;
1284 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1285 ValueBasicInformation
->NameLength
= NameSize
;
1287 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1290 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1291 Status
= STATUS_BUFFER_OVERFLOW
;
1295 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1297 CmiCopyPackedName(ValueBasicInformation
->Name
,
1299 NameSize
/ sizeof(WCHAR
));
1303 RtlCopyMemory(ValueBasicInformation
->Name
,
1310 case KeyValuePartialInformation
:
1311 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1313 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1316 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1318 Status
= STATUS_BUFFER_TOO_SMALL
;
1322 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1323 KeyValueInformation
;
1324 ValuePartialInformation
->TitleIndex
= 0;
1325 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1326 ValuePartialInformation
->DataLength
= DataSize
;
1328 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1331 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1332 Status
= STATUS_BUFFER_OVERFLOW
;
1336 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1338 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1339 RtlCopyMemory(ValuePartialInformation
->Data
,
1345 RtlCopyMemory(ValuePartialInformation
->Data
,
1346 &ValueCell
->DataOffset
,
1352 case KeyValueFullInformation
:
1353 NameSize
= ValueCell
->NameSize
;
1354 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1356 NameSize
*= sizeof(WCHAR
);
1358 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1360 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1361 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1363 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1365 Status
= STATUS_BUFFER_TOO_SMALL
;
1369 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1370 KeyValueInformation
;
1371 ValueFullInformation
->TitleIndex
= 0;
1372 ValueFullInformation
->Type
= ValueCell
->DataType
;
1373 ValueFullInformation
->NameLength
= NameSize
;
1374 ValueFullInformation
->DataOffset
=
1375 (ULONG_PTR
)ValueFullInformation
->Name
-
1376 (ULONG_PTR
)ValueFullInformation
+
1377 ValueFullInformation
->NameLength
;
1378 ValueFullInformation
->DataOffset
=
1379 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1380 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1382 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1385 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1387 Status
= STATUS_BUFFER_OVERFLOW
;
1390 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1391 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1393 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1394 Name
[0]) - NameSize
, sizeof(PVOID
));
1395 Status
= STATUS_BUFFER_OVERFLOW
;
1399 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1401 CmiCopyPackedName(ValueFullInformation
->Name
,
1403 NameSize
/ sizeof(WCHAR
));
1407 RtlCopyMemory(ValueFullInformation
->Name
,
1411 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1413 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1414 RtlCopyMemory((PCHAR
) ValueFullInformation
1415 + ValueFullInformation
->DataOffset
,
1421 RtlCopyMemory((PCHAR
) ValueFullInformation
1422 + ValueFullInformation
->DataOffset
,
1423 &ValueCell
->DataOffset
,
1430 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1431 Status
= STATUS_INVALID_INFO_CLASS
;
1436 ExReleaseResourceLite(&CmiRegistryLock
);
1437 KeLeaveCriticalRegion();
1438 ObDereferenceObject(KeyObject
);
1445 NtSetValueKey(IN HANDLE KeyHandle
,
1446 IN PUNICODE_STRING ValueName
,
1447 IN ULONG TitleIndex
,
1453 PKEY_OBJECT KeyObject
;
1454 PREGISTRY_HIVE RegistryHive
;
1456 PVALUE_CELL ValueCell
;
1457 BLOCK_OFFSET ValueCellOffset
;
1458 PDATA_CELL DataCell
;
1459 PDATA_CELL NewDataCell
;
1461 ULONG DesiredAccess
;
1463 DPRINT("NtSetValueKey(KeyHandle %x ValueName '%wZ' Type %d)\n",
1464 KeyHandle
, ValueName
, Type
);
1466 DesiredAccess
= KEY_SET_VALUE
;
1467 if (Type
== REG_LINK
)
1468 DesiredAccess
|= KEY_CREATE_LINK
;
1470 /* Verify that the handle is valid and is a registry key */
1471 Status
= ObReferenceObjectByHandle(KeyHandle
,
1475 (PVOID
*)&KeyObject
,
1477 if (!NT_SUCCESS(Status
))
1480 /* Acquire hive lock exclucively */
1481 KeEnterCriticalRegion();
1482 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1484 VERIFY_KEY_OBJECT(KeyObject
);
1486 /* Get pointer to key cell */
1487 KeyCell
= KeyObject
->KeyCell
;
1488 RegistryHive
= KeyObject
->RegistryHive
;
1489 Status
= CmiScanKeyForValue(RegistryHive
,
1494 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1496 DPRINT("Allocate new value cell\n");
1497 Status
= CmiAddValueToKey(RegistryHive
,
1499 KeyObject
->KeyCellOffset
,
1505 if (!NT_SUCCESS(Status
))
1507 DPRINT("Cannot add value. Status 0x%X\n", Status
);
1509 ExReleaseResourceLite(&CmiRegistryLock
);
1510 KeLeaveCriticalRegion();
1511 ObDereferenceObject(KeyObject
);
1515 DPRINT("DataSize %lu\n", DataSize
);
1516 DPRINT("ValueCell %p\n", ValueCell
);
1517 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1519 if (DataSize
<= sizeof(BLOCK_OFFSET
))
1521 /* If data size <= sizeof(BLOCK_OFFSET) then store data in the data offset */
1522 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1523 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1524 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1526 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1527 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
1530 RtlCopyMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
1531 ValueCell
->DataSize
= DataSize
| REG_DATA_IN_OFFSET
;
1532 ValueCell
->DataType
= Type
;
1533 RtlMoveMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
1534 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
1536 else if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1537 (DataSize
<= (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
1539 /* If new data size is <= current then overwrite current data */
1540 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
,&pBin
);
1541 RtlZeroMemory(DataCell
->Data
, ValueCell
->DataSize
);
1542 RtlCopyMemory(DataCell
->Data
, Data
, DataSize
);
1543 ValueCell
->DataSize
= DataSize
;
1544 ValueCell
->DataType
= Type
;
1549 * New data size is larger than the current, destroy current
1550 * data block and allocate a new one.
1552 BLOCK_OFFSET NewOffset
;
1554 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1556 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1557 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1559 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1560 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
1561 ValueCell
->DataSize
= 0;
1562 ValueCell
->DataType
= 0;
1563 ValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
1566 Status
= CmiAllocateCell (RegistryHive
,
1567 sizeof(CELL_HEADER
) + DataSize
,
1568 (PVOID
*)&NewDataCell
,
1570 if (!NT_SUCCESS(Status
))
1572 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status
);
1574 ExReleaseResourceLite(&CmiRegistryLock
);
1575 KeLeaveCriticalRegion();
1576 ObDereferenceObject(KeyObject
);
1581 RtlCopyMemory(&NewDataCell
->Data
[0], Data
, DataSize
);
1582 ValueCell
->DataSize
= DataSize
& REG_DATA_SIZE_MASK
;
1583 ValueCell
->DataType
= Type
;
1584 ValueCell
->DataOffset
= NewOffset
;
1585 CmiMarkBlockDirty(RegistryHive
, ValueCell
->DataOffset
);
1586 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
1590 if ((Type
== REG_LINK
) &&
1591 (_wcsicmp(ValueName
->Buffer
, L
"SymbolicLinkValue") == 0))
1593 KeyCell
->Flags
|= REG_KEY_LINK_CELL
;
1596 NtQuerySystemTime (&KeyCell
->LastWriteTime
);
1597 CmiMarkBlockDirty (RegistryHive
, KeyObject
->KeyCellOffset
);
1599 ExReleaseResourceLite(&CmiRegistryLock
);
1600 KeLeaveCriticalRegion();
1601 ObDereferenceObject(KeyObject
);
1605 DPRINT("Return Status 0x%X\n", Status
);
1612 NtDeleteValueKey (IN HANDLE KeyHandle
,
1613 IN PUNICODE_STRING ValueName
)
1615 PKEY_OBJECT KeyObject
;
1618 /* Verify that the handle is valid and is a registry key */
1619 Status
= ObReferenceObjectByHandle(KeyHandle
,
1623 (PVOID
*)&KeyObject
,
1625 if (!NT_SUCCESS(Status
))
1630 /* Acquire hive lock */
1631 KeEnterCriticalRegion();
1632 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1634 VERIFY_KEY_OBJECT(KeyObject
);
1636 Status
= CmiDeleteValueFromKey(KeyObject
->RegistryHive
,
1638 KeyObject
->KeyCellOffset
,
1641 NtQuerySystemTime (&KeyObject
->KeyCell
->LastWriteTime
);
1642 CmiMarkBlockDirty (KeyObject
->RegistryHive
, KeyObject
->KeyCellOffset
);
1644 /* Release hive lock */
1645 ExReleaseResourceLite(&CmiRegistryLock
);
1646 KeLeaveCriticalRegion();
1648 ObDereferenceObject (KeyObject
);
1658 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1659 * KeyObjectAttributes->Name specifies the name of the key to load.
1662 NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1663 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
1665 return NtLoadKey2 (KeyObjectAttributes
,
1666 FileObjectAttributes
,
1673 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1674 * KeyObjectAttributes->Name specifies the name of the key to load.
1675 * Flags can be 0 or REG_NO_LAZY_FLUSH.
1678 NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1679 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
1682 POBJECT_NAME_INFORMATION NameInfo
;
1683 PUNICODE_STRING NamePointer
;
1689 DPRINT ("NtLoadKey2() called\n");
1692 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, KeGetPreviousMode ()))
1693 return STATUS_PRIVILEGE_NOT_HELD
;
1696 if (FileObjectAttributes
->RootDirectory
!= NULL
)
1699 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1700 Buffer
= ExAllocatePool (NonPagedPool
,
1703 return STATUS_INSUFFICIENT_RESOURCES
;
1705 Status
= NtQueryObject (FileObjectAttributes
->RootDirectory
,
1706 ObjectNameInformation
,
1710 if (!NT_SUCCESS(Status
))
1712 DPRINT1 ("NtQueryObject() failed (Status %lx)\n", Status
);
1713 ExFreePool (Buffer
);
1717 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
1718 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
1719 &NameInfo
->Name
, NameInfo
->Name
.Length
);
1721 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
1722 if (FileObjectAttributes
->ObjectName
->Buffer
[0] != L
'\\')
1724 RtlAppendUnicodeToString (&NameInfo
->Name
,
1726 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
1727 &NameInfo
->Name
, NameInfo
->Name
.Length
);
1729 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
1730 FileObjectAttributes
->ObjectName
);
1732 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
1733 &NameInfo
->Name
, NameInfo
->Name
.Length
);
1734 NamePointer
= &NameInfo
->Name
;
1738 if (FileObjectAttributes
->ObjectName
->Buffer
[0] == L
'\\')
1741 NamePointer
= FileObjectAttributes
->ObjectName
;
1746 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1747 Buffer
= ExAllocatePool (NonPagedPool
,
1750 return STATUS_INSUFFICIENT_RESOURCES
;
1752 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
1753 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
1754 NameInfo
->Name
.Length
= 0;
1755 NameInfo
->Name
.Buffer
= (PWSTR
)((ULONG_PTR
)Buffer
+ sizeof(OBJECT_NAME_INFORMATION
));
1756 NameInfo
->Name
.Buffer
[0] = 0;
1758 RtlAppendUnicodeToString (&NameInfo
->Name
,
1760 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
1761 FileObjectAttributes
->ObjectName
);
1763 NamePointer
= &NameInfo
->Name
;
1767 DPRINT ("Full name: '%wZ'\n", NamePointer
);
1769 /* Acquire hive lock */
1770 KeEnterCriticalRegion();
1771 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1773 Status
= CmiLoadHive (KeyObjectAttributes
,
1776 if (!NT_SUCCESS (Status
))
1778 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
1781 /* Release hive lock */
1782 ExReleaseResourceLite(&CmiRegistryLock
);
1783 KeLeaveCriticalRegion();
1786 ExFreePool (Buffer
);
1793 NtNotifyChangeKey (IN HANDLE KeyHandle
,
1795 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
1796 IN PVOID ApcContext OPTIONAL
,
1797 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1798 IN ULONG CompletionFilter
,
1799 IN BOOLEAN Asynchroneous
,
1800 OUT PVOID ChangeBuffer
,
1802 IN BOOLEAN WatchSubtree
)
1805 return(STATUS_NOT_IMPLEMENTED
);
1810 NtQueryMultipleValueKey (IN HANDLE KeyHandle
,
1811 IN OUT PKEY_VALUE_ENTRY ValueList
,
1812 IN ULONG NumberOfValues
,
1814 IN OUT PULONG Length
,
1815 OUT PULONG ReturnLength
)
1817 PREGISTRY_HIVE RegistryHive
;
1818 PVALUE_CELL ValueCell
;
1819 PKEY_OBJECT KeyObject
;
1820 PDATA_CELL DataCell
;
1821 ULONG BufferLength
= 0;
1827 /* Verify that the handle is valid and is a registry key */
1828 Status
= ObReferenceObjectByHandle(KeyHandle
,
1832 (PVOID
*) &KeyObject
,
1834 if (!NT_SUCCESS(Status
))
1836 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
1840 /* Acquire hive lock */
1841 KeEnterCriticalRegion();
1842 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1844 VERIFY_KEY_OBJECT(KeyObject
);
1846 /* Get pointer to KeyCell */
1847 KeyCell
= KeyObject
->KeyCell
;
1848 RegistryHive
= KeyObject
->RegistryHive
;
1850 DataPtr
= (PUCHAR
) Buffer
;
1852 for (i
= 0; i
< NumberOfValues
; i
++)
1854 DPRINT("ValueName: '%wZ'\n", ValueList
[i
].ValueName
);
1856 /* Get Value block of interest */
1857 Status
= CmiScanKeyForValue(RegistryHive
,
1859 ValueList
[i
].ValueName
,
1863 if (!NT_SUCCESS(Status
))
1865 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
1868 else if (ValueCell
== NULL
)
1870 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1874 BufferLength
= ROUND_UP(BufferLength
, sizeof(PVOID
));
1876 if (BufferLength
+ (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) <= *Length
)
1878 DataPtr
= (PUCHAR
)ROUND_UP((ULONG_PTR
)DataPtr
, sizeof(PVOID
));
1880 ValueList
[i
].Type
= ValueCell
->DataType
;
1881 ValueList
[i
].DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1882 ValueList
[i
].DataOffset
= (ULONG_PTR
)DataPtr
- (ULONG_PTR
)Buffer
;
1884 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1886 DataCell
= CmiGetCell (RegistryHive
,
1887 ValueCell
->DataOffset
,
1889 RtlCopyMemory(DataPtr
,
1891 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
1895 RtlCopyMemory(DataPtr
,
1896 &ValueCell
->DataOffset
,
1897 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
1900 DataPtr
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1904 Status
= STATUS_BUFFER_TOO_SMALL
;
1907 BufferLength
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1910 if (NT_SUCCESS(Status
))
1911 *Length
= BufferLength
;
1913 *ReturnLength
= BufferLength
;
1915 /* Release hive lock */
1916 ExReleaseResourceLite(&CmiRegistryLock
);
1917 KeLeaveCriticalRegion();
1919 ObDereferenceObject(KeyObject
);
1921 DPRINT("Return Status 0x%X\n", Status
);
1928 NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes
,
1930 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
1933 return(STATUS_NOT_IMPLEMENTED
);
1938 NtRestoreKey (IN HANDLE KeyHandle
,
1939 IN HANDLE FileHandle
,
1940 IN ULONG RestoreFlags
)
1943 return(STATUS_NOT_IMPLEMENTED
);
1948 NtSaveKey (IN HANDLE KeyHandle
,
1949 IN HANDLE FileHandle
)
1951 PREGISTRY_HIVE TempHive
;
1952 PKEY_OBJECT KeyObject
;
1955 DPRINT ("NtSaveKey() called\n");
1958 if (!SeSinglePrivilegeCheck (SeBackupPrivilege
, KeGetPreviousMode ()))
1959 return STATUS_PRIVILEGE_NOT_HELD
;
1962 Status
= ObReferenceObjectByHandle (KeyHandle
,
1965 KeGetPreviousMode(),
1966 (PVOID
*)&KeyObject
,
1968 if (!NT_SUCCESS(Status
))
1970 DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
1974 /* Acquire hive lock exclucively */
1975 KeEnterCriticalRegion();
1976 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1978 /* Refuse to save a volatile key */
1979 if (KeyObject
->RegistryHive
== CmiVolatileHive
)
1981 DPRINT1 ("Cannot save a volatile key\n");
1982 ExReleaseResourceLite(&CmiRegistryLock
);
1983 KeLeaveCriticalRegion();
1984 ObDereferenceObject (KeyObject
);
1985 return STATUS_ACCESS_DENIED
;
1988 Status
= CmiCreateTempHive(&TempHive
);
1989 if (!NT_SUCCESS(Status
))
1991 DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status
);
1992 ExReleaseResourceLite(&CmiRegistryLock
);
1993 KeLeaveCriticalRegion();
1994 ObDereferenceObject (KeyObject
);
1998 Status
= CmiCopyKey (TempHive
,
2000 KeyObject
->RegistryHive
,
2001 KeyObject
->KeyCell
);
2002 if (!NT_SUCCESS(Status
))
2004 DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status
);
2005 CmiRemoveRegistryHive (TempHive
);
2006 ExReleaseResourceLite(&CmiRegistryLock
);
2007 KeLeaveCriticalRegion();
2008 ObDereferenceObject (KeyObject
);
2012 Status
= CmiSaveTempHive (TempHive
,
2014 if (!NT_SUCCESS(Status
))
2016 DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status
);
2019 CmiRemoveRegistryHive (TempHive
);
2021 /* Release hive lock */
2022 ExReleaseResourceLite(&CmiRegistryLock
);
2023 KeLeaveCriticalRegion();
2025 ObDereferenceObject (KeyObject
);
2027 DPRINT ("NtSaveKey() done\n");
2029 return STATUS_SUCCESS
;
2038 IN HANDLE KeyHandle
,
2039 IN HANDLE FileHandle
,
2040 IN ULONG Flags
// REG_STANDARD_FORMAT, etc..
2044 return STATUS_NOT_IMPLEMENTED
;
2049 NtSetInformationKey (IN HANDLE KeyHandle
,
2050 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
2051 IN PVOID KeyInformation
,
2052 IN ULONG KeyInformationLength
)
2054 PKEY_OBJECT KeyObject
;
2057 if (KeyInformationClass
!= KeyWriteTimeInformation
)
2058 return STATUS_INVALID_INFO_CLASS
;
2060 if (KeyInformationLength
!= sizeof (KEY_WRITE_TIME_INFORMATION
))
2061 return STATUS_INFO_LENGTH_MISMATCH
;
2063 /* Verify that the handle is valid and is a registry key */
2064 Status
= ObReferenceObjectByHandle (KeyHandle
,
2068 (PVOID
*)&KeyObject
,
2070 if (!NT_SUCCESS (Status
))
2072 DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2076 /* Acquire hive lock */
2077 KeEnterCriticalRegion();
2078 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2080 VERIFY_KEY_OBJECT(KeyObject
);
2082 KeyObject
->KeyCell
->LastWriteTime
.QuadPart
=
2083 ((PKEY_WRITE_TIME_INFORMATION
)KeyInformation
)->LastWriteTime
.QuadPart
;
2085 CmiMarkBlockDirty (KeyObject
->RegistryHive
,
2086 KeyObject
->KeyCellOffset
);
2088 /* Release hive lock */
2089 ExReleaseResourceLite(&CmiRegistryLock
);
2090 KeLeaveCriticalRegion();
2092 ObDereferenceObject (KeyObject
);
2096 DPRINT ("NtSaveKey() done\n");
2098 return STATUS_SUCCESS
;
2104 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2105 * KeyObjectAttributes->Name specifies the name of the key to unload.
2108 NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
2110 PREGISTRY_HIVE RegistryHive
;
2113 DPRINT ("NtUnloadKey() called\n");
2116 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, KeGetPreviousMode ()))
2117 return STATUS_PRIVILEGE_NOT_HELD
;
2120 /* Acquire registry lock exclusively */
2121 KeEnterCriticalRegion();
2122 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2124 Status
= CmiDisconnectHive (KeyObjectAttributes
,
2126 if (!NT_SUCCESS (Status
))
2128 DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status
);
2129 ExReleaseResourceLite (&CmiRegistryLock
);
2130 KeLeaveCriticalRegion();
2134 DPRINT ("RegistryHive %p\n", RegistryHive
);
2138 if (!IsNoFileHive (RegistryHive
))
2139 CmiFlushRegistryHive (RegistryHive
);
2142 CmiRemoveRegistryHive (RegistryHive
);
2144 /* Release registry lock */
2145 ExReleaseResourceLite (&CmiRegistryLock
);
2146 KeLeaveCriticalRegion();
2148 DPRINT ("NtUnloadKey() done\n");
2150 return STATUS_SUCCESS
;
2155 NtInitializeRegistry (IN BOOLEAN SetUpBoot
)
2159 if (CmiRegistryInitialized
== TRUE
)
2160 return STATUS_ACCESS_DENIED
;
2162 /* Save boot log file */
2163 IopSaveBootLogToFile();
2165 Status
= CmiInitHives (SetUpBoot
);
2167 CmiRegistryInitialized
= TRUE
;