3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/ntfunc.c
6 * PURPOSE: Ntxxx function for registry access
8 * PROGRAMMERS: No programmer listed.
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
20 /* GLOBALS ******************************************************************/
22 extern POBJECT_TYPE CmiKeyType
;
23 extern PREGISTRY_HIVE CmiVolatileHive
;
24 extern LIST_ENTRY CmiKeyObjectListHead
;
26 static BOOLEAN CmiRegistryInitialized
= FALSE
;
28 LIST_ENTRY CmiCallbackHead
;
29 FAST_MUTEX CmiCallbackLock
;
31 /* FUNCTIONS ****************************************************************/
37 CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function
,
39 IN OUT PLARGE_INTEGER Cookie
)
41 PREGISTRY_CALLBACK Callback
;
45 ASSERT(Function
&& Cookie
);
47 Callback
= ExAllocatePoolWithTag(PagedPool
,
48 sizeof(REGISTRY_CALLBACK
),
49 TAG('C', 'M', 'c', 'b'));
52 /* initialize the callback */
53 ExInitializeRundownProtection(&Callback
->RundownRef
);
54 Callback
->Function
= Function
;
55 Callback
->Context
= Context
;
56 Callback
->PendingDelete
= FALSE
;
58 /* add it to the callback list and receive a cookie for the callback */
59 ExAcquireFastMutex(&CmiCallbackLock
);
60 /* FIXME - to receive a unique cookie we'll just return the pointer to the
62 Callback
->Cookie
.QuadPart
= (ULONG_PTR
)Callback
;
63 InsertTailList(&CmiCallbackHead
, &Callback
->ListEntry
);
65 ExReleaseFastMutex(&CmiCallbackLock
);
67 *Cookie
= Callback
->Cookie
;
68 return STATUS_SUCCESS
;
71 return STATUS_INSUFFICIENT_RESOURCES
;
79 CmUnRegisterCallback(IN LARGE_INTEGER Cookie
)
81 PLIST_ENTRY CurrentEntry
;
85 ExAcquireFastMutex(&CmiCallbackLock
);
87 for(CurrentEntry
= CmiCallbackHead
.Flink
;
88 CurrentEntry
!= &CmiCallbackHead
;
89 CurrentEntry
= CurrentEntry
->Flink
)
91 PREGISTRY_CALLBACK CurrentCallback
;
93 CurrentCallback
= CONTAINING_RECORD(CurrentEntry
, REGISTRY_CALLBACK
, ListEntry
);
94 if(CurrentCallback
->Cookie
.QuadPart
== Cookie
.QuadPart
)
96 if(!CurrentCallback
->PendingDelete
)
98 /* found the callback, don't unlink it from the list yet so we don't screw
100 CurrentCallback
->PendingDelete
= TRUE
;
101 ExReleaseFastMutex(&CmiCallbackLock
);
103 /* if the callback is currently executing, wait until it finished */
104 ExWaitForRundownProtectionRelease(&CurrentCallback
->RundownRef
);
106 /* time to unlink it. It's now safe because every attempt to acquire a
107 runtime protection on this callback will fail */
108 ExAcquireFastMutex(&CmiCallbackLock
);
109 RemoveEntryList(&CurrentCallback
->ListEntry
);
110 ExReleaseFastMutex(&CmiCallbackLock
);
112 /* free the callback */
113 ExFreePool(CurrentCallback
);
114 return STATUS_SUCCESS
;
118 /* pending delete, pretend like it already is deleted */
119 ExReleaseFastMutex(&CmiCallbackLock
);
120 return STATUS_UNSUCCESSFUL
;
125 ExReleaseFastMutex(&CmiCallbackLock
);
127 return STATUS_UNSUCCESSFUL
;
132 CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1
,
135 PLIST_ENTRY CurrentEntry
;
139 ExAcquireFastMutex(&CmiCallbackLock
);
141 for(CurrentEntry
= CmiCallbackHead
.Flink
;
142 CurrentEntry
!= &CmiCallbackHead
;
143 CurrentEntry
= CurrentEntry
->Flink
)
145 PREGISTRY_CALLBACK CurrentCallback
;
147 CurrentCallback
= CONTAINING_RECORD(CurrentEntry
, REGISTRY_CALLBACK
, ListEntry
);
148 if(!CurrentCallback
->PendingDelete
&&
149 ExAcquireRundownProtectionEx(&CurrentCallback
->RundownRef
, 1))
153 /* don't hold locks during the callbacks! */
154 ExReleaseFastMutex(&CmiCallbackLock
);
156 Status
= CurrentCallback
->Function(CurrentCallback
->Context
,
159 if(!NT_SUCCESS(Status
))
161 /* one callback returned failure, don't call any more callbacks */
165 ExAcquireFastMutex(&CmiCallbackLock
);
166 /* don't release the rundown protection before holding the callback lock
167 so the pointer to the next callback isn't cleared in case this callback
169 ExReleaseRundownProtectionEx(&CurrentCallback
->RundownRef
, 1);
173 ExReleaseFastMutex(&CmiCallbackLock
);
175 return STATUS_SUCCESS
;
180 NtCreateKey(OUT PHANDLE KeyHandle
,
181 IN ACCESS_MASK DesiredAccess
,
182 IN POBJECT_ATTRIBUTES ObjectAttributes
,
184 IN PUNICODE_STRING Class
,
185 IN ULONG CreateOptions
,
186 OUT PULONG Disposition
)
188 UNICODE_STRING RemainingPath
;
189 PKEY_OBJECT KeyObject
;
197 DPRINT("NtCreateKey (Name %wZ KeyHandle %x Root %x)\n",
198 ObjectAttributes
->ObjectName
,
200 ObjectAttributes
->RootDirectory
);
202 Status
= ObFindObject(ObjectAttributes
,
206 if (!NT_SUCCESS(Status
))
208 DPRINT("ObFindObject failed, Status: 0x%x\n", Status
);
212 DPRINT("RemainingPath %wZ\n", &RemainingPath
);
214 if (RemainingPath
.Length
== 0)
216 /* Fail if the key has been deleted */
217 if (((PKEY_OBJECT
) Object
)->Flags
& KO_MARKED_FOR_DELETE
)
219 ObDereferenceObject(Object
);
220 RtlFreeUnicodeString(&RemainingPath
);
221 DPRINT("Object marked for delete!\n");
222 return(STATUS_UNSUCCESSFUL
);
226 *Disposition
= REG_OPENED_EXISTING_KEY
;
228 Status
= ObCreateHandle(PsGetCurrentProcess(),
234 DPRINT("ObCreateHandle failed Status 0x%x\n", Status
);
235 ObDereferenceObject(Object
);
236 RtlFreeUnicodeString(&RemainingPath
);
240 /* If RemainingPath contains \ we must return error
241 because NtCreateKey doesn't create trees */
242 Start
= RemainingPath
.Buffer
;
246 for (i
= 1; i
< RemainingPath
.Length
/ sizeof(WCHAR
); i
++)
248 if (L
'\\' == RemainingPath
.Buffer
[i
])
250 ObDereferenceObject(Object
);
251 DPRINT1("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath
);
252 RtlFreeUnicodeString(&RemainingPath
);
253 return STATUS_OBJECT_NAME_NOT_FOUND
;
257 DPRINT("RemainingPath %S ParentObject %x\n", RemainingPath
.Buffer
, Object
);
259 Status
= ObCreateObject(ExGetPreviousMode(),
268 if (!NT_SUCCESS(Status
))
270 DPRINT1("ObCreateObject() failed!\n");
274 Status
= ObInsertObject((PVOID
)KeyObject
,
280 if (!NT_SUCCESS(Status
))
282 ObDereferenceObject(KeyObject
);
283 RtlFreeUnicodeString(&RemainingPath
);
284 DPRINT1("ObInsertObject() failed!\n");
288 KeyObject
->ParentKey
= Object
;
290 if (CreateOptions
& REG_OPTION_VOLATILE
)
291 KeyObject
->RegistryHive
= CmiVolatileHive
;
293 KeyObject
->RegistryHive
= KeyObject
->ParentKey
->RegistryHive
;
295 KeyObject
->Flags
= 0;
296 KeyObject
->NumberOfSubKeys
= 0;
297 KeyObject
->SizeOfSubKeys
= 0;
298 KeyObject
->SubKeys
= NULL
;
300 /* Acquire hive lock */
301 KeEnterCriticalRegion();
302 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
304 InsertTailList(&CmiKeyObjectListHead
, &KeyObject
->ListEntry
);
306 /* add key to subkeys of parent if needed */
307 Status
= CmiAddSubKey(KeyObject
->RegistryHive
,
308 KeyObject
->ParentKey
,
314 if (!NT_SUCCESS(Status
))
316 DPRINT("CmiAddSubKey() failed (Status %lx)\n", Status
);
317 /* Release hive lock */
318 ExReleaseResourceLite(&CmiRegistryLock
);
319 KeLeaveCriticalRegion();
320 ObDereferenceObject(KeyObject
);
321 ObDereferenceObject(Object
);
322 RtlFreeUnicodeString(&RemainingPath
);
323 return STATUS_UNSUCCESSFUL
;
326 if (Start
== RemainingPath
.Buffer
)
328 KeyObject
->Name
= RemainingPath
;
332 RtlpCreateUnicodeString(&KeyObject
->Name
, Start
, NonPagedPool
);
333 RtlFreeUnicodeString(&RemainingPath
);
336 if (KeyObject
->RegistryHive
== KeyObject
->ParentKey
->RegistryHive
)
338 KeyObject
->KeyCell
->ParentKeyOffset
= KeyObject
->ParentKey
->KeyCellOffset
;
339 KeyObject
->KeyCell
->SecurityKeyOffset
= KeyObject
->ParentKey
->KeyCell
->SecurityKeyOffset
;
343 KeyObject
->KeyCell
->ParentKeyOffset
= -1;
344 KeyObject
->KeyCell
->SecurityKeyOffset
= -1;
345 /* This key must remain in memory unless it is deleted
346 or file is unloaded */
347 ObReferenceObjectByPointer(KeyObject
,
348 STANDARD_RIGHTS_REQUIRED
,
353 CmiAddKeyToList(KeyObject
->ParentKey
, KeyObject
);
355 VERIFY_KEY_OBJECT(KeyObject
);
357 /* Release hive lock */
358 ExReleaseResourceLite(&CmiRegistryLock
);
359 KeLeaveCriticalRegion();
362 ObDereferenceObject(Object
);
365 *Disposition
= REG_CREATED_NEW_KEY
;
374 NtDeleteKey(IN HANDLE KeyHandle
)
376 KPROCESSOR_MODE PreviousMode
;
377 PKEY_OBJECT KeyObject
;
382 DPRINT1("NtDeleteKey(KeyHandle %x) called\n", KeyHandle
);
384 PreviousMode
= ExGetPreviousMode();
386 /* Verify that the handle is valid and is a registry key */
387 Status
= ObReferenceObjectByHandle(KeyHandle
,
393 if (!NT_SUCCESS(Status
))
395 DPRINT1("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
399 /* Acquire hive lock */
400 KeEnterCriticalRegion();
401 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
403 VERIFY_KEY_OBJECT(KeyObject
);
405 /* Check for subkeys */
406 if (KeyObject
->NumberOfSubKeys
!= 0)
408 Status
= STATUS_CANNOT_DELETE
;
412 /* Set the marked for delete bit in the key object */
413 KeyObject
->Flags
|= KO_MARKED_FOR_DELETE
;
414 Status
= STATUS_SUCCESS
;
417 /* Release hive lock */
418 ExReleaseResourceLite(&CmiRegistryLock
);
419 KeLeaveCriticalRegion();
421 DPRINT1("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
423 /* Dereference the object */
424 ObDereferenceObject(KeyObject
);
425 /* Remove the keep-alive reference */
426 ObDereferenceObject(KeyObject
);
428 if (KeyObject
->RegistryHive
!= KeyObject
->ParentKey
->RegistryHive
)
429 ObDereferenceObject(KeyObject
);
431 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
432 DPRINT("HandleCount %lu\n", ObGetObjectHandleCount((PVOID
)KeyObject
));
436 * Hive-Synchronization will not be triggered here. This is done in
437 * CmiObjectDelete() (in regobj.c) after all key-related structures
438 * have been released.
446 NtEnumerateKey(IN HANDLE KeyHandle
,
448 IN KEY_INFORMATION_CLASS KeyInformationClass
,
449 OUT PVOID KeyInformation
,
451 OUT PULONG ResultLength
)
453 PKEY_OBJECT KeyObject
;
454 PKEY_OBJECT SubKeyObject
;
455 PREGISTRY_HIVE RegistryHive
;
456 PKEY_CELL KeyCell
, SubKeyCell
;
457 PHASH_TABLE_CELL HashTableBlock
;
458 PKEY_BASIC_INFORMATION BasicInformation
;
459 PKEY_NODE_INFORMATION NodeInformation
;
460 PKEY_FULL_INFORMATION FullInformation
;
461 PDATA_CELL ClassCell
;
462 ULONG NameSize
, ClassSize
;
463 KPROCESSOR_MODE PreviousMode
;
468 PreviousMode
= ExGetPreviousMode();
470 DPRINT("KH %x I %d KIC %x KI %x L %d RL %x\n",
478 /* Verify that the handle is valid and is a registry key */
479 Status
= ObReferenceObjectByHandle(KeyHandle
,
480 KEY_ENUMERATE_SUB_KEYS
,
483 (PVOID
*) &KeyObject
,
485 if (!NT_SUCCESS(Status
))
487 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
491 /* Acquire hive lock */
492 KeEnterCriticalRegion();
493 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
495 VERIFY_KEY_OBJECT(KeyObject
);
497 /* Get pointer to KeyCell */
498 KeyCell
= KeyObject
->KeyCell
;
499 RegistryHive
= KeyObject
->RegistryHive
;
503 /* Check for hightest possible sub key index */
504 if (Index
>= KeyCell
->NumberOfSubKeys
+ KeyObject
->NumberOfSubKeys
)
506 ExReleaseResourceLite(&CmiRegistryLock
);
507 KeLeaveCriticalRegion();
508 ObDereferenceObject(KeyObject
);
509 DPRINT("No more volatile entries\n");
510 return STATUS_NO_MORE_ENTRIES
;
513 /* Get pointer to SubKey */
514 if (Index
>= KeyCell
->NumberOfSubKeys
)
516 PKEY_OBJECT CurKey
= NULL
;
520 /* Search for volatile or 'foreign' keys */
521 j
= KeyCell
->NumberOfSubKeys
;
522 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
524 CurKey
= KeyObject
->SubKeys
[i
];
525 if (CurKey
->RegistryHive
!= RegistryHive
)
533 if (i
>= KeyObject
->NumberOfSubKeys
)
535 ExReleaseResourceLite(&CmiRegistryLock
);
536 KeLeaveCriticalRegion();
537 ObDereferenceObject(KeyObject
);
538 DPRINT("No more non-volatile entries\n");
539 return STATUS_NO_MORE_ENTRIES
;
542 SubKeyObject
= CurKey
;
543 SubKeyCell
= CurKey
->KeyCell
;
547 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
549 ExReleaseResourceLite(&CmiRegistryLock
);
550 KeLeaveCriticalRegion();
551 ObDereferenceObject(KeyObject
);
552 return STATUS_NO_MORE_ENTRIES
;
555 HashTableBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
556 if (HashTableBlock
== NULL
)
558 DPRINT("CmiGetBlock() failed\n");
559 ExReleaseResourceLite(&CmiRegistryLock
);
560 KeLeaveCriticalRegion();
561 ObDereferenceObject(KeyObject
);
562 return STATUS_UNSUCCESSFUL
;
565 SubKeyCell
= CmiGetKeyFromHashByIndex(RegistryHive
,
570 if (SubKeyCell
== NULL
)
572 ExReleaseResourceLite(&CmiRegistryLock
);
573 KeLeaveCriticalRegion();
574 ObDereferenceObject(KeyObject
);
575 DPRINT("No more entries\n");
576 return STATUS_NO_MORE_ENTRIES
;
579 Status
= STATUS_SUCCESS
;
580 switch (KeyInformationClass
)
582 case KeyBasicInformation
:
583 /* Check size of buffer */
584 if (SubKeyObject
!= NULL
)
586 NameSize
= SubKeyObject
->Name
.Length
;
590 NameSize
= SubKeyCell
->NameSize
;
591 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
593 NameSize
*= sizeof(WCHAR
);
597 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) + NameSize
;
600 * NOTE: It's perfetly valid to call NtEnumerateKey to get
601 * all the information but name. Actually the NT4 sound
602 * framework does that while querying parameters from registry.
603 * -- Filip Navara, 19/07/2004
605 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
607 Status
= STATUS_BUFFER_TOO_SMALL
;
611 /* Fill buffer with requested info */
612 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
613 BasicInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
614 BasicInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
615 BasicInformation
->TitleIndex
= Index
;
616 BasicInformation
->NameLength
= NameSize
;
618 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) < NameSize
)
620 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
621 Status
= STATUS_BUFFER_OVERFLOW
;
625 if (SubKeyObject
!= NULL
)
627 RtlCopyMemory(BasicInformation
->Name
,
628 SubKeyObject
->Name
.Buffer
,
633 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
635 CmiCopyPackedName(BasicInformation
->Name
,
637 NameSize
/ sizeof(WCHAR
));
641 RtlCopyMemory(BasicInformation
->Name
,
649 case KeyNodeInformation
:
650 /* Check size of buffer */
651 if (SubKeyObject
!= NULL
)
653 NameSize
= SubKeyObject
->Name
.Length
;
657 NameSize
= SubKeyCell
->NameSize
;
658 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
660 NameSize
*= sizeof(WCHAR
);
663 ClassSize
= SubKeyCell
->ClassSize
;
665 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
666 NameSize
+ ClassSize
;
668 if (Length
< FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]))
670 Status
= STATUS_BUFFER_TOO_SMALL
;
674 /* Fill buffer with requested info */
675 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
676 NodeInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
677 NodeInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
678 NodeInformation
->TitleIndex
= Index
;
679 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) + NameSize
;
680 NodeInformation
->ClassLength
= SubKeyCell
->ClassSize
;
681 NodeInformation
->NameLength
= NameSize
;
683 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
685 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
687 Status
= STATUS_BUFFER_OVERFLOW
;
690 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
691 NameSize
< ClassSize
)
693 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
695 Status
= STATUS_BUFFER_OVERFLOW
;
699 if (SubKeyObject
!= NULL
)
701 RtlCopyMemory(NodeInformation
->Name
,
702 SubKeyObject
->Name
.Buffer
,
707 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
709 CmiCopyPackedName(NodeInformation
->Name
,
711 NameSize
/ sizeof(WCHAR
));
715 RtlCopyMemory(NodeInformation
->Name
,
723 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
724 SubKeyCell
->ClassNameOffset
,
726 RtlCopyMemory (NodeInformation
->Name
+ SubKeyCell
->NameSize
,
733 case KeyFullInformation
:
734 ClassSize
= SubKeyCell
->ClassSize
;
736 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) +
739 /* Check size of buffer */
740 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]))
742 Status
= STATUS_BUFFER_TOO_SMALL
;
746 /* Fill buffer with requested info */
747 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
748 FullInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
749 FullInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
750 FullInformation
->TitleIndex
= Index
;
751 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) -
753 FullInformation
->ClassLength
= SubKeyCell
->ClassSize
;
754 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //SubKeyCell->NumberOfSubKeys;
755 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
756 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
757 FullInformation
->Values
= SubKeyCell
->NumberOfValues
;
758 FullInformation
->MaxValueNameLen
=
759 CmiGetMaxValueNameLength(RegistryHive
, SubKeyCell
);
760 FullInformation
->MaxValueDataLen
=
761 CmiGetMaxValueDataLength(RegistryHive
, SubKeyCell
);
763 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
765 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
766 Status
= STATUS_BUFFER_OVERFLOW
;
772 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
773 SubKeyCell
->ClassNameOffset
,
775 RtlCopyMemory (FullInformation
->Class
,
783 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
787 ExReleaseResourceLite(&CmiRegistryLock
);
788 KeLeaveCriticalRegion();
789 ObDereferenceObject(KeyObject
);
791 DPRINT("Returning status %x\n", Status
);
798 NtEnumerateValueKey(IN HANDLE KeyHandle
,
800 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
801 OUT PVOID KeyValueInformation
,
803 OUT PULONG ResultLength
)
806 PKEY_OBJECT KeyObject
;
807 PREGISTRY_HIVE RegistryHive
;
809 PVALUE_CELL ValueCell
;
811 ULONG NameSize
, DataSize
;
812 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
813 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
814 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
818 DPRINT("KH %x I %d KVIC %x KVI %x L %d RL %x\n",
821 KeyValueInformationClass
,
826 /* Verify that the handle is valid and is a registry key */
827 Status
= ObReferenceObjectByHandle(KeyHandle
,
831 (PVOID
*) &KeyObject
,
834 if (!NT_SUCCESS(Status
))
839 /* Acquire hive lock */
840 KeEnterCriticalRegion();
841 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
843 VERIFY_KEY_OBJECT(KeyObject
);
845 /* Get pointer to KeyCell */
846 KeyCell
= KeyObject
->KeyCell
;
847 RegistryHive
= KeyObject
->RegistryHive
;
849 /* Get Value block of interest */
850 Status
= CmiGetValueFromKeyByIndex(RegistryHive
,
855 if (!NT_SUCCESS(Status
))
857 ExReleaseResourceLite(&CmiRegistryLock
);
858 KeLeaveCriticalRegion();
859 ObDereferenceObject(KeyObject
);
863 if (ValueCell
!= NULL
)
865 switch (KeyValueInformationClass
)
867 case KeyValueBasicInformation
:
868 NameSize
= ValueCell
->NameSize
;
869 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
871 NameSize
*= sizeof(WCHAR
);
874 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) + NameSize
;
876 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
878 Status
= STATUS_BUFFER_TOO_SMALL
;
882 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
884 ValueBasicInformation
->TitleIndex
= 0;
885 ValueBasicInformation
->Type
= ValueCell
->DataType
;
886 ValueBasicInformation
->NameLength
= NameSize
;
888 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
891 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
892 Status
= STATUS_BUFFER_OVERFLOW
;
896 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
898 CmiCopyPackedName(ValueBasicInformation
->Name
,
900 NameSize
/ sizeof(WCHAR
));
904 RtlCopyMemory(ValueBasicInformation
->Name
,
911 case KeyValuePartialInformation
:
912 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
914 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
917 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
919 Status
= STATUS_BUFFER_TOO_SMALL
;
923 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
925 ValuePartialInformation
->TitleIndex
= 0;
926 ValuePartialInformation
->Type
= ValueCell
->DataType
;
927 ValuePartialInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
929 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
932 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
933 Status
= STATUS_BUFFER_OVERFLOW
;
937 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
939 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
940 RtlCopyMemory(ValuePartialInformation
->Data
,
946 RtlCopyMemory(ValuePartialInformation
->Data
,
947 &ValueCell
->DataOffset
,
953 case KeyValueFullInformation
:
954 NameSize
= ValueCell
->NameSize
;
955 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
957 NameSize
*= sizeof(WCHAR
);
959 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
961 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
962 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
964 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
966 Status
= STATUS_BUFFER_TOO_SMALL
;
970 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
972 ValueFullInformation
->TitleIndex
= 0;
973 ValueFullInformation
->Type
= ValueCell
->DataType
;
974 ValueFullInformation
->NameLength
= NameSize
;
975 ValueFullInformation
->DataOffset
=
976 (ULONG_PTR
)ValueFullInformation
->Name
-
977 (ULONG_PTR
)ValueFullInformation
+
978 ValueFullInformation
->NameLength
;
979 ValueFullInformation
->DataOffset
=
980 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
981 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
983 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
986 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
988 Status
= STATUS_BUFFER_OVERFLOW
;
991 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
992 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
994 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) - NameSize
, sizeof(PVOID
));
995 Status
= STATUS_BUFFER_OVERFLOW
;
999 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1001 CmiCopyPackedName(ValueFullInformation
->Name
,
1003 NameSize
/ sizeof(WCHAR
));
1007 RtlCopyMemory(ValueFullInformation
->Name
,
1012 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1014 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1015 RtlCopyMemory((PCHAR
) ValueFullInformation
1016 + ValueFullInformation
->DataOffset
,
1017 DataCell
->Data
, DataSize
);
1021 RtlCopyMemory((PCHAR
) ValueFullInformation
1022 + ValueFullInformation
->DataOffset
,
1023 &ValueCell
->DataOffset
, DataSize
);
1029 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1035 Status
= STATUS_UNSUCCESSFUL
;
1038 ExReleaseResourceLite(&CmiRegistryLock
);
1039 KeLeaveCriticalRegion();
1040 ObDereferenceObject(KeyObject
);
1047 NtFlushKey(IN HANDLE KeyHandle
)
1050 PKEY_OBJECT KeyObject
;
1051 PREGISTRY_HIVE RegistryHive
;
1052 KPROCESSOR_MODE PreviousMode
;
1056 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle
);
1058 PreviousMode
= ExGetPreviousMode();
1060 /* Verify that the handle is valid and is a registry key */
1061 Status
= ObReferenceObjectByHandle(KeyHandle
,
1065 (PVOID
*)&KeyObject
,
1067 if (!NT_SUCCESS(Status
))
1072 VERIFY_KEY_OBJECT(KeyObject
);
1074 RegistryHive
= KeyObject
->RegistryHive
;
1076 /* Acquire hive lock */
1077 KeEnterCriticalRegion();
1078 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1080 if (IsNoFileHive(RegistryHive
))
1082 Status
= STATUS_SUCCESS
;
1086 /* Flush non-volatile hive */
1087 Status
= CmiFlushRegistryHive(RegistryHive
);
1090 ExReleaseResourceLite(&CmiRegistryLock
);
1091 KeLeaveCriticalRegion();
1093 ObDereferenceObject(KeyObject
);
1095 return STATUS_SUCCESS
;
1100 NtOpenKey(OUT PHANDLE KeyHandle
,
1101 IN ACCESS_MASK DesiredAccess
,
1102 IN POBJECT_ATTRIBUTES ObjectAttributes
)
1104 UNICODE_STRING RemainingPath
;
1105 KPROCESSOR_MODE PreviousMode
;
1108 NTSTATUS Status
= STATUS_SUCCESS
;
1112 DPRINT("NtOpenKey(KH %x DA %x OA %x OA->ON '%wZ'\n",
1116 ObjectAttributes
? ObjectAttributes
->ObjectName
: NULL
);
1118 /* Check place for result handle, if it's null - return immediately */
1119 if (KeyHandle
== NULL
)
1120 return(STATUS_INVALID_PARAMETER
);
1122 PreviousMode
= ExGetPreviousMode();
1124 if(PreviousMode
!= KernelMode
)
1128 ProbeForWrite(KeyHandle
,
1134 Status
= _SEH_GetExceptionCode();
1138 if(!NT_SUCCESS(Status
))
1144 /* WINE checks for the length also */
1145 /*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
1146 return(STATUS_BUFFER_OVERFLOW);*/
1148 RemainingPath
.Buffer
= NULL
;
1149 Status
= ObFindObject(ObjectAttributes
,
1153 if (!NT_SUCCESS(Status
))
1155 DPRINT("ObFindObject() returned 0x%08lx\n", Status
);
1156 Status
= STATUS_INVALID_HANDLE
; /* Because ObFindObject returns STATUS_UNSUCCESSFUL */
1157 hKey
= *KeyHandle
; /* Preserve hkResult value */
1158 goto openkey_cleanup
;
1161 VERIFY_KEY_OBJECT((PKEY_OBJECT
) Object
);
1163 DPRINT("RemainingPath '%wZ'\n", &RemainingPath
);
1165 if ((RemainingPath
.Buffer
!= NULL
) && (RemainingPath
.Buffer
[0] != 0))
1167 ObDereferenceObject(Object
);
1168 RtlFreeUnicodeString(&RemainingPath
);
1169 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1171 goto openkey_cleanup
;
1174 RtlFreeUnicodeString(&RemainingPath
);
1176 /* Fail if the key has been deleted */
1177 if (((PKEY_OBJECT
)Object
)->Flags
& KO_MARKED_FOR_DELETE
)
1179 ObDereferenceObject(Object
);
1180 Status
= STATUS_UNSUCCESSFUL
;
1182 goto openkey_cleanup
;
1185 Status
= ObCreateHandle(PsGetCurrentProcess(),
1190 ObDereferenceObject(Object
);
1192 if (!NT_SUCCESS(Status
))
1202 Status
= _SEH_GetExceptionCode();
1211 NtQueryKey(IN HANDLE KeyHandle
,
1212 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1213 OUT PVOID KeyInformation
,
1215 OUT PULONG ResultLength
)
1217 PKEY_BASIC_INFORMATION BasicInformation
;
1218 PKEY_NODE_INFORMATION NodeInformation
;
1219 PKEY_FULL_INFORMATION FullInformation
;
1220 PREGISTRY_HIVE RegistryHive
;
1221 PDATA_CELL ClassCell
;
1222 PKEY_OBJECT KeyObject
;
1224 ULONG NameSize
, ClassSize
;
1229 DPRINT("NtQueryKey(KH %x KIC %x KI %x L %d RL %x)\n",
1231 KeyInformationClass
,
1236 /* Verify that the handle is valid and is a registry key */
1237 Status
= ObReferenceObjectByHandle(KeyHandle
,
1238 (KeyInformationClass
!= KeyNameInformation
? KEY_QUERY_VALUE
: 0),
1241 (PVOID
*) &KeyObject
,
1243 if (!NT_SUCCESS(Status
))
1248 /* Acquire hive lock */
1249 KeEnterCriticalRegion();
1250 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1252 VERIFY_KEY_OBJECT(KeyObject
);
1254 /* Get pointer to KeyCell */
1255 KeyCell
= KeyObject
->KeyCell
;
1256 RegistryHive
= KeyObject
->RegistryHive
;
1258 Status
= STATUS_SUCCESS
;
1259 switch (KeyInformationClass
)
1261 case KeyBasicInformation
:
1262 NameSize
= KeyObject
->Name
.Length
;
1264 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1266 /* Check size of buffer */
1267 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
1269 Status
= STATUS_BUFFER_TOO_SMALL
;
1273 /* Fill buffer with requested info */
1274 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
1275 BasicInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1276 BasicInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1277 BasicInformation
->TitleIndex
= 0;
1278 BasicInformation
->NameLength
= KeyObject
->Name
.Length
;
1280 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) <
1283 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1284 Status
= STATUS_BUFFER_OVERFLOW
;
1288 RtlCopyMemory(BasicInformation
->Name
,
1289 KeyObject
->Name
.Buffer
,
1294 case KeyNodeInformation
:
1295 NameSize
= KeyObject
->Name
.Length
;
1296 ClassSize
= KeyCell
->ClassSize
;
1298 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
1299 NameSize
+ ClassSize
;
1301 /* Check size of buffer */
1302 if (Length
< *ResultLength
)
1304 Status
= STATUS_BUFFER_TOO_SMALL
;
1308 /* Fill buffer with requested info */
1309 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
1310 NodeInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1311 NodeInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1312 NodeInformation
->TitleIndex
= 0;
1313 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
1314 KeyObject
->Name
.Length
;
1315 NodeInformation
->ClassLength
= KeyCell
->ClassSize
;
1316 NodeInformation
->NameLength
= KeyObject
->Name
.Length
;
1318 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
1320 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
1322 Status
= STATUS_BUFFER_OVERFLOW
;
1325 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1326 NameSize
< ClassSize
)
1328 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1330 Status
= STATUS_BUFFER_OVERFLOW
;
1334 RtlCopyMemory(NodeInformation
->Name
,
1335 KeyObject
->Name
.Buffer
,
1340 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1341 KeyCell
->ClassNameOffset
,
1343 RtlCopyMemory (NodeInformation
->Name
+ KeyObject
->Name
.Length
,
1350 case KeyFullInformation
:
1351 ClassSize
= KeyCell
->ClassSize
;
1353 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
1356 /* Check size of buffer */
1357 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
))
1359 Status
= STATUS_BUFFER_TOO_SMALL
;
1363 /* Fill buffer with requested info */
1364 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
1365 FullInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1366 FullInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1367 FullInformation
->TitleIndex
= 0;
1368 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) - sizeof(WCHAR
);
1369 FullInformation
->ClassLength
= KeyCell
->ClassSize
;
1370 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //KeyCell->NumberOfSubKeys;
1371 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
1372 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
1373 FullInformation
->Values
= KeyCell
->NumberOfValues
;
1374 FullInformation
->MaxValueNameLen
=
1375 CmiGetMaxValueNameLength(RegistryHive
, KeyCell
);
1376 FullInformation
->MaxValueDataLen
=
1377 CmiGetMaxValueDataLength(RegistryHive
, KeyCell
);
1379 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
1381 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
1382 Status
= STATUS_BUFFER_OVERFLOW
;
1388 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1389 KeyCell
->ClassNameOffset
,
1391 RtlCopyMemory (FullInformation
->Class
,
1392 ClassCell
->Data
, ClassSize
);
1397 case KeyNameInformation
:
1398 case KeyCachedInformation
:
1399 case KeyFlagsInformation
:
1400 DPRINT1("Key information class 0x%x not yet implemented!\n", KeyInformationClass
);
1401 Status
= STATUS_NOT_IMPLEMENTED
;
1405 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
1406 Status
= STATUS_INVALID_INFO_CLASS
;
1410 ExReleaseResourceLite(&CmiRegistryLock
);
1411 KeLeaveCriticalRegion();
1412 ObDereferenceObject(KeyObject
);
1419 NtQueryValueKey(IN HANDLE KeyHandle
,
1420 IN PUNICODE_STRING ValueName
,
1421 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1422 OUT PVOID KeyValueInformation
,
1424 OUT PULONG ResultLength
)
1427 ULONG NameSize
, DataSize
;
1428 PKEY_OBJECT KeyObject
;
1429 PREGISTRY_HIVE RegistryHive
;
1431 PVALUE_CELL ValueCell
;
1432 PDATA_CELL DataCell
;
1433 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
1434 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
1435 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
1439 DPRINT("NtQueryValueKey(KeyHandle %x ValueName %S Length %x)\n",
1440 KeyHandle
, ValueName
->Buffer
, Length
);
1442 /* Verify that the handle is valid and is a registry key */
1443 Status
= ObReferenceObjectByHandle(KeyHandle
,
1447 (PVOID
*)&KeyObject
,
1450 if (!NT_SUCCESS(Status
))
1452 DPRINT1("ObReferenceObjectByHandle() failed with status %x\n", Status
);
1456 /* Acquire hive lock */
1457 KeEnterCriticalRegion();
1458 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1460 VERIFY_KEY_OBJECT(KeyObject
);
1462 /* Get pointer to KeyCell */
1463 KeyCell
= KeyObject
->KeyCell
;
1464 RegistryHive
= KeyObject
->RegistryHive
;
1466 /* Get value cell by name */
1467 Status
= CmiScanKeyForValue(RegistryHive
,
1472 if (!NT_SUCCESS(Status
))
1474 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
1478 Status
= STATUS_SUCCESS
;
1479 switch (KeyValueInformationClass
)
1481 case KeyValueBasicInformation
:
1482 NameSize
= ValueCell
->NameSize
;
1483 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1485 NameSize
*= sizeof(WCHAR
);
1488 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) +
1491 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1493 Status
= STATUS_BUFFER_TOO_SMALL
;
1497 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1498 KeyValueInformation
;
1499 ValueBasicInformation
->TitleIndex
= 0;
1500 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1501 ValueBasicInformation
->NameLength
= NameSize
;
1503 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1506 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1507 Status
= STATUS_BUFFER_OVERFLOW
;
1511 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1513 CmiCopyPackedName(ValueBasicInformation
->Name
,
1515 NameSize
/ sizeof(WCHAR
));
1519 RtlCopyMemory(ValueBasicInformation
->Name
,
1526 case KeyValuePartialInformation
:
1527 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1529 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1532 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1534 Status
= STATUS_BUFFER_TOO_SMALL
;
1538 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1539 KeyValueInformation
;
1540 ValuePartialInformation
->TitleIndex
= 0;
1541 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1542 ValuePartialInformation
->DataLength
= DataSize
;
1544 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1547 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1548 Status
= STATUS_BUFFER_OVERFLOW
;
1552 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1554 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1555 RtlCopyMemory(ValuePartialInformation
->Data
,
1561 RtlCopyMemory(ValuePartialInformation
->Data
,
1562 &ValueCell
->DataOffset
,
1568 case KeyValueFullInformation
:
1569 NameSize
= ValueCell
->NameSize
;
1570 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1572 NameSize
*= sizeof(WCHAR
);
1574 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1576 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1577 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1579 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1581 Status
= STATUS_BUFFER_TOO_SMALL
;
1585 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1586 KeyValueInformation
;
1587 ValueFullInformation
->TitleIndex
= 0;
1588 ValueFullInformation
->Type
= ValueCell
->DataType
;
1589 ValueFullInformation
->NameLength
= NameSize
;
1590 ValueFullInformation
->DataOffset
=
1591 (ULONG_PTR
)ValueFullInformation
->Name
-
1592 (ULONG_PTR
)ValueFullInformation
+
1593 ValueFullInformation
->NameLength
;
1594 ValueFullInformation
->DataOffset
=
1595 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1596 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1598 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1601 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1603 Status
= STATUS_BUFFER_OVERFLOW
;
1606 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1607 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1609 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1610 Name
[0]) - NameSize
, sizeof(PVOID
));
1611 Status
= STATUS_BUFFER_OVERFLOW
;
1615 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1617 CmiCopyPackedName(ValueFullInformation
->Name
,
1619 NameSize
/ sizeof(WCHAR
));
1623 RtlCopyMemory(ValueFullInformation
->Name
,
1627 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1629 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1630 RtlCopyMemory((PCHAR
) ValueFullInformation
1631 + ValueFullInformation
->DataOffset
,
1637 RtlCopyMemory((PCHAR
) ValueFullInformation
1638 + ValueFullInformation
->DataOffset
,
1639 &ValueCell
->DataOffset
,
1646 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1647 Status
= STATUS_INVALID_INFO_CLASS
;
1652 ExReleaseResourceLite(&CmiRegistryLock
);
1653 KeLeaveCriticalRegion();
1654 ObDereferenceObject(KeyObject
);
1661 NtSetValueKey(IN HANDLE KeyHandle
,
1662 IN PUNICODE_STRING ValueName
,
1663 IN ULONG TitleIndex
,
1669 PKEY_OBJECT KeyObject
;
1670 PREGISTRY_HIVE RegistryHive
;
1672 PVALUE_CELL ValueCell
;
1673 BLOCK_OFFSET ValueCellOffset
;
1674 PDATA_CELL DataCell
;
1675 PDATA_CELL NewDataCell
;
1677 ULONG DesiredAccess
;
1681 DPRINT("NtSetValueKey(KeyHandle %x ValueName '%wZ' Type %d)\n",
1682 KeyHandle
, ValueName
, Type
);
1684 DesiredAccess
= KEY_SET_VALUE
;
1686 /* Verify that the handle is valid and is a registry key */
1687 Status
= ObReferenceObjectByHandle(KeyHandle
,
1690 ExGetPreviousMode(),
1691 (PVOID
*)&KeyObject
,
1693 if (!NT_SUCCESS(Status
))
1696 /* Acquire hive lock exclucively */
1697 KeEnterCriticalRegion();
1698 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1700 VERIFY_KEY_OBJECT(KeyObject
);
1702 /* Get pointer to key cell */
1703 KeyCell
= KeyObject
->KeyCell
;
1704 RegistryHive
= KeyObject
->RegistryHive
;
1705 Status
= CmiScanKeyForValue(RegistryHive
,
1710 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1712 DPRINT("Allocate new value cell\n");
1713 Status
= CmiAddValueToKey(RegistryHive
,
1715 KeyObject
->KeyCellOffset
,
1721 if (!NT_SUCCESS(Status
))
1723 DPRINT("Cannot add value. Status 0x%X\n", Status
);
1725 ExReleaseResourceLite(&CmiRegistryLock
);
1726 KeLeaveCriticalRegion();
1727 ObDereferenceObject(KeyObject
);
1731 DPRINT("DataSize %lu\n", DataSize
);
1732 DPRINT("ValueCell %p\n", ValueCell
);
1733 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1735 if (DataSize
<= sizeof(BLOCK_OFFSET
))
1737 /* If data size <= sizeof(BLOCK_OFFSET) then store data in the data offset */
1738 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1739 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1740 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1742 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1743 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
1746 RtlCopyMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
1747 ValueCell
->DataSize
= DataSize
| REG_DATA_IN_OFFSET
;
1748 ValueCell
->DataType
= Type
;
1749 RtlMoveMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
1750 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
1752 else if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1753 (DataSize
<= (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
1755 /* If new data size is <= current then overwrite current data */
1756 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
,&pBin
);
1757 RtlZeroMemory(DataCell
->Data
, ValueCell
->DataSize
);
1758 RtlCopyMemory(DataCell
->Data
, Data
, DataSize
);
1759 ValueCell
->DataSize
= DataSize
;
1760 ValueCell
->DataType
= Type
;
1765 * New data size is larger than the current, destroy current
1766 * data block and allocate a new one.
1768 BLOCK_OFFSET NewOffset
;
1770 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1772 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1773 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1775 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1776 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
1777 ValueCell
->DataSize
= 0;
1778 ValueCell
->DataType
= 0;
1779 ValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
1782 Status
= CmiAllocateCell (RegistryHive
,
1783 sizeof(CELL_HEADER
) + DataSize
,
1784 (PVOID
*)&NewDataCell
,
1786 if (!NT_SUCCESS(Status
))
1788 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status
);
1790 ExReleaseResourceLite(&CmiRegistryLock
);
1791 KeLeaveCriticalRegion();
1792 ObDereferenceObject(KeyObject
);
1797 RtlCopyMemory(&NewDataCell
->Data
[0], Data
, DataSize
);
1798 ValueCell
->DataSize
= DataSize
& REG_DATA_SIZE_MASK
;
1799 ValueCell
->DataType
= Type
;
1800 ValueCell
->DataOffset
= NewOffset
;
1801 CmiMarkBlockDirty(RegistryHive
, ValueCell
->DataOffset
);
1802 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
1806 if ((Type
== REG_LINK
) &&
1807 (_wcsicmp(ValueName
->Buffer
, L
"SymbolicLinkValue") == 0))
1809 KeyCell
->Flags
|= REG_KEY_LINK_CELL
;
1812 KeQuerySystemTime (&KeyCell
->LastWriteTime
);
1813 CmiMarkBlockDirty (RegistryHive
, KeyObject
->KeyCellOffset
);
1815 ExReleaseResourceLite(&CmiRegistryLock
);
1816 KeLeaveCriticalRegion();
1817 ObDereferenceObject(KeyObject
);
1821 DPRINT("Return Status 0x%X\n", Status
);
1828 NtDeleteValueKey (IN HANDLE KeyHandle
,
1829 IN PUNICODE_STRING ValueName
)
1831 PKEY_OBJECT KeyObject
;
1836 /* Verify that the handle is valid and is a registry key */
1837 Status
= ObReferenceObjectByHandle(KeyHandle
,
1841 (PVOID
*)&KeyObject
,
1843 if (!NT_SUCCESS(Status
))
1848 /* Acquire hive lock */
1849 KeEnterCriticalRegion();
1850 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1852 VERIFY_KEY_OBJECT(KeyObject
);
1854 Status
= CmiDeleteValueFromKey(KeyObject
->RegistryHive
,
1856 KeyObject
->KeyCellOffset
,
1859 KeQuerySystemTime (&KeyObject
->KeyCell
->LastWriteTime
);
1860 CmiMarkBlockDirty (KeyObject
->RegistryHive
, KeyObject
->KeyCellOffset
);
1862 /* Release hive lock */
1863 ExReleaseResourceLite(&CmiRegistryLock
);
1864 KeLeaveCriticalRegion();
1866 ObDereferenceObject (KeyObject
);
1876 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1877 * KeyObjectAttributes->Name specifies the name of the key to load.
1880 NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1881 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
1883 return NtLoadKey2 (KeyObjectAttributes
,
1884 FileObjectAttributes
,
1891 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1892 * KeyObjectAttributes->Name specifies the name of the key to load.
1893 * Flags can be 0 or REG_NO_LAZY_FLUSH.
1896 NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1897 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
1900 POBJECT_NAME_INFORMATION NameInfo
;
1901 PUNICODE_STRING NamePointer
;
1909 DPRINT ("NtLoadKey2() called\n");
1912 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, KeGetPreviousMode ()))
1913 return STATUS_PRIVILEGE_NOT_HELD
;
1916 if (FileObjectAttributes
->RootDirectory
!= NULL
)
1919 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1920 Buffer
= ExAllocatePool (NonPagedPool
,
1923 return STATUS_INSUFFICIENT_RESOURCES
;
1925 Status
= ZwQueryObject (FileObjectAttributes
->RootDirectory
,
1926 ObjectNameInformation
,
1930 if (!NT_SUCCESS(Status
))
1932 DPRINT1 ("NtQueryObject() failed (Status %lx)\n", Status
);
1933 ExFreePool (Buffer
);
1937 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
1938 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
1939 &NameInfo
->Name
, NameInfo
->Name
.Length
);
1941 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
1942 if (FileObjectAttributes
->ObjectName
->Buffer
[0] != L
'\\')
1944 RtlAppendUnicodeToString (&NameInfo
->Name
,
1946 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
1947 &NameInfo
->Name
, NameInfo
->Name
.Length
);
1949 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
1950 FileObjectAttributes
->ObjectName
);
1952 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
1953 &NameInfo
->Name
, NameInfo
->Name
.Length
);
1954 NamePointer
= &NameInfo
->Name
;
1958 if (FileObjectAttributes
->ObjectName
->Buffer
[0] == L
'\\')
1961 NamePointer
= FileObjectAttributes
->ObjectName
;
1966 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1967 Buffer
= ExAllocatePool (NonPagedPool
,
1970 return STATUS_INSUFFICIENT_RESOURCES
;
1972 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
1973 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
1974 NameInfo
->Name
.Length
= 0;
1975 NameInfo
->Name
.Buffer
= (PWSTR
)((ULONG_PTR
)Buffer
+ sizeof(OBJECT_NAME_INFORMATION
));
1976 NameInfo
->Name
.Buffer
[0] = 0;
1978 RtlAppendUnicodeToString (&NameInfo
->Name
,
1980 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
1981 FileObjectAttributes
->ObjectName
);
1983 NamePointer
= &NameInfo
->Name
;
1987 DPRINT ("Full name: '%wZ'\n", NamePointer
);
1989 /* Acquire hive lock */
1990 KeEnterCriticalRegion();
1991 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1993 Status
= CmiLoadHive (KeyObjectAttributes
,
1996 if (!NT_SUCCESS (Status
))
1998 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
2001 /* Release hive lock */
2002 ExReleaseResourceLite(&CmiRegistryLock
);
2003 KeLeaveCriticalRegion();
2006 ExFreePool (Buffer
);
2013 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2015 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2016 IN PVOID ApcContext OPTIONAL
,
2017 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2018 IN ULONG CompletionFilter
,
2019 IN BOOLEAN WatchSubtree
,
2022 IN BOOLEAN Asynchronous
)
2025 return(STATUS_NOT_IMPLEMENTED
);
2030 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2032 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2033 IN PVOID ApcContext OPTIONAL
,
2034 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2035 IN ULONG CompletionFilter
,
2036 IN BOOLEAN WatchSubtree
,
2039 IN BOOLEAN Asynchronous
)
2041 return NtNotifyChangeMultipleKeys(KeyHandle
,
2058 NtQueryMultipleValueKey (IN HANDLE KeyHandle
,
2059 IN OUT PKEY_VALUE_ENTRY ValueList
,
2060 IN ULONG NumberOfValues
,
2062 IN OUT PULONG Length
,
2063 OUT PULONG ReturnLength
)
2065 PREGISTRY_HIVE RegistryHive
;
2066 PVALUE_CELL ValueCell
;
2067 PKEY_OBJECT KeyObject
;
2068 PDATA_CELL DataCell
;
2069 ULONG BufferLength
= 0;
2077 /* Verify that the handle is valid and is a registry key */
2078 Status
= ObReferenceObjectByHandle(KeyHandle
,
2082 (PVOID
*) &KeyObject
,
2084 if (!NT_SUCCESS(Status
))
2086 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2090 /* Acquire hive lock */
2091 KeEnterCriticalRegion();
2092 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
2094 VERIFY_KEY_OBJECT(KeyObject
);
2096 /* Get pointer to KeyCell */
2097 KeyCell
= KeyObject
->KeyCell
;
2098 RegistryHive
= KeyObject
->RegistryHive
;
2100 DataPtr
= (PUCHAR
) Buffer
;
2102 for (i
= 0; i
< NumberOfValues
; i
++)
2104 DPRINT("ValueName: '%wZ'\n", ValueList
[i
].ValueName
);
2106 /* Get Value block of interest */
2107 Status
= CmiScanKeyForValue(RegistryHive
,
2109 ValueList
[i
].ValueName
,
2113 if (!NT_SUCCESS(Status
))
2115 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
2118 else if (ValueCell
== NULL
)
2120 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
2124 BufferLength
= ROUND_UP(BufferLength
, sizeof(PVOID
));
2126 if (BufferLength
+ (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) <= *Length
)
2128 DataPtr
= (PUCHAR
)ROUND_UP((ULONG_PTR
)DataPtr
, sizeof(PVOID
));
2130 ValueList
[i
].Type
= ValueCell
->DataType
;
2131 ValueList
[i
].DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2132 ValueList
[i
].DataOffset
= (ULONG_PTR
)DataPtr
- (ULONG_PTR
)Buffer
;
2134 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
2136 DataCell
= CmiGetCell (RegistryHive
,
2137 ValueCell
->DataOffset
,
2139 RtlCopyMemory(DataPtr
,
2141 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2145 RtlCopyMemory(DataPtr
,
2146 &ValueCell
->DataOffset
,
2147 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2150 DataPtr
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2154 Status
= STATUS_BUFFER_TOO_SMALL
;
2157 BufferLength
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2160 if (NT_SUCCESS(Status
))
2161 *Length
= BufferLength
;
2163 *ReturnLength
= BufferLength
;
2165 /* Release hive lock */
2166 ExReleaseResourceLite(&CmiRegistryLock
);
2167 KeLeaveCriticalRegion();
2169 ObDereferenceObject(KeyObject
);
2171 DPRINT("Return Status 0x%X\n", Status
);
2178 NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes
,
2180 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
2183 return(STATUS_NOT_IMPLEMENTED
);
2188 NtRestoreKey (IN HANDLE KeyHandle
,
2189 IN HANDLE FileHandle
,
2190 IN ULONG RestoreFlags
)
2193 return(STATUS_NOT_IMPLEMENTED
);
2198 NtSaveKey (IN HANDLE KeyHandle
,
2199 IN HANDLE FileHandle
)
2201 PREGISTRY_HIVE TempHive
;
2202 PKEY_OBJECT KeyObject
;
2207 DPRINT ("NtSaveKey() called\n");
2210 if (!SeSinglePrivilegeCheck (SeBackupPrivilege
, KeGetPreviousMode ()))
2211 return STATUS_PRIVILEGE_NOT_HELD
;
2214 Status
= ObReferenceObjectByHandle (KeyHandle
,
2217 KeGetPreviousMode(),
2218 (PVOID
*)&KeyObject
,
2220 if (!NT_SUCCESS(Status
))
2222 DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
2226 /* Acquire hive lock exclucively */
2227 KeEnterCriticalRegion();
2228 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2230 /* Refuse to save a volatile key */
2231 if (KeyObject
->RegistryHive
== CmiVolatileHive
)
2233 DPRINT1 ("Cannot save a volatile key\n");
2234 ExReleaseResourceLite(&CmiRegistryLock
);
2235 KeLeaveCriticalRegion();
2236 ObDereferenceObject (KeyObject
);
2237 return STATUS_ACCESS_DENIED
;
2240 Status
= CmiCreateTempHive(&TempHive
);
2241 if (!NT_SUCCESS(Status
))
2243 DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status
);
2244 ExReleaseResourceLite(&CmiRegistryLock
);
2245 KeLeaveCriticalRegion();
2246 ObDereferenceObject (KeyObject
);
2250 Status
= CmiCopyKey (TempHive
,
2252 KeyObject
->RegistryHive
,
2253 KeyObject
->KeyCell
);
2254 if (!NT_SUCCESS(Status
))
2256 DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status
);
2257 CmiRemoveRegistryHive (TempHive
);
2258 ExReleaseResourceLite(&CmiRegistryLock
);
2259 KeLeaveCriticalRegion();
2260 ObDereferenceObject (KeyObject
);
2264 Status
= CmiSaveTempHive (TempHive
,
2266 if (!NT_SUCCESS(Status
))
2268 DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status
);
2271 CmiRemoveRegistryHive (TempHive
);
2273 /* Release hive lock */
2274 ExReleaseResourceLite(&CmiRegistryLock
);
2275 KeLeaveCriticalRegion();
2277 ObDereferenceObject (KeyObject
);
2279 DPRINT ("NtSaveKey() done\n");
2281 return STATUS_SUCCESS
;
2290 IN HANDLE KeyHandle
,
2291 IN HANDLE FileHandle
,
2292 IN ULONG Flags
// REG_STANDARD_FORMAT, etc..
2296 return STATUS_NOT_IMPLEMENTED
;
2301 NtSetInformationKey (IN HANDLE KeyHandle
,
2302 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
2303 IN PVOID KeyInformation
,
2304 IN ULONG KeyInformationLength
)
2306 PKEY_OBJECT KeyObject
;
2311 if (KeyInformationClass
!= KeyWriteTimeInformation
)
2312 return STATUS_INVALID_INFO_CLASS
;
2314 if (KeyInformationLength
!= sizeof (KEY_WRITE_TIME_INFORMATION
))
2315 return STATUS_INFO_LENGTH_MISMATCH
;
2317 /* Verify that the handle is valid and is a registry key */
2318 Status
= ObReferenceObjectByHandle (KeyHandle
,
2322 (PVOID
*)&KeyObject
,
2324 if (!NT_SUCCESS (Status
))
2326 DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2330 /* Acquire hive lock */
2331 KeEnterCriticalRegion();
2332 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2334 VERIFY_KEY_OBJECT(KeyObject
);
2336 KeyObject
->KeyCell
->LastWriteTime
.QuadPart
=
2337 ((PKEY_WRITE_TIME_INFORMATION
)KeyInformation
)->LastWriteTime
.QuadPart
;
2339 CmiMarkBlockDirty (KeyObject
->RegistryHive
,
2340 KeyObject
->KeyCellOffset
);
2342 /* Release hive lock */
2343 ExReleaseResourceLite(&CmiRegistryLock
);
2344 KeLeaveCriticalRegion();
2346 ObDereferenceObject (KeyObject
);
2350 DPRINT ("NtSaveKey() done\n");
2352 return STATUS_SUCCESS
;
2358 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2359 * KeyObjectAttributes->Name specifies the name of the key to unload.
2362 NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
2364 PREGISTRY_HIVE RegistryHive
;
2369 DPRINT ("NtUnloadKey() called\n");
2372 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, KeGetPreviousMode ()))
2373 return STATUS_PRIVILEGE_NOT_HELD
;
2376 /* Acquire registry lock exclusively */
2377 KeEnterCriticalRegion();
2378 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2380 Status
= CmiDisconnectHive (KeyObjectAttributes
,
2382 if (!NT_SUCCESS (Status
))
2384 DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status
);
2385 ExReleaseResourceLite (&CmiRegistryLock
);
2386 KeLeaveCriticalRegion();
2390 DPRINT ("RegistryHive %p\n", RegistryHive
);
2394 if (!IsNoFileHive (RegistryHive
))
2395 CmiFlushRegistryHive (RegistryHive
);
2398 CmiRemoveRegistryHive (RegistryHive
);
2400 /* Release registry lock */
2401 ExReleaseResourceLite (&CmiRegistryLock
);
2402 KeLeaveCriticalRegion();
2404 DPRINT ("NtUnloadKey() done\n");
2406 return STATUS_SUCCESS
;
2411 NtInitializeRegistry (IN BOOLEAN SetUpBoot
)
2417 if (CmiRegistryInitialized
== TRUE
)
2418 return STATUS_ACCESS_DENIED
;
2420 /* Save boot log file */
2421 IopSaveBootLogToFile();
2423 Status
= CmiInitHives (SetUpBoot
);
2425 CmiRegistryInitialized
= TRUE
;