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
= ExGetPreviousMode();
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
< ValueFullInformation
->DataOffset
)
1140 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1142 Status
= STATUS_BUFFER_OVERFLOW
;
1145 else if (Length
- ValueFullInformation
->DataOffset
< DataSize
)
1147 DataSize
= Length
- ValueFullInformation
->DataOffset
;
1148 Status
= STATUS_BUFFER_OVERFLOW
;
1152 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1154 CmiCopyPackedName(ValueFullInformation
->Name
,
1156 NameSize
/ sizeof(WCHAR
));
1160 RtlCopyMemory(ValueFullInformation
->Name
,
1165 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1167 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1168 RtlCopyMemory((PCHAR
) ValueFullInformation
1169 + ValueFullInformation
->DataOffset
,
1170 DataCell
->Data
, DataSize
);
1174 RtlCopyMemory((PCHAR
) ValueFullInformation
1175 + ValueFullInformation
->DataOffset
,
1176 &ValueCell
->DataOffset
, DataSize
);
1182 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1188 Status
= STATUS_UNSUCCESSFUL
;
1191 ExReleaseResourceLite(&CmiRegistryLock
);
1192 KeLeaveCriticalRegion();
1193 ObDereferenceObject(KeyObject
);
1200 NtFlushKey(IN HANDLE KeyHandle
)
1203 PKEY_OBJECT KeyObject
;
1204 PREGISTRY_HIVE RegistryHive
;
1205 KPROCESSOR_MODE PreviousMode
;
1209 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle
);
1211 PreviousMode
= ExGetPreviousMode();
1213 /* Verify that the handle is valid and is a registry key */
1214 Status
= ObReferenceObjectByHandle(KeyHandle
,
1218 (PVOID
*)&KeyObject
,
1220 if (!NT_SUCCESS(Status
))
1225 VERIFY_KEY_OBJECT(KeyObject
);
1227 RegistryHive
= KeyObject
->RegistryHive
;
1229 /* Acquire hive lock */
1230 KeEnterCriticalRegion();
1231 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1233 if (IsNoFileHive(RegistryHive
))
1235 Status
= STATUS_SUCCESS
;
1239 /* Flush non-volatile hive */
1240 Status
= CmiFlushRegistryHive(RegistryHive
);
1243 ExReleaseResourceLite(&CmiRegistryLock
);
1244 KeLeaveCriticalRegion();
1246 ObDereferenceObject(KeyObject
);
1248 return STATUS_SUCCESS
;
1253 NtOpenKey(OUT PHANDLE KeyHandle
,
1254 IN ACCESS_MASK DesiredAccess
,
1255 IN POBJECT_ATTRIBUTES ObjectAttributes
)
1257 UNICODE_STRING RemainingPath
;
1258 KPROCESSOR_MODE PreviousMode
;
1259 PVOID Object
= NULL
;
1261 NTSTATUS Status
= STATUS_SUCCESS
;
1262 UNICODE_STRING ObjectName
;
1263 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
1264 REG_PRE_OPEN_KEY_INFORMATION PreOpenKeyInfo
;
1265 REG_POST_OPEN_KEY_INFORMATION PostOpenKeyInfo
;
1269 DPRINT("NtOpenKey(KH 0x%p DA %x OA 0x%p OA->ON '%wZ'\n",
1273 ObjectAttributes
? ObjectAttributes
->ObjectName
: NULL
);
1275 /* Check place for result handle, if it's null - return immediately */
1276 if (KeyHandle
== NULL
)
1277 return(STATUS_INVALID_PARAMETER
);
1279 PreviousMode
= ExGetPreviousMode();
1281 if(PreviousMode
!= KernelMode
)
1285 ProbeForWriteHandle(KeyHandle
);
1289 Status
= _SEH_GetExceptionCode();
1293 if(!NT_SUCCESS(Status
))
1299 /* WINE checks for the length also */
1300 /*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
1301 return(STATUS_BUFFER_OVERFLOW);*/
1303 /* Capture all the info */
1304 DPRINT("Capturing Create Info\n");
1305 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
1310 if (!NT_SUCCESS(Status
))
1312 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
1316 PostOpenKeyInfo
.CompleteName
= &ObjectName
;
1317 PreOpenKeyInfo
.CompleteName
= &ObjectName
;
1318 Status
= CmiCallRegisteredCallbacks(RegNtPreOpenKey
, &PreOpenKeyInfo
);
1319 if (!NT_SUCCESS(Status
))
1321 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
1322 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
1327 RemainingPath
.Buffer
= NULL
;
1329 Status
= ObFindObject(&ObjectCreateInfo
,
1334 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
1335 if (!NT_SUCCESS(Status
))
1337 DPRINT("CmpFindObject() returned 0x%08lx\n", Status
);
1338 Status
= STATUS_INVALID_HANDLE
; /* Because CmpFindObject returns STATUS_UNSUCCESSFUL */
1339 hKey
= *KeyHandle
; /* Preserve hkResult value */
1340 goto openkey_cleanup
;
1343 VERIFY_KEY_OBJECT((PKEY_OBJECT
) Object
);
1345 DPRINT("RemainingPath '%wZ'\n", &RemainingPath
);
1347 if ((RemainingPath
.Buffer
!= NULL
) && (RemainingPath
.Buffer
[0] != 0))
1349 RtlFreeUnicodeString(&RemainingPath
);
1350 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1352 goto openkey_cleanup
;
1355 RtlFreeUnicodeString(&RemainingPath
);
1357 /* Fail if the key has been deleted */
1358 if (((PKEY_OBJECT
)Object
)->Flags
& KO_MARKED_FOR_DELETE
)
1360 Status
= STATUS_UNSUCCESSFUL
;
1362 goto openkey_cleanup
;
1365 Status
= ObpCreateHandle(PsGetCurrentProcess(),
1371 if (!NT_SUCCESS(Status
))
1376 PostOpenKeyInfo
.Object
= NT_SUCCESS(Status
) ? (PVOID
)Object
: NULL
;
1377 PostOpenKeyInfo
.Status
= Status
;
1378 CmiCallRegisteredCallbacks (RegNtPostOpenKey
, &PostOpenKeyInfo
);
1379 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
1383 ObDereferenceObject(Object
);
1392 Status
= _SEH_GetExceptionCode();
1401 NtQueryKey(IN HANDLE KeyHandle
,
1402 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1403 OUT PVOID KeyInformation
,
1405 OUT PULONG ResultLength
)
1407 PKEY_BASIC_INFORMATION BasicInformation
;
1408 PKEY_NODE_INFORMATION NodeInformation
;
1409 PKEY_FULL_INFORMATION FullInformation
;
1410 PREGISTRY_HIVE RegistryHive
;
1411 PDATA_CELL ClassCell
;
1412 PKEY_OBJECT KeyObject
;
1414 ULONG NameSize
, ClassSize
;
1416 REG_QUERY_KEY_INFORMATION QueryKeyInfo
;
1417 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1421 DPRINT("NtQueryKey(KH 0x%p KIC %x KI 0x%p L %d RL 0x%p)\n",
1423 KeyInformationClass
,
1428 /* Verify that the handle is valid and is a registry key */
1429 Status
= ObReferenceObjectByHandle(KeyHandle
,
1430 (KeyInformationClass
!= KeyNameInformation
? KEY_QUERY_VALUE
: 0),
1432 ExGetPreviousMode(),
1433 (PVOID
*) &KeyObject
,
1435 if (!NT_SUCCESS(Status
))
1440 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1441 QueryKeyInfo
.Object
= (PVOID
)KeyObject
;
1442 QueryKeyInfo
.KeyInformationClass
= KeyInformationClass
;
1443 QueryKeyInfo
.KeyInformation
= KeyInformation
;
1444 QueryKeyInfo
.Length
= Length
;
1445 QueryKeyInfo
.ResultLength
= ResultLength
;
1447 Status
= CmiCallRegisteredCallbacks(RegNtQueryKey
, &QueryKeyInfo
);
1448 if (!NT_SUCCESS(Status
))
1450 ObDereferenceObject(KeyObject
);
1454 /* Acquire hive lock */
1455 KeEnterCriticalRegion();
1456 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1458 VERIFY_KEY_OBJECT(KeyObject
);
1460 /* Get pointer to KeyCell */
1461 KeyCell
= KeyObject
->KeyCell
;
1462 RegistryHive
= KeyObject
->RegistryHive
;
1464 Status
= STATUS_SUCCESS
;
1465 switch (KeyInformationClass
)
1467 case KeyBasicInformation
:
1468 NameSize
= KeyObject
->Name
.Length
;
1470 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1472 /* Check size of buffer */
1473 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
1475 Status
= STATUS_BUFFER_TOO_SMALL
;
1479 /* Fill buffer with requested info */
1480 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
1481 BasicInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1482 BasicInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1483 BasicInformation
->TitleIndex
= 0;
1484 BasicInformation
->NameLength
= KeyObject
->Name
.Length
;
1486 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) <
1489 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1490 Status
= STATUS_BUFFER_OVERFLOW
;
1494 RtlCopyMemory(BasicInformation
->Name
,
1495 KeyObject
->Name
.Buffer
,
1500 case KeyNodeInformation
:
1501 NameSize
= KeyObject
->Name
.Length
;
1502 ClassSize
= KeyCell
->ClassSize
;
1504 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
1505 NameSize
+ ClassSize
;
1507 /* Check size of buffer */
1508 if (Length
< *ResultLength
)
1510 Status
= STATUS_BUFFER_TOO_SMALL
;
1514 /* Fill buffer with requested info */
1515 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
1516 NodeInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1517 NodeInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1518 NodeInformation
->TitleIndex
= 0;
1519 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
1520 KeyObject
->Name
.Length
;
1521 NodeInformation
->ClassLength
= KeyCell
->ClassSize
;
1522 NodeInformation
->NameLength
= KeyObject
->Name
.Length
;
1524 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
1526 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
1528 Status
= STATUS_BUFFER_OVERFLOW
;
1531 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1532 NameSize
< ClassSize
)
1534 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1536 Status
= STATUS_BUFFER_OVERFLOW
;
1540 RtlCopyMemory(NodeInformation
->Name
,
1541 KeyObject
->Name
.Buffer
,
1546 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1547 KeyCell
->ClassNameOffset
,
1549 RtlCopyMemory (NodeInformation
->Name
+ KeyObject
->Name
.Length
,
1556 case KeyFullInformation
:
1557 ClassSize
= KeyCell
->ClassSize
;
1559 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
1562 /* Check size of buffer */
1563 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
))
1565 Status
= STATUS_BUFFER_TOO_SMALL
;
1569 /* Fill buffer with requested info */
1570 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
1571 FullInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1572 FullInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1573 FullInformation
->TitleIndex
= 0;
1574 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) - sizeof(WCHAR
);
1575 FullInformation
->ClassLength
= KeyCell
->ClassSize
;
1576 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //KeyCell->NumberOfSubKeys;
1577 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
1578 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
1579 FullInformation
->Values
= KeyCell
->NumberOfValues
;
1580 FullInformation
->MaxValueNameLen
=
1581 CmiGetMaxValueNameLength(RegistryHive
, KeyCell
);
1582 FullInformation
->MaxValueDataLen
=
1583 CmiGetMaxValueDataLength(RegistryHive
, KeyCell
);
1585 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
1587 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
1588 Status
= STATUS_BUFFER_OVERFLOW
;
1594 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1595 KeyCell
->ClassNameOffset
,
1597 RtlCopyMemory (FullInformation
->Class
,
1598 ClassCell
->Data
, ClassSize
);
1603 case KeyNameInformation
:
1604 case KeyCachedInformation
:
1605 case KeyFlagsInformation
:
1606 DPRINT1("Key information class 0x%x not yet implemented!\n", KeyInformationClass
);
1607 Status
= STATUS_NOT_IMPLEMENTED
;
1611 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
1612 Status
= STATUS_INVALID_INFO_CLASS
;
1616 ExReleaseResourceLite(&CmiRegistryLock
);
1617 KeLeaveCriticalRegion();
1619 PostOperationInfo
.Status
= Status
;
1620 CmiCallRegisteredCallbacks(RegNtPostQueryKey
, &PostOperationInfo
);
1622 ObDereferenceObject(KeyObject
);
1629 NtQueryValueKey(IN HANDLE KeyHandle
,
1630 IN PUNICODE_STRING ValueName
,
1631 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1632 OUT PVOID KeyValueInformation
,
1634 OUT PULONG ResultLength
)
1637 ULONG NameSize
, DataSize
;
1638 PKEY_OBJECT KeyObject
;
1639 PREGISTRY_HIVE RegistryHive
;
1641 PVALUE_CELL ValueCell
;
1642 PDATA_CELL DataCell
;
1643 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
1644 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
1645 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
1646 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo
;
1647 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1651 DPRINT("NtQueryValueKey(KeyHandle 0x%p ValueName %S Length %x)\n",
1652 KeyHandle
, ValueName
->Buffer
, Length
);
1654 /* Verify that the handle is valid and is a registry key */
1655 Status
= ObReferenceObjectByHandle(KeyHandle
,
1658 ExGetPreviousMode(),
1659 (PVOID
*)&KeyObject
,
1662 if (!NT_SUCCESS(Status
))
1664 DPRINT1("ObReferenceObjectByHandle() failed with status %x %p\n", Status
, KeyHandle
);
1668 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1669 QueryValueKeyInfo
.Object
= (PVOID
)KeyObject
;
1670 QueryValueKeyInfo
.ValueName
= ValueName
;
1671 QueryValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
1672 QueryValueKeyInfo
.Length
= Length
;
1673 QueryValueKeyInfo
.ResultLength
= ResultLength
;
1675 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
1676 if (!NT_SUCCESS(Status
))
1678 ObDereferenceObject(KeyObject
);
1682 /* Acquire hive lock */
1683 KeEnterCriticalRegion();
1684 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1686 VERIFY_KEY_OBJECT(KeyObject
);
1688 /* Get pointer to KeyCell */
1689 KeyCell
= KeyObject
->KeyCell
;
1690 RegistryHive
= KeyObject
->RegistryHive
;
1692 /* Get value cell by name */
1693 Status
= CmiScanKeyForValue(RegistryHive
,
1698 if (!NT_SUCCESS(Status
))
1700 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
1704 Status
= STATUS_SUCCESS
;
1705 switch (KeyValueInformationClass
)
1707 case KeyValueBasicInformation
:
1708 NameSize
= ValueCell
->NameSize
;
1709 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1711 NameSize
*= sizeof(WCHAR
);
1714 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) +
1717 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1719 Status
= STATUS_BUFFER_TOO_SMALL
;
1723 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1724 KeyValueInformation
;
1725 ValueBasicInformation
->TitleIndex
= 0;
1726 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1727 ValueBasicInformation
->NameLength
= NameSize
;
1729 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1732 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1733 Status
= STATUS_BUFFER_OVERFLOW
;
1737 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1739 CmiCopyPackedName(ValueBasicInformation
->Name
,
1741 NameSize
/ sizeof(WCHAR
));
1745 RtlCopyMemory(ValueBasicInformation
->Name
,
1752 case KeyValuePartialInformation
:
1753 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1755 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1758 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1760 Status
= STATUS_BUFFER_TOO_SMALL
;
1764 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1765 KeyValueInformation
;
1766 ValuePartialInformation
->TitleIndex
= 0;
1767 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1768 ValuePartialInformation
->DataLength
= DataSize
;
1770 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1773 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1774 Status
= STATUS_BUFFER_OVERFLOW
;
1778 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1780 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1781 RtlCopyMemory(ValuePartialInformation
->Data
,
1787 RtlCopyMemory(ValuePartialInformation
->Data
,
1788 &ValueCell
->DataOffset
,
1794 case KeyValueFullInformation
:
1795 NameSize
= ValueCell
->NameSize
;
1796 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1798 NameSize
*= sizeof(WCHAR
);
1800 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1802 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1803 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1805 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1807 Status
= STATUS_BUFFER_TOO_SMALL
;
1811 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1812 KeyValueInformation
;
1813 ValueFullInformation
->TitleIndex
= 0;
1814 ValueFullInformation
->Type
= ValueCell
->DataType
;
1815 ValueFullInformation
->NameLength
= NameSize
;
1816 ValueFullInformation
->DataOffset
=
1817 (ULONG_PTR
)ValueFullInformation
->Name
-
1818 (ULONG_PTR
)ValueFullInformation
+
1819 ValueFullInformation
->NameLength
;
1820 ValueFullInformation
->DataOffset
=
1821 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1822 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1824 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1827 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1829 Status
= STATUS_BUFFER_OVERFLOW
;
1832 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1833 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1835 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1836 Name
[0]) - NameSize
, sizeof(PVOID
));
1837 Status
= STATUS_BUFFER_OVERFLOW
;
1841 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1843 CmiCopyPackedName(ValueFullInformation
->Name
,
1845 NameSize
/ sizeof(WCHAR
));
1849 RtlCopyMemory(ValueFullInformation
->Name
,
1853 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1855 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1856 RtlCopyMemory((PCHAR
) ValueFullInformation
1857 + ValueFullInformation
->DataOffset
,
1863 RtlCopyMemory((PCHAR
) ValueFullInformation
1864 + ValueFullInformation
->DataOffset
,
1865 &ValueCell
->DataOffset
,
1872 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1873 Status
= STATUS_INVALID_INFO_CLASS
;
1878 ExReleaseResourceLite(&CmiRegistryLock
);
1879 KeLeaveCriticalRegion();
1881 PostOperationInfo
.Status
= Status
;
1882 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
1883 ObDereferenceObject(KeyObject
);
1890 NtSetValueKey(IN HANDLE KeyHandle
,
1891 IN PUNICODE_STRING ValueName
,
1892 IN ULONG TitleIndex
,
1898 PKEY_OBJECT KeyObject
;
1899 PREGISTRY_HIVE RegistryHive
;
1901 PVALUE_CELL ValueCell
;
1902 BLOCK_OFFSET ValueCellOffset
;
1903 PDATA_CELL DataCell
;
1904 PDATA_CELL NewDataCell
;
1905 ULONG DesiredAccess
;
1906 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo
;
1907 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1912 DPRINT("NtSetValueKey(KeyHandle 0x%p ValueName '%wZ' Type %d)\n",
1913 KeyHandle
, ValueName
, Type
);
1915 DesiredAccess
= KEY_SET_VALUE
;
1917 /* Verify that the handle is valid and is a registry key */
1918 Status
= ObReferenceObjectByHandle(KeyHandle
,
1921 ExGetPreviousMode(),
1922 (PVOID
*)&KeyObject
,
1924 if (!NT_SUCCESS(Status
))
1927 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1928 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
1929 SetValueKeyInfo
.ValueName
= ValueName
;
1930 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
1931 SetValueKeyInfo
.Type
= Type
;
1932 SetValueKeyInfo
.Data
= Data
;
1933 SetValueKeyInfo
.DataSize
= DataSize
;
1934 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
1935 if (!NT_SUCCESS(Status
))
1937 ObDereferenceObject(KeyObject
);
1941 /* Acquire hive lock exclucively */
1942 KeEnterCriticalRegion();
1943 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1945 VERIFY_KEY_OBJECT(KeyObject
);
1947 /* Get pointer to key cell */
1948 KeyCell
= KeyObject
->KeyCell
;
1949 RegistryHive
= KeyObject
->RegistryHive
;
1950 Status
= CmiScanKeyForValue(RegistryHive
,
1955 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1957 DPRINT("Allocate new value cell\n");
1958 Status
= CmiAddValueToKey(RegistryHive
,
1960 KeyObject
->KeyCellOffset
,
1966 if (!NT_SUCCESS(Status
))
1968 DPRINT("Cannot add value. Status 0x%X\n", Status
);
1970 ExReleaseResourceLite(&CmiRegistryLock
);
1971 KeLeaveCriticalRegion();
1972 PostOperationInfo
.Status
= Status
;
1973 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
1974 ObDereferenceObject(KeyObject
);
1978 DPRINT("DataSize %lu\n", DataSize
);
1979 DPRINT("ValueCell %p\n", ValueCell
);
1980 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1982 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1983 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1985 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1986 DataCellSize
= (DataCell
->CellSize
< 0 ? -DataCell
->CellSize
: DataCell
->CellSize
) - sizeof(CELL_HEADER
);
1995 if (DataSize
<= sizeof(BLOCK_OFFSET
))
1997 /* If data size <= sizeof(BLOCK_OFFSET) then store data in the data offset */
1998 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
2001 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
2004 RtlCopyMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
2005 ValueCell
->DataSize
= DataSize
| REG_DATA_IN_OFFSET
;
2006 ValueCell
->DataType
= Type
;
2007 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
2011 if (DataSize
> DataCellSize
)
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 Status
= CmiAllocateCell (RegistryHive
,
2022 sizeof(CELL_HEADER
) + DataSize
,
2023 (PVOID
*)&NewDataCell
,
2025 if (!NT_SUCCESS(Status
))
2027 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status
);
2029 ExReleaseResourceLite(&CmiRegistryLock
);
2030 KeLeaveCriticalRegion();
2031 PostOperationInfo
.Status
= Status
;
2032 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
2033 ObDereferenceObject(KeyObject
);
2040 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
2043 ValueCell
->DataOffset
= NewOffset
;
2044 DataCell
= NewDataCell
;
2047 RtlCopyMemory(DataCell
->Data
, Data
, DataSize
);
2048 ValueCell
->DataSize
= DataSize
& REG_DATA_SIZE_MASK
;
2049 ValueCell
->DataType
= Type
;
2050 CmiMarkBlockDirty(RegistryHive
, ValueCell
->DataOffset
);
2051 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
2055 if ((Type
== REG_LINK
) &&
2056 (_wcsicmp(ValueName
->Buffer
, L
"SymbolicLinkValue") == 0))
2058 KeyCell
->Flags
|= REG_KEY_LINK_CELL
;
2061 KeQuerySystemTime (&KeyCell
->LastWriteTime
);
2062 CmiMarkBlockDirty (RegistryHive
, KeyObject
->KeyCellOffset
);
2064 ExReleaseResourceLite(&CmiRegistryLock
);
2065 KeLeaveCriticalRegion();
2066 PostOperationInfo
.Status
= Status
;
2067 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
2068 ObDereferenceObject(KeyObject
);
2072 DPRINT("Return Status 0x%X\n", Status
);
2079 NtDeleteValueKey (IN HANDLE KeyHandle
,
2080 IN PUNICODE_STRING ValueName
)
2082 PKEY_OBJECT KeyObject
;
2084 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
2085 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2086 KPROCESSOR_MODE PreviousMode
;
2087 UNICODE_STRING CapturedValueName
;
2091 PreviousMode
= ExGetPreviousMode();
2093 /* Verify that the handle is valid and is a registry key */
2094 Status
= ObReferenceObjectByHandle(KeyHandle
,
2098 (PVOID
*)&KeyObject
,
2100 if (!NT_SUCCESS(Status
))
2105 Status
= ProbeAndCaptureUnicodeString(&CapturedValueName
,
2108 if (!NT_SUCCESS(Status
))
2112 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
2113 DeleteValueKeyInfo
.ValueName
= &CapturedValueName
;
2115 /* FIXME - check if value exists before calling the callbacks? */
2116 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
, &DeleteValueKeyInfo
);
2117 if (!NT_SUCCESS(Status
))
2119 ReleaseCapturedUnicodeString(&CapturedValueName
,
2122 ObDereferenceObject(KeyObject
);
2126 /* Acquire hive lock */
2127 KeEnterCriticalRegion();
2128 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2130 VERIFY_KEY_OBJECT(KeyObject
);
2132 Status
= CmiDeleteValueFromKey(KeyObject
->RegistryHive
,
2134 KeyObject
->KeyCellOffset
,
2137 KeQuerySystemTime (&KeyObject
->KeyCell
->LastWriteTime
);
2138 CmiMarkBlockDirty (KeyObject
->RegistryHive
, KeyObject
->KeyCellOffset
);
2140 /* Release hive lock */
2141 ExReleaseResourceLite(&CmiRegistryLock
);
2142 KeLeaveCriticalRegion();
2144 ReleaseCapturedUnicodeString(&CapturedValueName
,
2147 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2148 PostOperationInfo
.Status
= Status
;
2150 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
, &PostOperationInfo
);
2152 ObDereferenceObject (KeyObject
);
2162 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2163 * KeyObjectAttributes->Name specifies the name of the key to load.
2166 NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
2167 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
2169 return NtLoadKey2 (KeyObjectAttributes
,
2170 FileObjectAttributes
,
2177 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2178 * KeyObjectAttributes->Name specifies the name of the key to load.
2179 * Flags can be 0 or REG_NO_LAZY_FLUSH.
2182 NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
2183 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
2186 POBJECT_NAME_INFORMATION NameInfo
;
2187 PUNICODE_STRING NamePointer
;
2195 DPRINT ("NtLoadKey2() called\n");
2198 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, ExGetPreviousMode ()))
2199 return STATUS_PRIVILEGE_NOT_HELD
;
2202 if (FileObjectAttributes
->RootDirectory
!= NULL
)
2205 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2206 Buffer
= ExAllocatePool (NonPagedPool
,
2209 return STATUS_INSUFFICIENT_RESOURCES
;
2211 Status
= ZwQueryObject (FileObjectAttributes
->RootDirectory
,
2212 ObjectNameInformation
,
2216 if (!NT_SUCCESS(Status
))
2218 DPRINT1 ("NtQueryObject() failed (Status %lx)\n", Status
);
2219 ExFreePool (Buffer
);
2223 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2224 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2225 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2227 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2228 if (FileObjectAttributes
->ObjectName
->Buffer
[0] != L
'\\')
2230 RtlAppendUnicodeToString (&NameInfo
->Name
,
2232 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2233 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2235 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2236 FileObjectAttributes
->ObjectName
);
2238 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2239 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2240 NamePointer
= &NameInfo
->Name
;
2244 if (FileObjectAttributes
->ObjectName
->Buffer
[0] == L
'\\')
2247 NamePointer
= FileObjectAttributes
->ObjectName
;
2252 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2253 Buffer
= ExAllocatePool (NonPagedPool
,
2256 return STATUS_INSUFFICIENT_RESOURCES
;
2258 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2259 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2260 NameInfo
->Name
.Length
= 0;
2261 NameInfo
->Name
.Buffer
= (PWSTR
)((ULONG_PTR
)Buffer
+ sizeof(OBJECT_NAME_INFORMATION
));
2262 NameInfo
->Name
.Buffer
[0] = 0;
2264 RtlAppendUnicodeToString (&NameInfo
->Name
,
2266 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2267 FileObjectAttributes
->ObjectName
);
2269 NamePointer
= &NameInfo
->Name
;
2273 DPRINT ("Full name: '%wZ'\n", NamePointer
);
2275 /* Acquire hive lock */
2276 KeEnterCriticalRegion();
2277 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2279 Status
= CmiLoadHive (KeyObjectAttributes
,
2282 if (!NT_SUCCESS (Status
))
2284 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
2287 /* Release hive lock */
2288 ExReleaseResourceLite(&CmiRegistryLock
);
2289 KeLeaveCriticalRegion();
2292 ExFreePool (Buffer
);
2299 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2301 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2302 IN PVOID ApcContext OPTIONAL
,
2303 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2304 IN ULONG CompletionFilter
,
2305 IN BOOLEAN WatchSubtree
,
2308 IN BOOLEAN Asynchronous
)
2311 return(STATUS_NOT_IMPLEMENTED
);
2316 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2318 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2319 IN PVOID ApcContext OPTIONAL
,
2320 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2321 IN ULONG CompletionFilter
,
2322 IN BOOLEAN WatchSubtree
,
2325 IN BOOLEAN Asynchronous
)
2327 return NtNotifyChangeMultipleKeys(KeyHandle
,
2344 NtQueryMultipleValueKey (IN HANDLE KeyHandle
,
2345 IN OUT PKEY_VALUE_ENTRY ValueList
,
2346 IN ULONG NumberOfValues
,
2348 IN OUT PULONG Length
,
2349 OUT PULONG ReturnLength
)
2351 PREGISTRY_HIVE RegistryHive
;
2352 PVALUE_CELL ValueCell
;
2353 PKEY_OBJECT KeyObject
;
2354 PDATA_CELL DataCell
;
2355 ULONG BufferLength
= 0;
2360 REG_QUERY_MULTIPLE_VALUE_KEY_INFORMATION QueryMultipleValueKeyInfo
;
2361 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2365 /* Verify that the handle is valid and is a registry key */
2366 Status
= ObReferenceObjectByHandle(KeyHandle
,
2369 ExGetPreviousMode(),
2370 (PVOID
*) &KeyObject
,
2372 if (!NT_SUCCESS(Status
))
2374 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2378 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2379 QueryMultipleValueKeyInfo
.Object
= (PVOID
)KeyObject
;
2380 QueryMultipleValueKeyInfo
.ValueEntries
= ValueList
;
2381 QueryMultipleValueKeyInfo
.EntryCount
= NumberOfValues
;
2382 QueryMultipleValueKeyInfo
.ValueBuffer
= Buffer
;
2383 QueryMultipleValueKeyInfo
.BufferLength
= Length
;
2384 QueryMultipleValueKeyInfo
.RequiredBufferLength
= ReturnLength
;
2386 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryMultipleValueKey
, &QueryMultipleValueKeyInfo
);
2387 if (!NT_SUCCESS(Status
))
2389 ObDereferenceObject(KeyObject
);
2393 /* Acquire hive lock */
2394 KeEnterCriticalRegion();
2395 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
2397 VERIFY_KEY_OBJECT(KeyObject
);
2399 /* Get pointer to KeyCell */
2400 KeyCell
= KeyObject
->KeyCell
;
2401 RegistryHive
= KeyObject
->RegistryHive
;
2403 DataPtr
= (PUCHAR
) Buffer
;
2405 for (i
= 0; i
< NumberOfValues
; i
++)
2407 DPRINT("ValueName: '%wZ'\n", ValueList
[i
].ValueName
);
2409 /* Get Value block of interest */
2410 Status
= CmiScanKeyForValue(RegistryHive
,
2412 ValueList
[i
].ValueName
,
2416 if (!NT_SUCCESS(Status
))
2418 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
2421 else if (ValueCell
== NULL
)
2423 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
2427 BufferLength
= ROUND_UP(BufferLength
, sizeof(PVOID
));
2429 if (BufferLength
+ (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) <= *Length
)
2431 DataPtr
= (PUCHAR
)ROUND_UP((ULONG_PTR
)DataPtr
, sizeof(PVOID
));
2433 ValueList
[i
].Type
= ValueCell
->DataType
;
2434 ValueList
[i
].DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2435 ValueList
[i
].DataOffset
= (ULONG_PTR
)DataPtr
- (ULONG_PTR
)Buffer
;
2437 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
2439 DataCell
= CmiGetCell (RegistryHive
,
2440 ValueCell
->DataOffset
,
2442 RtlCopyMemory(DataPtr
,
2444 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2448 RtlCopyMemory(DataPtr
,
2449 &ValueCell
->DataOffset
,
2450 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2453 DataPtr
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2457 Status
= STATUS_BUFFER_TOO_SMALL
;
2460 BufferLength
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2463 if (NT_SUCCESS(Status
))
2464 *Length
= BufferLength
;
2466 *ReturnLength
= BufferLength
;
2468 /* Release hive lock */
2469 ExReleaseResourceLite(&CmiRegistryLock
);
2470 KeLeaveCriticalRegion();
2472 PostOperationInfo
.Status
= Status
;
2473 CmiCallRegisteredCallbacks(RegNtPostQueryMultipleValueKey
, &PostOperationInfo
);
2475 ObDereferenceObject(KeyObject
);
2477 DPRINT("Return Status 0x%X\n", Status
);
2484 NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes
,
2486 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
2489 return(STATUS_NOT_IMPLEMENTED
);
2494 NtRestoreKey (IN HANDLE KeyHandle
,
2495 IN HANDLE FileHandle
,
2496 IN ULONG RestoreFlags
)
2499 return(STATUS_NOT_IMPLEMENTED
);
2504 NtSaveKey (IN HANDLE KeyHandle
,
2505 IN HANDLE FileHandle
)
2507 PREGISTRY_HIVE TempHive
;
2508 PKEY_OBJECT KeyObject
;
2513 DPRINT ("NtSaveKey() called\n");
2516 if (!SeSinglePrivilegeCheck (SeBackupPrivilege
, ExGetPreviousMode ()))
2517 return STATUS_PRIVILEGE_NOT_HELD
;
2520 Status
= ObReferenceObjectByHandle (KeyHandle
,
2523 ExGetPreviousMode(),
2524 (PVOID
*)&KeyObject
,
2526 if (!NT_SUCCESS(Status
))
2528 DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
2532 /* Acquire hive lock exclucively */
2533 KeEnterCriticalRegion();
2534 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2536 /* Refuse to save a volatile key */
2537 if (KeyObject
->RegistryHive
== CmiVolatileHive
)
2539 DPRINT1 ("Cannot save a volatile key\n");
2540 ExReleaseResourceLite(&CmiRegistryLock
);
2541 KeLeaveCriticalRegion();
2542 ObDereferenceObject (KeyObject
);
2543 return STATUS_ACCESS_DENIED
;
2546 Status
= CmiCreateTempHive(&TempHive
);
2547 if (!NT_SUCCESS(Status
))
2549 DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status
);
2550 ExReleaseResourceLite(&CmiRegistryLock
);
2551 KeLeaveCriticalRegion();
2552 ObDereferenceObject (KeyObject
);
2556 Status
= CmiCopyKey (TempHive
,
2558 KeyObject
->RegistryHive
,
2559 KeyObject
->KeyCell
);
2560 if (!NT_SUCCESS(Status
))
2562 DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status
);
2563 CmiRemoveRegistryHive (TempHive
);
2564 ExReleaseResourceLite(&CmiRegistryLock
);
2565 KeLeaveCriticalRegion();
2566 ObDereferenceObject (KeyObject
);
2570 Status
= CmiSaveTempHive (TempHive
,
2572 if (!NT_SUCCESS(Status
))
2574 DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status
);
2577 CmiRemoveRegistryHive (TempHive
);
2579 /* Release hive lock */
2580 ExReleaseResourceLite(&CmiRegistryLock
);
2581 KeLeaveCriticalRegion();
2583 ObDereferenceObject (KeyObject
);
2585 DPRINT ("NtSaveKey() done\n");
2587 return STATUS_SUCCESS
;
2596 IN HANDLE KeyHandle
,
2597 IN HANDLE FileHandle
,
2598 IN ULONG Flags
// REG_STANDARD_FORMAT, etc..
2602 return STATUS_NOT_IMPLEMENTED
;
2607 NtSetInformationKey (IN HANDLE KeyHandle
,
2608 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
2609 IN PVOID KeyInformation
,
2610 IN ULONG KeyInformationLength
)
2612 PKEY_OBJECT KeyObject
;
2614 REG_SET_INFORMATION_KEY_INFORMATION SetInformationKeyInfo
;
2615 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2619 /* Verify that the handle is valid and is a registry key */
2620 Status
= ObReferenceObjectByHandle (KeyHandle
,
2623 ExGetPreviousMode(),
2624 (PVOID
*)&KeyObject
,
2626 if (!NT_SUCCESS (Status
))
2628 DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2632 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2633 SetInformationKeyInfo
.Object
= (PVOID
)KeyObject
;
2634 SetInformationKeyInfo
.KeySetInformationClass
= KeyInformationClass
;
2635 SetInformationKeyInfo
.KeySetInformation
= KeyInformation
;
2636 SetInformationKeyInfo
.KeySetInformationLength
= KeyInformationLength
;
2638 Status
= CmiCallRegisteredCallbacks(RegNtSetInformationKey
, &SetInformationKeyInfo
);
2639 if (!NT_SUCCESS(Status
))
2641 ObDereferenceObject (KeyObject
);
2645 if (KeyInformationClass
!= KeyWriteTimeInformation
)
2647 Status
= STATUS_INVALID_INFO_CLASS
;
2650 else if (KeyInformationLength
!= sizeof (KEY_WRITE_TIME_INFORMATION
))
2652 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2656 /* Acquire hive lock */
2657 KeEnterCriticalRegion();
2658 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2660 VERIFY_KEY_OBJECT(KeyObject
);
2662 KeyObject
->KeyCell
->LastWriteTime
.QuadPart
=
2663 ((PKEY_WRITE_TIME_INFORMATION
)KeyInformation
)->LastWriteTime
.QuadPart
;
2665 CmiMarkBlockDirty (KeyObject
->RegistryHive
,
2666 KeyObject
->KeyCellOffset
);
2668 /* Release hive lock */
2669 ExReleaseResourceLite(&CmiRegistryLock
);
2670 KeLeaveCriticalRegion();
2673 PostOperationInfo
.Status
= Status
;
2674 CmiCallRegisteredCallbacks(RegNtPostSetInformationKey
, &PostOperationInfo
);
2676 ObDereferenceObject (KeyObject
);
2678 if (NT_SUCCESS(Status
))
2683 DPRINT ("NtSaveKey() done\n");
2685 return STATUS_SUCCESS
;
2691 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2692 * KeyObjectAttributes->Name specifies the name of the key to unload.
2695 NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
2697 PREGISTRY_HIVE RegistryHive
;
2702 DPRINT ("NtUnloadKey() called\n");
2705 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, ExGetPreviousMode ()))
2706 return STATUS_PRIVILEGE_NOT_HELD
;
2709 /* Acquire registry lock exclusively */
2710 KeEnterCriticalRegion();
2711 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2713 Status
= CmiDisconnectHive (KeyObjectAttributes
,
2715 if (!NT_SUCCESS (Status
))
2717 DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status
);
2718 ExReleaseResourceLite (&CmiRegistryLock
);
2719 KeLeaveCriticalRegion();
2723 DPRINT ("RegistryHive %p\n", RegistryHive
);
2727 if (!IsNoFileHive (RegistryHive
))
2728 CmiFlushRegistryHive (RegistryHive
);
2731 CmiRemoveRegistryHive (RegistryHive
);
2733 /* Release registry lock */
2734 ExReleaseResourceLite (&CmiRegistryLock
);
2735 KeLeaveCriticalRegion();
2737 DPRINT ("NtUnloadKey() done\n");
2739 return STATUS_SUCCESS
;
2744 NtInitializeRegistry (IN BOOLEAN SetUpBoot
)
2750 if (CmiRegistryInitialized
== TRUE
)
2751 return STATUS_ACCESS_DENIED
;
2753 /* Save boot log file */
2754 IopSaveBootLogToFile();
2756 Status
= CmiInitHives (SetUpBoot
);
2758 CmiRegistryInitialized
= TRUE
;