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
;
136 NTSTATUS Status
= STATUS_SUCCESS
;
140 ExAcquireFastMutex(&CmiCallbackLock
);
142 for(CurrentEntry
= CmiCallbackHead
.Flink
;
143 CurrentEntry
!= &CmiCallbackHead
;
144 CurrentEntry
= CurrentEntry
->Flink
)
146 PREGISTRY_CALLBACK CurrentCallback
;
148 CurrentCallback
= CONTAINING_RECORD(CurrentEntry
, REGISTRY_CALLBACK
, ListEntry
);
149 if(!CurrentCallback
->PendingDelete
&&
150 ExAcquireRundownProtectionEx(&CurrentCallback
->RundownRef
, 1))
152 /* don't hold locks during the callbacks! */
153 ExReleaseFastMutex(&CmiCallbackLock
);
155 Status
= CurrentCallback
->Function(CurrentCallback
->Context
,
159 ExAcquireFastMutex(&CmiCallbackLock
);
160 /* don't release the rundown protection before holding the callback lock
161 so the pointer to the next callback isn't cleared in case this callback
163 ExReleaseRundownProtectionEx(&CurrentCallback
->RundownRef
, 1);
164 if(!NT_SUCCESS(Status
))
166 /* one callback returned failure, don't call any more callbacks */
172 ExReleaseFastMutex(&CmiCallbackLock
);
179 NtCreateKey(OUT PHANDLE KeyHandle
,
180 IN ACCESS_MASK DesiredAccess
,
181 IN POBJECT_ATTRIBUTES ObjectAttributes
,
183 IN PUNICODE_STRING Class
,
184 IN ULONG CreateOptions
,
185 OUT PULONG Disposition
)
187 UNICODE_STRING RemainingPath
= {0};
188 BOOLEAN FreeRemainingPath
= TRUE
;
189 ULONG LocalDisposition
;
190 PKEY_OBJECT KeyObject
;
191 NTSTATUS Status
= STATUS_SUCCESS
;
194 UNICODE_STRING ObjectName
;
195 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
197 REG_PRE_CREATE_KEY_INFORMATION PreCreateKeyInfo
;
198 REG_POST_CREATE_KEY_INFORMATION PostCreateKeyInfo
;
199 KPROCESSOR_MODE PreviousMode
;
200 UNICODE_STRING CapturedClass
= {0};
205 PreviousMode
= KeGetPreviousMode();
207 if (PreviousMode
!= KernelMode
)
211 ProbeForWriteHandle(KeyHandle
);
212 if (Disposition
!= NULL
)
214 ProbeForWriteUlong(Disposition
);
219 Status
= _SEH_GetExceptionCode();
223 if (!NT_SUCCESS(Status
))
231 Status
= ProbeAndCaptureUnicodeString(&CapturedClass
,
234 if (!NT_SUCCESS(Status
))
240 /* Capture all the info */
241 DPRINT("Capturing Create Info\n");
242 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
247 if (!NT_SUCCESS(Status
))
249 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
253 PostCreateKeyInfo
.CompleteName
= &ObjectName
;
254 PreCreateKeyInfo
.CompleteName
= &ObjectName
;
255 Status
= CmiCallRegisteredCallbacks(RegNtPreCreateKey
, &PreCreateKeyInfo
);
256 if (!NT_SUCCESS(Status
))
258 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
262 Status
= ObFindObject(&ObjectCreateInfo
,
267 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
268 if (!NT_SUCCESS(Status
))
270 PostCreateKeyInfo
.Object
= NULL
;
271 PostCreateKeyInfo
.Status
= Status
;
272 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
274 DPRINT("CmpFindObject failed, Status: 0x%x\n", Status
);
278 DPRINT("RemainingPath %wZ\n", &RemainingPath
);
280 if (RemainingPath
.Length
== 0)
282 /* Fail if the key has been deleted */
283 if (((PKEY_OBJECT
) Object
)->Flags
& KO_MARKED_FOR_DELETE
)
285 PostCreateKeyInfo
.Object
= NULL
;
286 PostCreateKeyInfo
.Status
= STATUS_UNSUCCESSFUL
;
287 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
289 DPRINT("Object marked for delete!\n");
290 Status
= STATUS_UNSUCCESSFUL
;
294 Status
= ObpCreateHandle(PsGetCurrentProcess(),
300 DPRINT("ObpCreateHandle failed Status 0x%x\n", Status
);
302 PostCreateKeyInfo
.Object
= NULL
;
303 PostCreateKeyInfo
.Status
= Status
;
304 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
306 LocalDisposition
= REG_OPENED_EXISTING_KEY
;
310 /* If RemainingPath contains \ we must return error
311 because NtCreateKey doesn't create trees */
312 Start
= RemainingPath
.Buffer
;
316 for (i
= 1; i
< RemainingPath
.Length
/ sizeof(WCHAR
); i
++)
318 if (L
'\\' == RemainingPath
.Buffer
[i
])
320 DPRINT("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath
);
322 PostCreateKeyInfo
.Object
= NULL
;
323 PostCreateKeyInfo
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
324 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
326 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
331 DPRINT("RemainingPath %S ParentObject 0x%p\n", RemainingPath
.Buffer
, Object
);
333 Status
= ObCreateObject(PreviousMode
,
342 if (!NT_SUCCESS(Status
))
344 DPRINT1("ObCreateObject() failed!\n");
345 PostCreateKeyInfo
.Object
= NULL
;
346 PostCreateKeyInfo
.Status
= Status
;
347 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
352 Status
= ObInsertObject((PVOID
)KeyObject
,
358 if (!NT_SUCCESS(Status
))
360 ObDereferenceObject(KeyObject
);
361 DPRINT1("ObInsertObject() failed!\n");
363 PostCreateKeyInfo
.Object
= NULL
;
364 PostCreateKeyInfo
.Status
= Status
;
365 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
370 KeyObject
->ParentKey
= Object
;
372 if (CreateOptions
& REG_OPTION_VOLATILE
)
373 KeyObject
->RegistryHive
= CmiVolatileHive
;
375 KeyObject
->RegistryHive
= KeyObject
->ParentKey
->RegistryHive
;
377 KeyObject
->Flags
= 0;
378 KeyObject
->NumberOfSubKeys
= 0;
379 KeyObject
->SizeOfSubKeys
= 0;
380 KeyObject
->SubKeys
= NULL
;
382 /* Acquire hive lock */
383 KeEnterCriticalRegion();
384 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
386 InsertTailList(&CmiKeyObjectListHead
, &KeyObject
->ListEntry
);
388 /* add key to subkeys of parent if needed */
389 Status
= CmiAddSubKey(KeyObject
->RegistryHive
,
390 KeyObject
->ParentKey
,
396 if (!NT_SUCCESS(Status
))
398 DPRINT("CmiAddSubKey() failed (Status %lx)\n", Status
);
399 /* Release hive lock */
400 ExReleaseResourceLite(&CmiRegistryLock
);
401 KeLeaveCriticalRegion();
402 ObDereferenceObject(KeyObject
);
404 PostCreateKeyInfo
.Object
= NULL
;
405 PostCreateKeyInfo
.Status
= STATUS_UNSUCCESSFUL
;
406 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
408 Status
= STATUS_UNSUCCESSFUL
;
412 if (Start
== RemainingPath
.Buffer
)
414 KeyObject
->Name
= RemainingPath
;
415 FreeRemainingPath
= FALSE
;
419 RtlpCreateUnicodeString(&KeyObject
->Name
, Start
, NonPagedPool
);
422 if (KeyObject
->RegistryHive
== KeyObject
->ParentKey
->RegistryHive
)
424 KeyObject
->KeyCell
->ParentKeyOffset
= KeyObject
->ParentKey
->KeyCellOffset
;
425 KeyObject
->KeyCell
->SecurityKeyOffset
= KeyObject
->ParentKey
->KeyCell
->SecurityKeyOffset
;
429 KeyObject
->KeyCell
->ParentKeyOffset
= -1;
430 KeyObject
->KeyCell
->SecurityKeyOffset
= -1;
431 /* This key must remain in memory unless it is deleted
432 or file is unloaded */
433 ObReferenceObject(KeyObject
);
436 CmiAddKeyToList(KeyObject
->ParentKey
, KeyObject
);
438 VERIFY_KEY_OBJECT(KeyObject
);
440 /* Release hive lock */
441 ExReleaseResourceLite(&CmiRegistryLock
);
442 KeLeaveCriticalRegion();
444 PostCreateKeyInfo
.Object
= KeyObject
;
445 PostCreateKeyInfo
.Status
= Status
;
446 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
450 LocalDisposition
= REG_CREATED_NEW_KEY
;
456 if (Disposition
!= NULL
)
458 *Disposition
= LocalDisposition
;
463 Status
= _SEH_GetExceptionCode();
470 ReleaseCapturedUnicodeString(&CapturedClass
,
473 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
474 if (FreeRemainingPath
) RtlFreeUnicodeString(&RemainingPath
);
475 if (Object
!= NULL
) ObDereferenceObject(Object
);
482 NtDeleteKey(IN HANDLE KeyHandle
)
484 KPROCESSOR_MODE PreviousMode
;
485 PKEY_OBJECT KeyObject
;
487 REG_DELETE_KEY_INFORMATION DeleteKeyInfo
;
488 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
492 DPRINT("NtDeleteKey(KeyHandle 0x%p) called\n", KeyHandle
);
494 PreviousMode
= ExGetPreviousMode();
496 /* Verify that the handle is valid and is a registry key */
497 Status
= ObReferenceObjectByHandle(KeyHandle
,
503 if (!NT_SUCCESS(Status
))
505 DPRINT1("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
509 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
510 DeleteKeyInfo
.Object
= (PVOID
)KeyObject
;
511 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &DeleteKeyInfo
);
512 if (!NT_SUCCESS(Status
))
514 PostOperationInfo
.Status
= Status
;
515 CmiCallRegisteredCallbacks(RegNtDeleteKey
, &PostOperationInfo
);
516 ObDereferenceObject(KeyObject
);
520 /* Acquire hive lock */
521 KeEnterCriticalRegion();
522 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
524 VERIFY_KEY_OBJECT(KeyObject
);
526 /* Check for subkeys */
527 if (KeyObject
->NumberOfSubKeys
!= 0)
529 Status
= STATUS_CANNOT_DELETE
;
533 /* Set the marked for delete bit in the key object */
534 KeyObject
->Flags
|= KO_MARKED_FOR_DELETE
;
535 Status
= STATUS_SUCCESS
;
538 /* Release hive lock */
539 ExReleaseResourceLite(&CmiRegistryLock
);
540 KeLeaveCriticalRegion();
542 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
544 /* Remove the keep-alive reference */
545 ObDereferenceObject(KeyObject
);
547 if (KeyObject
->RegistryHive
!= KeyObject
->ParentKey
->RegistryHive
)
548 ObDereferenceObject(KeyObject
);
550 PostOperationInfo
.Status
= Status
;
551 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
553 /* Dereference the object */
554 ObDereferenceObject(KeyObject
);
556 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
557 DPRINT("HandleCount %lu\n", ObGetObjectHandleCount((PVOID
)KeyObject
));
561 * Hive-Synchronization will not be triggered here. This is done in
562 * CmiObjectDelete() (in regobj.c) after all key-related structures
563 * have been released.
571 NtEnumerateKey(IN HANDLE KeyHandle
,
573 IN KEY_INFORMATION_CLASS KeyInformationClass
,
574 OUT PVOID KeyInformation
,
576 OUT PULONG ResultLength
)
578 PKEY_OBJECT KeyObject
;
579 PKEY_OBJECT SubKeyObject
;
580 PREGISTRY_HIVE RegistryHive
;
581 PKEY_CELL KeyCell
, SubKeyCell
;
582 PHASH_TABLE_CELL HashTableBlock
;
583 PKEY_BASIC_INFORMATION BasicInformation
;
584 PKEY_NODE_INFORMATION NodeInformation
;
585 PKEY_FULL_INFORMATION FullInformation
;
586 PDATA_CELL ClassCell
;
587 ULONG NameSize
, ClassSize
;
588 KPROCESSOR_MODE PreviousMode
;
590 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo
;
591 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
595 PreviousMode
= ExGetPreviousMode();
597 DPRINT("KH 0x%p I %d KIC %x KI 0x%p L %d RL 0x%p\n",
605 /* Verify that the handle is valid and is a registry key */
606 Status
= ObReferenceObjectByHandle(KeyHandle
,
607 KEY_ENUMERATE_SUB_KEYS
,
610 (PVOID
*) &KeyObject
,
612 if (!NT_SUCCESS(Status
))
614 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
618 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
619 EnumerateKeyInfo
.Object
= (PVOID
)KeyObject
;
620 EnumerateKeyInfo
.Index
= Index
;
621 EnumerateKeyInfo
.KeyInformationClass
= KeyInformationClass
;
622 EnumerateKeyInfo
.Length
= Length
;
623 EnumerateKeyInfo
.ResultLength
= ResultLength
;
625 Status
= CmiCallRegisteredCallbacks(RegNtEnumerateKey
, &EnumerateKeyInfo
);
626 if (!NT_SUCCESS(Status
))
628 ObDereferenceObject(KeyObject
);
632 /* Acquire hive lock */
633 KeEnterCriticalRegion();
634 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
636 VERIFY_KEY_OBJECT(KeyObject
);
638 /* Get pointer to KeyCell */
639 KeyCell
= KeyObject
->KeyCell
;
640 RegistryHive
= KeyObject
->RegistryHive
;
644 /* Check for hightest possible sub key index */
645 if (Index
>= KeyCell
->NumberOfSubKeys
+ KeyObject
->NumberOfSubKeys
)
647 ExReleaseResourceLite(&CmiRegistryLock
);
648 KeLeaveCriticalRegion();
649 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
650 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
651 ObDereferenceObject(KeyObject
);
652 DPRINT("No more volatile entries\n");
653 return STATUS_NO_MORE_ENTRIES
;
656 /* Get pointer to SubKey */
657 if (Index
>= KeyCell
->NumberOfSubKeys
)
659 PKEY_OBJECT CurKey
= NULL
;
663 /* Search for volatile or 'foreign' keys */
664 j
= KeyCell
->NumberOfSubKeys
;
665 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
667 CurKey
= KeyObject
->SubKeys
[i
];
668 if (CurKey
->RegistryHive
!= RegistryHive
)
676 if (i
>= KeyObject
->NumberOfSubKeys
)
678 ExReleaseResourceLite(&CmiRegistryLock
);
679 KeLeaveCriticalRegion();
680 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
681 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
682 ObDereferenceObject(KeyObject
);
683 DPRINT("No more non-volatile entries\n");
684 return STATUS_NO_MORE_ENTRIES
;
687 SubKeyObject
= CurKey
;
688 SubKeyCell
= CurKey
->KeyCell
;
692 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
694 ExReleaseResourceLite(&CmiRegistryLock
);
695 KeLeaveCriticalRegion();
696 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
697 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
698 ObDereferenceObject(KeyObject
);
699 return STATUS_NO_MORE_ENTRIES
;
702 HashTableBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
703 if (HashTableBlock
== NULL
)
705 DPRINT("CmiGetBlock() failed\n");
706 ExReleaseResourceLite(&CmiRegistryLock
);
707 KeLeaveCriticalRegion();
708 PostOperationInfo
.Status
= STATUS_UNSUCCESSFUL
;
709 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
710 ObDereferenceObject(KeyObject
);
711 return STATUS_UNSUCCESSFUL
;
714 SubKeyCell
= CmiGetKeyFromHashByIndex(RegistryHive
,
719 if (SubKeyCell
== NULL
)
721 ExReleaseResourceLite(&CmiRegistryLock
);
722 KeLeaveCriticalRegion();
723 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
724 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
725 ObDereferenceObject(KeyObject
);
726 DPRINT("No more entries\n");
727 return STATUS_NO_MORE_ENTRIES
;
730 Status
= STATUS_SUCCESS
;
731 switch (KeyInformationClass
)
733 case KeyBasicInformation
:
734 /* Check size of buffer */
735 if (SubKeyObject
!= NULL
)
737 NameSize
= SubKeyObject
->Name
.Length
;
741 NameSize
= SubKeyCell
->NameSize
;
742 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
744 NameSize
*= sizeof(WCHAR
);
748 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) + NameSize
;
751 * NOTE: It's perfetly valid to call NtEnumerateKey to get
752 * all the information but name. Actually the NT4 sound
753 * framework does that while querying parameters from registry.
754 * -- Filip Navara, 19/07/2004
756 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
758 Status
= STATUS_BUFFER_TOO_SMALL
;
762 /* Fill buffer with requested info */
763 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
764 BasicInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
765 BasicInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
766 BasicInformation
->TitleIndex
= Index
;
767 BasicInformation
->NameLength
= NameSize
;
769 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) < NameSize
)
771 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
772 Status
= STATUS_BUFFER_OVERFLOW
;
776 if (SubKeyObject
!= NULL
)
778 RtlCopyMemory(BasicInformation
->Name
,
779 SubKeyObject
->Name
.Buffer
,
784 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
786 CmiCopyPackedName(BasicInformation
->Name
,
788 NameSize
/ sizeof(WCHAR
));
792 RtlCopyMemory(BasicInformation
->Name
,
800 case KeyNodeInformation
:
801 /* Check size of buffer */
802 if (SubKeyObject
!= NULL
)
804 NameSize
= SubKeyObject
->Name
.Length
;
808 NameSize
= SubKeyCell
->NameSize
;
809 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
811 NameSize
*= sizeof(WCHAR
);
814 ClassSize
= SubKeyCell
->ClassSize
;
816 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
817 NameSize
+ ClassSize
;
819 if (Length
< FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]))
821 Status
= STATUS_BUFFER_TOO_SMALL
;
825 /* Fill buffer with requested info */
826 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
827 NodeInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
828 NodeInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
829 NodeInformation
->TitleIndex
= Index
;
830 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) + NameSize
;
831 NodeInformation
->ClassLength
= SubKeyCell
->ClassSize
;
832 NodeInformation
->NameLength
= NameSize
;
834 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
836 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
838 Status
= STATUS_BUFFER_OVERFLOW
;
841 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
842 NameSize
< ClassSize
)
844 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
846 Status
= STATUS_BUFFER_OVERFLOW
;
850 if (SubKeyObject
!= NULL
)
852 RtlCopyMemory(NodeInformation
->Name
,
853 SubKeyObject
->Name
.Buffer
,
858 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
860 CmiCopyPackedName(NodeInformation
->Name
,
862 NameSize
/ sizeof(WCHAR
));
866 RtlCopyMemory(NodeInformation
->Name
,
874 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
875 SubKeyCell
->ClassNameOffset
,
877 RtlCopyMemory (NodeInformation
->Name
+ SubKeyCell
->NameSize
,
884 case KeyFullInformation
:
885 ClassSize
= SubKeyCell
->ClassSize
;
887 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) +
890 /* Check size of buffer */
891 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]))
893 Status
= STATUS_BUFFER_TOO_SMALL
;
897 /* Fill buffer with requested info */
898 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
899 FullInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
900 FullInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
901 FullInformation
->TitleIndex
= Index
;
902 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) -
904 FullInformation
->ClassLength
= SubKeyCell
->ClassSize
;
905 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //SubKeyCell->NumberOfSubKeys;
906 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
907 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
908 FullInformation
->Values
= SubKeyCell
->NumberOfValues
;
909 FullInformation
->MaxValueNameLen
=
910 CmiGetMaxValueNameLength(RegistryHive
, SubKeyCell
);
911 FullInformation
->MaxValueDataLen
=
912 CmiGetMaxValueDataLength(RegistryHive
, SubKeyCell
);
914 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
916 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
917 Status
= STATUS_BUFFER_OVERFLOW
;
923 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
924 SubKeyCell
->ClassNameOffset
,
926 RtlCopyMemory (FullInformation
->Class
,
934 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
938 ExReleaseResourceLite(&CmiRegistryLock
);
939 KeLeaveCriticalRegion();
941 PostOperationInfo
.Status
= Status
;
942 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
944 ObDereferenceObject(KeyObject
);
946 DPRINT("Returning status %x\n", Status
);
953 NtEnumerateValueKey(IN HANDLE KeyHandle
,
955 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
956 OUT PVOID KeyValueInformation
,
958 OUT PULONG ResultLength
)
961 PKEY_OBJECT KeyObject
;
962 PREGISTRY_HIVE RegistryHive
;
964 PVALUE_CELL ValueCell
;
966 ULONG NameSize
, DataSize
;
967 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
968 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
969 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
973 DPRINT("KH 0x%p I %d KVIC %x KVI 0x%p L %d RL 0x%p\n",
976 KeyValueInformationClass
,
981 /* Verify that the handle is valid and is a registry key */
982 Status
= ObReferenceObjectByHandle(KeyHandle
,
986 (PVOID
*) &KeyObject
,
989 if (!NT_SUCCESS(Status
))
994 /* Acquire hive lock */
995 KeEnterCriticalRegion();
996 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
998 VERIFY_KEY_OBJECT(KeyObject
);
1000 /* Get pointer to KeyCell */
1001 KeyCell
= KeyObject
->KeyCell
;
1002 RegistryHive
= KeyObject
->RegistryHive
;
1004 /* Get Value block of interest */
1005 Status
= CmiGetValueFromKeyByIndex(RegistryHive
,
1010 if (!NT_SUCCESS(Status
))
1012 ExReleaseResourceLite(&CmiRegistryLock
);
1013 KeLeaveCriticalRegion();
1014 ObDereferenceObject(KeyObject
);
1018 if (ValueCell
!= NULL
)
1020 switch (KeyValueInformationClass
)
1022 case KeyValueBasicInformation
:
1023 NameSize
= ValueCell
->NameSize
;
1024 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1026 NameSize
*= sizeof(WCHAR
);
1029 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) + NameSize
;
1031 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1033 Status
= STATUS_BUFFER_TOO_SMALL
;
1037 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1038 KeyValueInformation
;
1039 ValueBasicInformation
->TitleIndex
= 0;
1040 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1041 ValueBasicInformation
->NameLength
= NameSize
;
1043 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1046 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1047 Status
= STATUS_BUFFER_OVERFLOW
;
1051 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1053 CmiCopyPackedName(ValueBasicInformation
->Name
,
1055 NameSize
/ sizeof(WCHAR
));
1059 RtlCopyMemory(ValueBasicInformation
->Name
,
1066 case KeyValuePartialInformation
:
1067 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1069 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1072 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1074 Status
= STATUS_BUFFER_TOO_SMALL
;
1078 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1079 KeyValueInformation
;
1080 ValuePartialInformation
->TitleIndex
= 0;
1081 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1082 ValuePartialInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1084 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1087 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1088 Status
= STATUS_BUFFER_OVERFLOW
;
1092 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1094 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1095 RtlCopyMemory(ValuePartialInformation
->Data
,
1101 RtlCopyMemory(ValuePartialInformation
->Data
,
1102 &ValueCell
->DataOffset
,
1108 case KeyValueFullInformation
:
1109 NameSize
= ValueCell
->NameSize
;
1110 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1112 NameSize
*= sizeof(WCHAR
);
1114 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1116 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1117 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1119 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1121 Status
= STATUS_BUFFER_TOO_SMALL
;
1125 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1126 KeyValueInformation
;
1127 ValueFullInformation
->TitleIndex
= 0;
1128 ValueFullInformation
->Type
= ValueCell
->DataType
;
1129 ValueFullInformation
->NameLength
= NameSize
;
1130 ValueFullInformation
->DataOffset
=
1131 (ULONG_PTR
)ValueFullInformation
->Name
-
1132 (ULONG_PTR
)ValueFullInformation
+
1133 ValueFullInformation
->NameLength
;
1134 ValueFullInformation
->DataOffset
=
1135 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1136 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1138 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1141 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1143 Status
= STATUS_BUFFER_OVERFLOW
;
1146 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1147 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1149 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) - NameSize
, sizeof(PVOID
));
1150 Status
= STATUS_BUFFER_OVERFLOW
;
1154 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1156 CmiCopyPackedName(ValueFullInformation
->Name
,
1158 NameSize
/ sizeof(WCHAR
));
1162 RtlCopyMemory(ValueFullInformation
->Name
,
1167 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1169 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1170 RtlCopyMemory((PCHAR
) ValueFullInformation
1171 + ValueFullInformation
->DataOffset
,
1172 DataCell
->Data
, DataSize
);
1176 RtlCopyMemory((PCHAR
) ValueFullInformation
1177 + ValueFullInformation
->DataOffset
,
1178 &ValueCell
->DataOffset
, DataSize
);
1184 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1190 Status
= STATUS_UNSUCCESSFUL
;
1193 ExReleaseResourceLite(&CmiRegistryLock
);
1194 KeLeaveCriticalRegion();
1195 ObDereferenceObject(KeyObject
);
1202 NtFlushKey(IN HANDLE KeyHandle
)
1205 PKEY_OBJECT KeyObject
;
1206 PREGISTRY_HIVE RegistryHive
;
1207 KPROCESSOR_MODE PreviousMode
;
1211 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle
);
1213 PreviousMode
= ExGetPreviousMode();
1215 /* Verify that the handle is valid and is a registry key */
1216 Status
= ObReferenceObjectByHandle(KeyHandle
,
1220 (PVOID
*)&KeyObject
,
1222 if (!NT_SUCCESS(Status
))
1227 VERIFY_KEY_OBJECT(KeyObject
);
1229 RegistryHive
= KeyObject
->RegistryHive
;
1231 /* Acquire hive lock */
1232 KeEnterCriticalRegion();
1233 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1235 if (IsNoFileHive(RegistryHive
))
1237 Status
= STATUS_SUCCESS
;
1241 /* Flush non-volatile hive */
1242 Status
= CmiFlushRegistryHive(RegistryHive
);
1245 ExReleaseResourceLite(&CmiRegistryLock
);
1246 KeLeaveCriticalRegion();
1248 ObDereferenceObject(KeyObject
);
1250 return STATUS_SUCCESS
;
1255 NtOpenKey(OUT PHANDLE KeyHandle
,
1256 IN ACCESS_MASK DesiredAccess
,
1257 IN POBJECT_ATTRIBUTES ObjectAttributes
)
1259 UNICODE_STRING RemainingPath
;
1260 KPROCESSOR_MODE PreviousMode
;
1261 PVOID Object
= NULL
;
1263 NTSTATUS Status
= STATUS_SUCCESS
;
1264 UNICODE_STRING ObjectName
;
1265 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
1266 REG_PRE_OPEN_KEY_INFORMATION PreOpenKeyInfo
;
1267 REG_POST_OPEN_KEY_INFORMATION PostOpenKeyInfo
;
1271 DPRINT("NtOpenKey(KH 0x%p DA %x OA 0x%p OA->ON '%wZ'\n",
1275 ObjectAttributes
? ObjectAttributes
->ObjectName
: NULL
);
1277 /* Check place for result handle, if it's null - return immediately */
1278 if (KeyHandle
== NULL
)
1279 return(STATUS_INVALID_PARAMETER
);
1281 PreviousMode
= ExGetPreviousMode();
1283 if(PreviousMode
!= KernelMode
)
1287 ProbeForWriteHandle(KeyHandle
);
1291 Status
= _SEH_GetExceptionCode();
1295 if(!NT_SUCCESS(Status
))
1301 /* WINE checks for the length also */
1302 /*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
1303 return(STATUS_BUFFER_OVERFLOW);*/
1305 /* Capture all the info */
1306 DPRINT("Capturing Create Info\n");
1307 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
1312 if (!NT_SUCCESS(Status
))
1314 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
1318 PostOpenKeyInfo
.CompleteName
= &ObjectName
;
1319 PreOpenKeyInfo
.CompleteName
= &ObjectName
;
1320 Status
= CmiCallRegisteredCallbacks(RegNtPreOpenKey
, &PreOpenKeyInfo
);
1321 if (!NT_SUCCESS(Status
))
1323 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
1324 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
1329 RemainingPath
.Buffer
= NULL
;
1331 Status
= ObFindObject(&ObjectCreateInfo
,
1336 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
1337 if (!NT_SUCCESS(Status
))
1339 DPRINT("CmpFindObject() returned 0x%08lx\n", Status
);
1340 Status
= STATUS_INVALID_HANDLE
; /* Because CmpFindObject returns STATUS_UNSUCCESSFUL */
1341 hKey
= *KeyHandle
; /* Preserve hkResult value */
1342 goto openkey_cleanup
;
1345 VERIFY_KEY_OBJECT((PKEY_OBJECT
) Object
);
1347 DPRINT("RemainingPath '%wZ'\n", &RemainingPath
);
1349 if ((RemainingPath
.Buffer
!= NULL
) && (RemainingPath
.Buffer
[0] != 0))
1351 RtlFreeUnicodeString(&RemainingPath
);
1352 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1354 goto openkey_cleanup
;
1357 RtlFreeUnicodeString(&RemainingPath
);
1359 /* Fail if the key has been deleted */
1360 if (((PKEY_OBJECT
)Object
)->Flags
& KO_MARKED_FOR_DELETE
)
1362 Status
= STATUS_UNSUCCESSFUL
;
1364 goto openkey_cleanup
;
1367 Status
= ObpCreateHandle(PsGetCurrentProcess(),
1373 if (!NT_SUCCESS(Status
))
1378 PostOpenKeyInfo
.Object
= NT_SUCCESS(Status
) ? (PVOID
)Object
: NULL
;
1379 PostOpenKeyInfo
.Status
= Status
;
1380 CmiCallRegisteredCallbacks (RegNtPostOpenKey
, &PostOpenKeyInfo
);
1381 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
1385 ObDereferenceObject(Object
);
1394 Status
= _SEH_GetExceptionCode();
1403 NtQueryKey(IN HANDLE KeyHandle
,
1404 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1405 OUT PVOID KeyInformation
,
1407 OUT PULONG ResultLength
)
1409 PKEY_BASIC_INFORMATION BasicInformation
;
1410 PKEY_NODE_INFORMATION NodeInformation
;
1411 PKEY_FULL_INFORMATION FullInformation
;
1412 PREGISTRY_HIVE RegistryHive
;
1413 PDATA_CELL ClassCell
;
1414 PKEY_OBJECT KeyObject
;
1416 ULONG NameSize
, ClassSize
;
1418 REG_QUERY_KEY_INFORMATION QueryKeyInfo
;
1419 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1423 DPRINT("NtQueryKey(KH 0x%p KIC %x KI 0x%p L %d RL 0x%p)\n",
1425 KeyInformationClass
,
1430 /* Verify that the handle is valid and is a registry key */
1431 Status
= ObReferenceObjectByHandle(KeyHandle
,
1432 (KeyInformationClass
!= KeyNameInformation
? KEY_QUERY_VALUE
: 0),
1435 (PVOID
*) &KeyObject
,
1437 if (!NT_SUCCESS(Status
))
1442 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1443 QueryKeyInfo
.Object
= (PVOID
)KeyObject
;
1444 QueryKeyInfo
.KeyInformationClass
= KeyInformationClass
;
1445 QueryKeyInfo
.KeyInformation
= KeyInformation
;
1446 QueryKeyInfo
.Length
= Length
;
1447 QueryKeyInfo
.ResultLength
= ResultLength
;
1449 Status
= CmiCallRegisteredCallbacks(RegNtQueryKey
, &QueryKeyInfo
);
1450 if (!NT_SUCCESS(Status
))
1452 ObDereferenceObject(KeyObject
);
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 Status
= STATUS_SUCCESS
;
1467 switch (KeyInformationClass
)
1469 case KeyBasicInformation
:
1470 NameSize
= KeyObject
->Name
.Length
;
1472 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1474 /* Check size of buffer */
1475 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
1477 Status
= STATUS_BUFFER_TOO_SMALL
;
1481 /* Fill buffer with requested info */
1482 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
1483 BasicInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1484 BasicInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1485 BasicInformation
->TitleIndex
= 0;
1486 BasicInformation
->NameLength
= KeyObject
->Name
.Length
;
1488 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) <
1491 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1492 Status
= STATUS_BUFFER_OVERFLOW
;
1496 RtlCopyMemory(BasicInformation
->Name
,
1497 KeyObject
->Name
.Buffer
,
1502 case KeyNodeInformation
:
1503 NameSize
= KeyObject
->Name
.Length
;
1504 ClassSize
= KeyCell
->ClassSize
;
1506 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
1507 NameSize
+ ClassSize
;
1509 /* Check size of buffer */
1510 if (Length
< *ResultLength
)
1512 Status
= STATUS_BUFFER_TOO_SMALL
;
1516 /* Fill buffer with requested info */
1517 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
1518 NodeInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1519 NodeInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1520 NodeInformation
->TitleIndex
= 0;
1521 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
1522 KeyObject
->Name
.Length
;
1523 NodeInformation
->ClassLength
= KeyCell
->ClassSize
;
1524 NodeInformation
->NameLength
= KeyObject
->Name
.Length
;
1526 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
1528 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
1530 Status
= STATUS_BUFFER_OVERFLOW
;
1533 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1534 NameSize
< ClassSize
)
1536 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1538 Status
= STATUS_BUFFER_OVERFLOW
;
1542 RtlCopyMemory(NodeInformation
->Name
,
1543 KeyObject
->Name
.Buffer
,
1548 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1549 KeyCell
->ClassNameOffset
,
1551 RtlCopyMemory (NodeInformation
->Name
+ KeyObject
->Name
.Length
,
1558 case KeyFullInformation
:
1559 ClassSize
= KeyCell
->ClassSize
;
1561 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
1564 /* Check size of buffer */
1565 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
))
1567 Status
= STATUS_BUFFER_TOO_SMALL
;
1571 /* Fill buffer with requested info */
1572 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
1573 FullInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1574 FullInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1575 FullInformation
->TitleIndex
= 0;
1576 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) - sizeof(WCHAR
);
1577 FullInformation
->ClassLength
= KeyCell
->ClassSize
;
1578 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //KeyCell->NumberOfSubKeys;
1579 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
1580 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
1581 FullInformation
->Values
= KeyCell
->NumberOfValues
;
1582 FullInformation
->MaxValueNameLen
=
1583 CmiGetMaxValueNameLength(RegistryHive
, KeyCell
);
1584 FullInformation
->MaxValueDataLen
=
1585 CmiGetMaxValueDataLength(RegistryHive
, KeyCell
);
1587 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
1589 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
1590 Status
= STATUS_BUFFER_OVERFLOW
;
1596 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1597 KeyCell
->ClassNameOffset
,
1599 RtlCopyMemory (FullInformation
->Class
,
1600 ClassCell
->Data
, ClassSize
);
1605 case KeyNameInformation
:
1606 case KeyCachedInformation
:
1607 case KeyFlagsInformation
:
1608 DPRINT1("Key information class 0x%x not yet implemented!\n", KeyInformationClass
);
1609 Status
= STATUS_NOT_IMPLEMENTED
;
1613 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
1614 Status
= STATUS_INVALID_INFO_CLASS
;
1618 ExReleaseResourceLite(&CmiRegistryLock
);
1619 KeLeaveCriticalRegion();
1621 PostOperationInfo
.Status
= Status
;
1622 CmiCallRegisteredCallbacks(RegNtPostQueryKey
, &PostOperationInfo
);
1624 ObDereferenceObject(KeyObject
);
1631 NtQueryValueKey(IN HANDLE KeyHandle
,
1632 IN PUNICODE_STRING ValueName
,
1633 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1634 OUT PVOID KeyValueInformation
,
1636 OUT PULONG ResultLength
)
1639 ULONG NameSize
, DataSize
;
1640 PKEY_OBJECT KeyObject
;
1641 PREGISTRY_HIVE RegistryHive
;
1643 PVALUE_CELL ValueCell
;
1644 PDATA_CELL DataCell
;
1645 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
1646 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
1647 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
1648 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo
;
1649 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1653 DPRINT("NtQueryValueKey(KeyHandle 0x%p ValueName %S Length %x)\n",
1654 KeyHandle
, ValueName
->Buffer
, Length
);
1656 /* Verify that the handle is valid and is a registry key */
1657 Status
= ObReferenceObjectByHandle(KeyHandle
,
1661 (PVOID
*)&KeyObject
,
1664 if (!NT_SUCCESS(Status
))
1666 DPRINT1("ObReferenceObjectByHandle() failed with status %x %p\n", Status
, KeyHandle
);
1670 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1671 QueryValueKeyInfo
.Object
= (PVOID
)KeyObject
;
1672 QueryValueKeyInfo
.ValueName
= ValueName
;
1673 QueryValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
1674 QueryValueKeyInfo
.Length
= Length
;
1675 QueryValueKeyInfo
.ResultLength
= ResultLength
;
1677 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
1678 if (!NT_SUCCESS(Status
))
1680 ObDereferenceObject(KeyObject
);
1684 /* Acquire hive lock */
1685 KeEnterCriticalRegion();
1686 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1688 VERIFY_KEY_OBJECT(KeyObject
);
1690 /* Get pointer to KeyCell */
1691 KeyCell
= KeyObject
->KeyCell
;
1692 RegistryHive
= KeyObject
->RegistryHive
;
1694 /* Get value cell by name */
1695 Status
= CmiScanKeyForValue(RegistryHive
,
1700 if (!NT_SUCCESS(Status
))
1702 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
1706 Status
= STATUS_SUCCESS
;
1707 switch (KeyValueInformationClass
)
1709 case KeyValueBasicInformation
:
1710 NameSize
= ValueCell
->NameSize
;
1711 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1713 NameSize
*= sizeof(WCHAR
);
1716 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) +
1719 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1721 Status
= STATUS_BUFFER_TOO_SMALL
;
1725 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1726 KeyValueInformation
;
1727 ValueBasicInformation
->TitleIndex
= 0;
1728 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1729 ValueBasicInformation
->NameLength
= NameSize
;
1731 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1734 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1735 Status
= STATUS_BUFFER_OVERFLOW
;
1739 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1741 CmiCopyPackedName(ValueBasicInformation
->Name
,
1743 NameSize
/ sizeof(WCHAR
));
1747 RtlCopyMemory(ValueBasicInformation
->Name
,
1754 case KeyValuePartialInformation
:
1755 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1757 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1760 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1762 Status
= STATUS_BUFFER_TOO_SMALL
;
1766 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1767 KeyValueInformation
;
1768 ValuePartialInformation
->TitleIndex
= 0;
1769 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1770 ValuePartialInformation
->DataLength
= DataSize
;
1772 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1775 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1776 Status
= STATUS_BUFFER_OVERFLOW
;
1780 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1782 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1783 RtlCopyMemory(ValuePartialInformation
->Data
,
1789 RtlCopyMemory(ValuePartialInformation
->Data
,
1790 &ValueCell
->DataOffset
,
1796 case KeyValueFullInformation
:
1797 NameSize
= ValueCell
->NameSize
;
1798 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1800 NameSize
*= sizeof(WCHAR
);
1802 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1804 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1805 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1807 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1809 Status
= STATUS_BUFFER_TOO_SMALL
;
1813 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1814 KeyValueInformation
;
1815 ValueFullInformation
->TitleIndex
= 0;
1816 ValueFullInformation
->Type
= ValueCell
->DataType
;
1817 ValueFullInformation
->NameLength
= NameSize
;
1818 ValueFullInformation
->DataOffset
=
1819 (ULONG_PTR
)ValueFullInformation
->Name
-
1820 (ULONG_PTR
)ValueFullInformation
+
1821 ValueFullInformation
->NameLength
;
1822 ValueFullInformation
->DataOffset
=
1823 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1824 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1826 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1829 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1831 Status
= STATUS_BUFFER_OVERFLOW
;
1834 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1835 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1837 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1838 Name
[0]) - NameSize
, sizeof(PVOID
));
1839 Status
= STATUS_BUFFER_OVERFLOW
;
1843 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1845 CmiCopyPackedName(ValueFullInformation
->Name
,
1847 NameSize
/ sizeof(WCHAR
));
1851 RtlCopyMemory(ValueFullInformation
->Name
,
1855 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1857 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1858 RtlCopyMemory((PCHAR
) ValueFullInformation
1859 + ValueFullInformation
->DataOffset
,
1865 RtlCopyMemory((PCHAR
) ValueFullInformation
1866 + ValueFullInformation
->DataOffset
,
1867 &ValueCell
->DataOffset
,
1874 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1875 Status
= STATUS_INVALID_INFO_CLASS
;
1880 ExReleaseResourceLite(&CmiRegistryLock
);
1881 KeLeaveCriticalRegion();
1883 PostOperationInfo
.Status
= Status
;
1884 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
1885 ObDereferenceObject(KeyObject
);
1892 NtSetValueKey(IN HANDLE KeyHandle
,
1893 IN PUNICODE_STRING ValueName
,
1894 IN ULONG TitleIndex
,
1900 PKEY_OBJECT KeyObject
;
1901 PREGISTRY_HIVE RegistryHive
;
1903 PVALUE_CELL ValueCell
;
1904 BLOCK_OFFSET ValueCellOffset
;
1905 PDATA_CELL DataCell
;
1906 PDATA_CELL NewDataCell
;
1908 ULONG DesiredAccess
;
1909 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo
;
1910 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1914 DPRINT("NtSetValueKey(KeyHandle 0x%p ValueName '%wZ' Type %d)\n",
1915 KeyHandle
, ValueName
, Type
);
1917 DesiredAccess
= KEY_SET_VALUE
;
1919 /* Verify that the handle is valid and is a registry key */
1920 Status
= ObReferenceObjectByHandle(KeyHandle
,
1923 ExGetPreviousMode(),
1924 (PVOID
*)&KeyObject
,
1926 if (!NT_SUCCESS(Status
))
1929 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1930 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
1931 SetValueKeyInfo
.ValueName
= ValueName
;
1932 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
1933 SetValueKeyInfo
.Type
= Type
;
1934 SetValueKeyInfo
.Data
= Data
;
1935 SetValueKeyInfo
.DataSize
= DataSize
;
1936 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
1937 if (!NT_SUCCESS(Status
))
1939 ObDereferenceObject(KeyObject
);
1943 /* Acquire hive lock exclucively */
1944 KeEnterCriticalRegion();
1945 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1947 VERIFY_KEY_OBJECT(KeyObject
);
1949 /* Get pointer to key cell */
1950 KeyCell
= KeyObject
->KeyCell
;
1951 RegistryHive
= KeyObject
->RegistryHive
;
1952 Status
= CmiScanKeyForValue(RegistryHive
,
1957 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1959 DPRINT("Allocate new value cell\n");
1960 Status
= CmiAddValueToKey(RegistryHive
,
1962 KeyObject
->KeyCellOffset
,
1968 if (!NT_SUCCESS(Status
))
1970 DPRINT("Cannot add value. Status 0x%X\n", Status
);
1972 ExReleaseResourceLite(&CmiRegistryLock
);
1973 KeLeaveCriticalRegion();
1974 PostOperationInfo
.Status
= Status
;
1975 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
1976 ObDereferenceObject(KeyObject
);
1980 DPRINT("DataSize %lu\n", DataSize
);
1981 DPRINT("ValueCell %p\n", ValueCell
);
1982 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1984 if (DataSize
<= sizeof(BLOCK_OFFSET
))
1986 /* If data size <= sizeof(BLOCK_OFFSET) then store data in the data offset */
1987 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1988 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1989 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1991 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1992 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
1995 RtlCopyMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
1996 ValueCell
->DataSize
= DataSize
| REG_DATA_IN_OFFSET
;
1997 ValueCell
->DataType
= Type
;
1998 RtlMoveMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
1999 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
2001 else if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
2002 (DataSize
<= (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
2004 /* If new data size is <= current then overwrite current data */
2005 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
,&pBin
);
2006 RtlZeroMemory(DataCell
->Data
, ValueCell
->DataSize
);
2007 RtlCopyMemory(DataCell
->Data
, Data
, DataSize
);
2008 ValueCell
->DataSize
= DataSize
;
2009 ValueCell
->DataType
= Type
;
2014 * New data size is larger than the current, destroy current
2015 * data block and allocate a new one.
2017 BLOCK_OFFSET NewOffset
;
2019 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
2021 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
2022 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
2024 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
2025 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
2026 ValueCell
->DataSize
= 0;
2027 ValueCell
->DataType
= 0;
2028 ValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
2031 Status
= CmiAllocateCell (RegistryHive
,
2032 sizeof(CELL_HEADER
) + DataSize
,
2033 (PVOID
*)&NewDataCell
,
2035 if (!NT_SUCCESS(Status
))
2037 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status
);
2039 ExReleaseResourceLite(&CmiRegistryLock
);
2040 KeLeaveCriticalRegion();
2041 PostOperationInfo
.Status
= Status
;
2042 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
2043 ObDereferenceObject(KeyObject
);
2048 RtlCopyMemory(&NewDataCell
->Data
[0], Data
, DataSize
);
2049 ValueCell
->DataSize
= DataSize
& REG_DATA_SIZE_MASK
;
2050 ValueCell
->DataType
= Type
;
2051 ValueCell
->DataOffset
= NewOffset
;
2052 CmiMarkBlockDirty(RegistryHive
, ValueCell
->DataOffset
);
2053 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
2057 if ((Type
== REG_LINK
) &&
2058 (_wcsicmp(ValueName
->Buffer
, L
"SymbolicLinkValue") == 0))
2060 KeyCell
->Flags
|= REG_KEY_LINK_CELL
;
2063 KeQuerySystemTime (&KeyCell
->LastWriteTime
);
2064 CmiMarkBlockDirty (RegistryHive
, KeyObject
->KeyCellOffset
);
2066 ExReleaseResourceLite(&CmiRegistryLock
);
2067 KeLeaveCriticalRegion();
2068 PostOperationInfo
.Status
= Status
;
2069 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
2070 ObDereferenceObject(KeyObject
);
2074 DPRINT("Return Status 0x%X\n", Status
);
2081 NtDeleteValueKey (IN HANDLE KeyHandle
,
2082 IN PUNICODE_STRING ValueName
)
2084 PKEY_OBJECT KeyObject
;
2086 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
2087 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2088 KPROCESSOR_MODE PreviousMode
;
2089 UNICODE_STRING CapturedValueName
;
2093 PreviousMode
= KeGetPreviousMode();
2095 /* Verify that the handle is valid and is a registry key */
2096 Status
= ObReferenceObjectByHandle(KeyHandle
,
2100 (PVOID
*)&KeyObject
,
2102 if (!NT_SUCCESS(Status
))
2107 Status
= ProbeAndCaptureUnicodeString(&CapturedValueName
,
2110 if (!NT_SUCCESS(Status
))
2114 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
2115 DeleteValueKeyInfo
.ValueName
= &CapturedValueName
;
2117 /* FIXME - check if value exists before calling the callbacks? */
2118 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
, &DeleteValueKeyInfo
);
2119 if (!NT_SUCCESS(Status
))
2121 ReleaseCapturedUnicodeString(&CapturedValueName
,
2124 ObDereferenceObject(KeyObject
);
2128 /* Acquire hive lock */
2129 KeEnterCriticalRegion();
2130 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2132 VERIFY_KEY_OBJECT(KeyObject
);
2134 Status
= CmiDeleteValueFromKey(KeyObject
->RegistryHive
,
2136 KeyObject
->KeyCellOffset
,
2139 KeQuerySystemTime (&KeyObject
->KeyCell
->LastWriteTime
);
2140 CmiMarkBlockDirty (KeyObject
->RegistryHive
, KeyObject
->KeyCellOffset
);
2142 /* Release hive lock */
2143 ExReleaseResourceLite(&CmiRegistryLock
);
2144 KeLeaveCriticalRegion();
2146 ReleaseCapturedUnicodeString(&CapturedValueName
,
2149 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2150 PostOperationInfo
.Status
= Status
;
2152 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
, &PostOperationInfo
);
2154 ObDereferenceObject (KeyObject
);
2164 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2165 * KeyObjectAttributes->Name specifies the name of the key to load.
2168 NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
2169 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
2171 return NtLoadKey2 (KeyObjectAttributes
,
2172 FileObjectAttributes
,
2179 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2180 * KeyObjectAttributes->Name specifies the name of the key to load.
2181 * Flags can be 0 or REG_NO_LAZY_FLUSH.
2184 NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
2185 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
2188 POBJECT_NAME_INFORMATION NameInfo
;
2189 PUNICODE_STRING NamePointer
;
2197 DPRINT ("NtLoadKey2() called\n");
2200 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, KeGetPreviousMode ()))
2201 return STATUS_PRIVILEGE_NOT_HELD
;
2204 if (FileObjectAttributes
->RootDirectory
!= NULL
)
2207 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2208 Buffer
= ExAllocatePool (NonPagedPool
,
2211 return STATUS_INSUFFICIENT_RESOURCES
;
2213 Status
= ZwQueryObject (FileObjectAttributes
->RootDirectory
,
2214 ObjectNameInformation
,
2218 if (!NT_SUCCESS(Status
))
2220 DPRINT1 ("NtQueryObject() failed (Status %lx)\n", Status
);
2221 ExFreePool (Buffer
);
2225 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2226 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2227 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2229 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2230 if (FileObjectAttributes
->ObjectName
->Buffer
[0] != L
'\\')
2232 RtlAppendUnicodeToString (&NameInfo
->Name
,
2234 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2235 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2237 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2238 FileObjectAttributes
->ObjectName
);
2240 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2241 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2242 NamePointer
= &NameInfo
->Name
;
2246 if (FileObjectAttributes
->ObjectName
->Buffer
[0] == L
'\\')
2249 NamePointer
= FileObjectAttributes
->ObjectName
;
2254 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2255 Buffer
= ExAllocatePool (NonPagedPool
,
2258 return STATUS_INSUFFICIENT_RESOURCES
;
2260 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2261 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2262 NameInfo
->Name
.Length
= 0;
2263 NameInfo
->Name
.Buffer
= (PWSTR
)((ULONG_PTR
)Buffer
+ sizeof(OBJECT_NAME_INFORMATION
));
2264 NameInfo
->Name
.Buffer
[0] = 0;
2266 RtlAppendUnicodeToString (&NameInfo
->Name
,
2268 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2269 FileObjectAttributes
->ObjectName
);
2271 NamePointer
= &NameInfo
->Name
;
2275 DPRINT ("Full name: '%wZ'\n", NamePointer
);
2277 /* Acquire hive lock */
2278 KeEnterCriticalRegion();
2279 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2281 Status
= CmiLoadHive (KeyObjectAttributes
,
2284 if (!NT_SUCCESS (Status
))
2286 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
2289 /* Release hive lock */
2290 ExReleaseResourceLite(&CmiRegistryLock
);
2291 KeLeaveCriticalRegion();
2294 ExFreePool (Buffer
);
2301 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2303 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2304 IN PVOID ApcContext OPTIONAL
,
2305 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2306 IN ULONG CompletionFilter
,
2307 IN BOOLEAN WatchSubtree
,
2310 IN BOOLEAN Asynchronous
)
2313 return(STATUS_NOT_IMPLEMENTED
);
2318 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2320 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2321 IN PVOID ApcContext OPTIONAL
,
2322 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2323 IN ULONG CompletionFilter
,
2324 IN BOOLEAN WatchSubtree
,
2327 IN BOOLEAN Asynchronous
)
2329 return NtNotifyChangeMultipleKeys(KeyHandle
,
2346 NtQueryMultipleValueKey (IN HANDLE KeyHandle
,
2347 IN OUT PKEY_VALUE_ENTRY ValueList
,
2348 IN ULONG NumberOfValues
,
2350 IN OUT PULONG Length
,
2351 OUT PULONG ReturnLength
)
2353 PREGISTRY_HIVE RegistryHive
;
2354 PVALUE_CELL ValueCell
;
2355 PKEY_OBJECT KeyObject
;
2356 PDATA_CELL DataCell
;
2357 ULONG BufferLength
= 0;
2362 REG_QUERY_MULTIPLE_VALUE_KEY_INFORMATION QueryMultipleValueKeyInfo
;
2363 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2367 /* Verify that the handle is valid and is a registry key */
2368 Status
= ObReferenceObjectByHandle(KeyHandle
,
2372 (PVOID
*) &KeyObject
,
2374 if (!NT_SUCCESS(Status
))
2376 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2380 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2381 QueryMultipleValueKeyInfo
.Object
= (PVOID
)KeyObject
;
2382 QueryMultipleValueKeyInfo
.ValueEntries
= ValueList
;
2383 QueryMultipleValueKeyInfo
.EntryCount
= NumberOfValues
;
2384 QueryMultipleValueKeyInfo
.ValueBuffer
= Buffer
;
2385 QueryMultipleValueKeyInfo
.BufferLength
= Length
;
2386 QueryMultipleValueKeyInfo
.RequiredBufferLength
= ReturnLength
;
2388 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryMultipleValueKey
, &QueryMultipleValueKeyInfo
);
2389 if (!NT_SUCCESS(Status
))
2391 ObDereferenceObject(KeyObject
);
2395 /* Acquire hive lock */
2396 KeEnterCriticalRegion();
2397 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
2399 VERIFY_KEY_OBJECT(KeyObject
);
2401 /* Get pointer to KeyCell */
2402 KeyCell
= KeyObject
->KeyCell
;
2403 RegistryHive
= KeyObject
->RegistryHive
;
2405 DataPtr
= (PUCHAR
) Buffer
;
2407 for (i
= 0; i
< NumberOfValues
; i
++)
2409 DPRINT("ValueName: '%wZ'\n", ValueList
[i
].ValueName
);
2411 /* Get Value block of interest */
2412 Status
= CmiScanKeyForValue(RegistryHive
,
2414 ValueList
[i
].ValueName
,
2418 if (!NT_SUCCESS(Status
))
2420 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
2423 else if (ValueCell
== NULL
)
2425 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
2429 BufferLength
= ROUND_UP(BufferLength
, sizeof(PVOID
));
2431 if (BufferLength
+ (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) <= *Length
)
2433 DataPtr
= (PUCHAR
)ROUND_UP((ULONG_PTR
)DataPtr
, sizeof(PVOID
));
2435 ValueList
[i
].Type
= ValueCell
->DataType
;
2436 ValueList
[i
].DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2437 ValueList
[i
].DataOffset
= (ULONG_PTR
)DataPtr
- (ULONG_PTR
)Buffer
;
2439 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
2441 DataCell
= CmiGetCell (RegistryHive
,
2442 ValueCell
->DataOffset
,
2444 RtlCopyMemory(DataPtr
,
2446 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2450 RtlCopyMemory(DataPtr
,
2451 &ValueCell
->DataOffset
,
2452 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2455 DataPtr
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2459 Status
= STATUS_BUFFER_TOO_SMALL
;
2462 BufferLength
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2465 if (NT_SUCCESS(Status
))
2466 *Length
= BufferLength
;
2468 *ReturnLength
= BufferLength
;
2470 /* Release hive lock */
2471 ExReleaseResourceLite(&CmiRegistryLock
);
2472 KeLeaveCriticalRegion();
2474 PostOperationInfo
.Status
= Status
;
2475 CmiCallRegisteredCallbacks(RegNtPostQueryMultipleValueKey
, &PostOperationInfo
);
2477 ObDereferenceObject(KeyObject
);
2479 DPRINT("Return Status 0x%X\n", Status
);
2486 NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes
,
2488 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
2491 return(STATUS_NOT_IMPLEMENTED
);
2496 NtRestoreKey (IN HANDLE KeyHandle
,
2497 IN HANDLE FileHandle
,
2498 IN ULONG RestoreFlags
)
2501 return(STATUS_NOT_IMPLEMENTED
);
2506 NtSaveKey (IN HANDLE KeyHandle
,
2507 IN HANDLE FileHandle
)
2509 PREGISTRY_HIVE TempHive
;
2510 PKEY_OBJECT KeyObject
;
2515 DPRINT ("NtSaveKey() called\n");
2518 if (!SeSinglePrivilegeCheck (SeBackupPrivilege
, KeGetPreviousMode ()))
2519 return STATUS_PRIVILEGE_NOT_HELD
;
2522 Status
= ObReferenceObjectByHandle (KeyHandle
,
2525 KeGetPreviousMode(),
2526 (PVOID
*)&KeyObject
,
2528 if (!NT_SUCCESS(Status
))
2530 DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
2534 /* Acquire hive lock exclucively */
2535 KeEnterCriticalRegion();
2536 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2538 /* Refuse to save a volatile key */
2539 if (KeyObject
->RegistryHive
== CmiVolatileHive
)
2541 DPRINT1 ("Cannot save a volatile key\n");
2542 ExReleaseResourceLite(&CmiRegistryLock
);
2543 KeLeaveCriticalRegion();
2544 ObDereferenceObject (KeyObject
);
2545 return STATUS_ACCESS_DENIED
;
2548 Status
= CmiCreateTempHive(&TempHive
);
2549 if (!NT_SUCCESS(Status
))
2551 DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status
);
2552 ExReleaseResourceLite(&CmiRegistryLock
);
2553 KeLeaveCriticalRegion();
2554 ObDereferenceObject (KeyObject
);
2558 Status
= CmiCopyKey (TempHive
,
2560 KeyObject
->RegistryHive
,
2561 KeyObject
->KeyCell
);
2562 if (!NT_SUCCESS(Status
))
2564 DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status
);
2565 CmiRemoveRegistryHive (TempHive
);
2566 ExReleaseResourceLite(&CmiRegistryLock
);
2567 KeLeaveCriticalRegion();
2568 ObDereferenceObject (KeyObject
);
2572 Status
= CmiSaveTempHive (TempHive
,
2574 if (!NT_SUCCESS(Status
))
2576 DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status
);
2579 CmiRemoveRegistryHive (TempHive
);
2581 /* Release hive lock */
2582 ExReleaseResourceLite(&CmiRegistryLock
);
2583 KeLeaveCriticalRegion();
2585 ObDereferenceObject (KeyObject
);
2587 DPRINT ("NtSaveKey() done\n");
2589 return STATUS_SUCCESS
;
2598 IN HANDLE KeyHandle
,
2599 IN HANDLE FileHandle
,
2600 IN ULONG Flags
// REG_STANDARD_FORMAT, etc..
2604 return STATUS_NOT_IMPLEMENTED
;
2609 NtSetInformationKey (IN HANDLE KeyHandle
,
2610 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
2611 IN PVOID KeyInformation
,
2612 IN ULONG KeyInformationLength
)
2614 PKEY_OBJECT KeyObject
;
2616 REG_SET_INFORMATION_KEY_INFORMATION SetInformationKeyInfo
;
2617 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2621 /* Verify that the handle is valid and is a registry key */
2622 Status
= ObReferenceObjectByHandle (KeyHandle
,
2626 (PVOID
*)&KeyObject
,
2628 if (!NT_SUCCESS (Status
))
2630 DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2634 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2635 SetInformationKeyInfo
.Object
= (PVOID
)KeyObject
;
2636 SetInformationKeyInfo
.KeySetInformationClass
= KeyInformationClass
;
2637 SetInformationKeyInfo
.KeySetInformation
= KeyInformation
;
2638 SetInformationKeyInfo
.KeySetInformationLength
= KeyInformationLength
;
2640 Status
= CmiCallRegisteredCallbacks(RegNtSetInformationKey
, &SetInformationKeyInfo
);
2641 if (!NT_SUCCESS(Status
))
2643 ObDereferenceObject (KeyObject
);
2647 if (KeyInformationClass
!= KeyWriteTimeInformation
)
2649 Status
= STATUS_INVALID_INFO_CLASS
;
2652 else if (KeyInformationLength
!= sizeof (KEY_WRITE_TIME_INFORMATION
))
2654 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2658 /* Acquire hive lock */
2659 KeEnterCriticalRegion();
2660 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2662 VERIFY_KEY_OBJECT(KeyObject
);
2664 KeyObject
->KeyCell
->LastWriteTime
.QuadPart
=
2665 ((PKEY_WRITE_TIME_INFORMATION
)KeyInformation
)->LastWriteTime
.QuadPart
;
2667 CmiMarkBlockDirty (KeyObject
->RegistryHive
,
2668 KeyObject
->KeyCellOffset
);
2670 /* Release hive lock */
2671 ExReleaseResourceLite(&CmiRegistryLock
);
2672 KeLeaveCriticalRegion();
2675 PostOperationInfo
.Status
= Status
;
2676 CmiCallRegisteredCallbacks(RegNtPostSetInformationKey
, &PostOperationInfo
);
2678 ObDereferenceObject (KeyObject
);
2680 if (NT_SUCCESS(Status
))
2685 DPRINT ("NtSaveKey() done\n");
2687 return STATUS_SUCCESS
;
2693 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2694 * KeyObjectAttributes->Name specifies the name of the key to unload.
2697 NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
2699 PREGISTRY_HIVE RegistryHive
;
2704 DPRINT ("NtUnloadKey() called\n");
2707 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, KeGetPreviousMode ()))
2708 return STATUS_PRIVILEGE_NOT_HELD
;
2711 /* Acquire registry lock exclusively */
2712 KeEnterCriticalRegion();
2713 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2715 Status
= CmiDisconnectHive (KeyObjectAttributes
,
2717 if (!NT_SUCCESS (Status
))
2719 DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status
);
2720 ExReleaseResourceLite (&CmiRegistryLock
);
2721 KeLeaveCriticalRegion();
2725 DPRINT ("RegistryHive %p\n", RegistryHive
);
2729 if (!IsNoFileHive (RegistryHive
))
2730 CmiFlushRegistryHive (RegistryHive
);
2733 CmiRemoveRegistryHive (RegistryHive
);
2735 /* Release registry lock */
2736 ExReleaseResourceLite (&CmiRegistryLock
);
2737 KeLeaveCriticalRegion();
2739 DPRINT ("NtUnloadKey() done\n");
2741 return STATUS_SUCCESS
;
2746 NtInitializeRegistry (IN BOOLEAN SetUpBoot
)
2752 if (CmiRegistryInitialized
== TRUE
)
2753 return STATUS_ACCESS_DENIED
;
2755 /* Save boot log file */
2756 IopSaveBootLogToFile();
2758 Status
= CmiInitHives (SetUpBoot
);
2760 CmiRegistryInitialized
= TRUE
;