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 DPRINT1("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 DPRINT1("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 DPRINT1("Object marked for delete!\n");
290 Status
= STATUS_UNSUCCESSFUL
;
294 Status
= ObpCreateHandle(PsGetCurrentProcess(),
300 if (!NT_SUCCESS(Status
))
301 DPRINT1("ObpCreateHandle failed Status 0x%x\n", Status
);
303 PostCreateKeyInfo
.Object
= NULL
;
304 PostCreateKeyInfo
.Status
= Status
;
305 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
307 LocalDisposition
= REG_OPENED_EXISTING_KEY
;
311 /* If RemainingPath contains \ we must return error
312 because NtCreateKey doesn't create trees */
313 Start
= RemainingPath
.Buffer
;
317 for (i
= 1; i
< RemainingPath
.Length
/ sizeof(WCHAR
); i
++)
319 if (L
'\\' == RemainingPath
.Buffer
[i
])
321 DPRINT("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath
);
323 PostCreateKeyInfo
.Object
= NULL
;
324 PostCreateKeyInfo
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
325 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
327 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
332 DPRINT("RemainingPath %S ParentObject 0x%p\n", RemainingPath
.Buffer
, Object
);
334 Status
= ObCreateObject(PreviousMode
,
343 if (!NT_SUCCESS(Status
))
345 DPRINT1("ObCreateObject() failed!\n");
346 PostCreateKeyInfo
.Object
= NULL
;
347 PostCreateKeyInfo
.Status
= Status
;
348 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
353 Status
= ObInsertObject((PVOID
)KeyObject
,
359 if (!NT_SUCCESS(Status
))
361 ObDereferenceObject(KeyObject
);
362 DPRINT1("ObInsertObject() failed!\n");
364 PostCreateKeyInfo
.Object
= NULL
;
365 PostCreateKeyInfo
.Status
= Status
;
366 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
371 KeyObject
->ParentKey
= Object
;
373 if (CreateOptions
& REG_OPTION_VOLATILE
)
374 KeyObject
->RegistryHive
= CmiVolatileHive
;
376 KeyObject
->RegistryHive
= KeyObject
->ParentKey
->RegistryHive
;
378 KeyObject
->Flags
= 0;
379 KeyObject
->NumberOfSubKeys
= 0;
380 KeyObject
->SizeOfSubKeys
= 0;
381 KeyObject
->SubKeys
= NULL
;
383 /* Acquire hive lock */
384 KeEnterCriticalRegion();
385 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
387 InsertTailList(&CmiKeyObjectListHead
, &KeyObject
->ListEntry
);
389 /* add key to subkeys of parent if needed */
390 Status
= CmiAddSubKey(KeyObject
->RegistryHive
,
391 KeyObject
->ParentKey
,
397 if (!NT_SUCCESS(Status
))
399 DPRINT1("CmiAddSubKey() failed (Status %lx)\n", Status
);
400 /* Release hive lock */
401 ExReleaseResourceLite(&CmiRegistryLock
);
402 KeLeaveCriticalRegion();
403 ObDereferenceObject(KeyObject
);
405 PostCreateKeyInfo
.Object
= NULL
;
406 PostCreateKeyInfo
.Status
= STATUS_UNSUCCESSFUL
;
407 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
409 Status
= STATUS_UNSUCCESSFUL
;
413 if (Start
== RemainingPath
.Buffer
)
415 KeyObject
->Name
= RemainingPath
;
416 FreeRemainingPath
= FALSE
;
420 RtlpCreateUnicodeString(&KeyObject
->Name
, Start
, NonPagedPool
);
423 if (KeyObject
->RegistryHive
== KeyObject
->ParentKey
->RegistryHive
)
425 KeyObject
->KeyCell
->ParentKeyOffset
= KeyObject
->ParentKey
->KeyCellOffset
;
426 KeyObject
->KeyCell
->SecurityKeyOffset
= KeyObject
->ParentKey
->KeyCell
->SecurityKeyOffset
;
430 KeyObject
->KeyCell
->ParentKeyOffset
= -1;
431 KeyObject
->KeyCell
->SecurityKeyOffset
= -1;
432 /* This key must remain in memory unless it is deleted
433 or file is unloaded */
434 ObReferenceObject(KeyObject
);
437 CmiAddKeyToList(KeyObject
->ParentKey
, KeyObject
);
439 VERIFY_KEY_OBJECT(KeyObject
);
441 /* Release hive lock */
442 ExReleaseResourceLite(&CmiRegistryLock
);
443 KeLeaveCriticalRegion();
445 PostCreateKeyInfo
.Object
= KeyObject
;
446 PostCreateKeyInfo
.Status
= Status
;
447 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
451 LocalDisposition
= REG_CREATED_NEW_KEY
;
457 if (Disposition
!= NULL
)
459 *Disposition
= LocalDisposition
;
464 Status
= _SEH_GetExceptionCode();
471 ReleaseCapturedUnicodeString(&CapturedClass
,
474 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
475 if (FreeRemainingPath
) RtlFreeUnicodeString(&RemainingPath
);
476 if (Object
!= NULL
) ObDereferenceObject(Object
);
483 NtDeleteKey(IN HANDLE KeyHandle
)
485 KPROCESSOR_MODE PreviousMode
;
486 PKEY_OBJECT KeyObject
;
488 REG_DELETE_KEY_INFORMATION DeleteKeyInfo
;
489 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
493 DPRINT("NtDeleteKey(KeyHandle 0x%p) called\n", KeyHandle
);
495 PreviousMode
= ExGetPreviousMode();
497 /* Verify that the handle is valid and is a registry key */
498 Status
= ObReferenceObjectByHandle(KeyHandle
,
504 if (!NT_SUCCESS(Status
))
506 DPRINT1("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
510 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
511 DeleteKeyInfo
.Object
= (PVOID
)KeyObject
;
512 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &DeleteKeyInfo
);
513 if (!NT_SUCCESS(Status
))
515 PostOperationInfo
.Status
= Status
;
516 CmiCallRegisteredCallbacks(RegNtDeleteKey
, &PostOperationInfo
);
517 ObDereferenceObject(KeyObject
);
521 /* Acquire hive lock */
522 KeEnterCriticalRegion();
523 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
525 VERIFY_KEY_OBJECT(KeyObject
);
527 /* Check for subkeys */
528 if (KeyObject
->NumberOfSubKeys
!= 0)
530 Status
= STATUS_CANNOT_DELETE
;
534 /* Set the marked for delete bit in the key object */
535 KeyObject
->Flags
|= KO_MARKED_FOR_DELETE
;
536 Status
= STATUS_SUCCESS
;
539 /* Release hive lock */
540 ExReleaseResourceLite(&CmiRegistryLock
);
541 KeLeaveCriticalRegion();
543 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
545 /* Remove the keep-alive reference */
546 ObDereferenceObject(KeyObject
);
548 if (KeyObject
->RegistryHive
!= KeyObject
->ParentKey
->RegistryHive
)
549 ObDereferenceObject(KeyObject
);
551 PostOperationInfo
.Status
= Status
;
552 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
554 /* Dereference the object */
555 ObDereferenceObject(KeyObject
);
557 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
558 DPRINT("HandleCount %lu\n", ObGetObjectHandleCount((PVOID
)KeyObject
));
562 * Hive-Synchronization will not be triggered here. This is done in
563 * CmiObjectDelete() (in regobj.c) after all key-related structures
564 * have been released.
572 NtEnumerateKey(IN HANDLE KeyHandle
,
574 IN KEY_INFORMATION_CLASS KeyInformationClass
,
575 OUT PVOID KeyInformation
,
577 OUT PULONG ResultLength
)
579 PKEY_OBJECT KeyObject
;
580 PKEY_OBJECT SubKeyObject
;
581 PREGISTRY_HIVE RegistryHive
;
582 PKEY_CELL KeyCell
, SubKeyCell
;
583 PHASH_TABLE_CELL HashTableBlock
;
584 PKEY_BASIC_INFORMATION BasicInformation
;
585 PKEY_NODE_INFORMATION NodeInformation
;
586 PKEY_FULL_INFORMATION FullInformation
;
587 PDATA_CELL ClassCell
;
588 ULONG NameSize
, ClassSize
;
589 KPROCESSOR_MODE PreviousMode
;
591 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo
;
592 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
596 PreviousMode
= ExGetPreviousMode();
598 DPRINT("KH 0x%p I %d KIC %x KI 0x%p L %d RL 0x%p\n",
606 /* Verify that the handle is valid and is a registry key */
607 Status
= ObReferenceObjectByHandle(KeyHandle
,
608 KEY_ENUMERATE_SUB_KEYS
,
611 (PVOID
*) &KeyObject
,
613 if (!NT_SUCCESS(Status
))
615 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
619 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
620 EnumerateKeyInfo
.Object
= (PVOID
)KeyObject
;
621 EnumerateKeyInfo
.Index
= Index
;
622 EnumerateKeyInfo
.KeyInformationClass
= KeyInformationClass
;
623 EnumerateKeyInfo
.Length
= Length
;
624 EnumerateKeyInfo
.ResultLength
= ResultLength
;
626 Status
= CmiCallRegisteredCallbacks(RegNtEnumerateKey
, &EnumerateKeyInfo
);
627 if (!NT_SUCCESS(Status
))
629 ObDereferenceObject(KeyObject
);
633 /* Acquire hive lock */
634 KeEnterCriticalRegion();
635 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
637 VERIFY_KEY_OBJECT(KeyObject
);
639 /* Get pointer to KeyCell */
640 KeyCell
= KeyObject
->KeyCell
;
641 RegistryHive
= KeyObject
->RegistryHive
;
645 /* Check for hightest possible sub key index */
646 if (Index
>= KeyCell
->NumberOfSubKeys
+ KeyObject
->NumberOfSubKeys
)
648 ExReleaseResourceLite(&CmiRegistryLock
);
649 KeLeaveCriticalRegion();
650 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
651 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
652 ObDereferenceObject(KeyObject
);
653 DPRINT("No more volatile entries\n");
654 return STATUS_NO_MORE_ENTRIES
;
657 /* Get pointer to SubKey */
658 if (Index
>= KeyCell
->NumberOfSubKeys
)
660 PKEY_OBJECT CurKey
= NULL
;
664 /* Search for volatile or 'foreign' keys */
665 j
= KeyCell
->NumberOfSubKeys
;
666 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
668 CurKey
= KeyObject
->SubKeys
[i
];
669 if (CurKey
->RegistryHive
!= RegistryHive
)
677 if (i
>= KeyObject
->NumberOfSubKeys
)
679 ExReleaseResourceLite(&CmiRegistryLock
);
680 KeLeaveCriticalRegion();
681 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
682 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
683 ObDereferenceObject(KeyObject
);
684 DPRINT("No more non-volatile entries\n");
685 return STATUS_NO_MORE_ENTRIES
;
688 SubKeyObject
= CurKey
;
689 SubKeyCell
= CurKey
->KeyCell
;
693 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
695 ExReleaseResourceLite(&CmiRegistryLock
);
696 KeLeaveCriticalRegion();
697 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
698 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
699 ObDereferenceObject(KeyObject
);
700 return STATUS_NO_MORE_ENTRIES
;
703 HashTableBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
704 if (HashTableBlock
== NULL
)
706 DPRINT("CmiGetBlock() failed\n");
707 ExReleaseResourceLite(&CmiRegistryLock
);
708 KeLeaveCriticalRegion();
709 PostOperationInfo
.Status
= STATUS_UNSUCCESSFUL
;
710 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
711 ObDereferenceObject(KeyObject
);
712 return STATUS_UNSUCCESSFUL
;
715 SubKeyCell
= CmiGetKeyFromHashByIndex(RegistryHive
,
720 if (SubKeyCell
== NULL
)
722 ExReleaseResourceLite(&CmiRegistryLock
);
723 KeLeaveCriticalRegion();
724 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
725 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
726 ObDereferenceObject(KeyObject
);
727 DPRINT("No more entries\n");
728 return STATUS_NO_MORE_ENTRIES
;
731 Status
= STATUS_SUCCESS
;
732 switch (KeyInformationClass
)
734 case KeyBasicInformation
:
735 /* Check size of buffer */
736 if (SubKeyObject
!= NULL
)
738 NameSize
= SubKeyObject
->Name
.Length
;
742 NameSize
= SubKeyCell
->NameSize
;
743 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
745 NameSize
*= sizeof(WCHAR
);
749 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) + NameSize
;
752 * NOTE: It's perfetly valid to call NtEnumerateKey to get
753 * all the information but name. Actually the NT4 sound
754 * framework does that while querying parameters from registry.
755 * -- Filip Navara, 19/07/2004
757 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
759 Status
= STATUS_BUFFER_TOO_SMALL
;
763 /* Fill buffer with requested info */
764 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
765 BasicInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
766 BasicInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
767 BasicInformation
->TitleIndex
= Index
;
768 BasicInformation
->NameLength
= NameSize
;
770 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) < NameSize
)
772 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
773 Status
= STATUS_BUFFER_OVERFLOW
;
777 if (SubKeyObject
!= NULL
)
779 RtlCopyMemory(BasicInformation
->Name
,
780 SubKeyObject
->Name
.Buffer
,
785 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
787 CmiCopyPackedName(BasicInformation
->Name
,
789 NameSize
/ sizeof(WCHAR
));
793 RtlCopyMemory(BasicInformation
->Name
,
801 case KeyNodeInformation
:
802 /* Check size of buffer */
803 if (SubKeyObject
!= NULL
)
805 NameSize
= SubKeyObject
->Name
.Length
;
809 NameSize
= SubKeyCell
->NameSize
;
810 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
812 NameSize
*= sizeof(WCHAR
);
815 ClassSize
= SubKeyCell
->ClassSize
;
817 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
818 NameSize
+ ClassSize
;
820 if (Length
< FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]))
822 Status
= STATUS_BUFFER_TOO_SMALL
;
826 /* Fill buffer with requested info */
827 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
828 NodeInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
829 NodeInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
830 NodeInformation
->TitleIndex
= Index
;
831 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) + NameSize
;
832 NodeInformation
->ClassLength
= SubKeyCell
->ClassSize
;
833 NodeInformation
->NameLength
= NameSize
;
835 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
837 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
839 Status
= STATUS_BUFFER_OVERFLOW
;
842 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
843 NameSize
< ClassSize
)
845 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
847 Status
= STATUS_BUFFER_OVERFLOW
;
851 if (SubKeyObject
!= NULL
)
853 RtlCopyMemory(NodeInformation
->Name
,
854 SubKeyObject
->Name
.Buffer
,
859 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
861 CmiCopyPackedName(NodeInformation
->Name
,
863 NameSize
/ sizeof(WCHAR
));
867 RtlCopyMemory(NodeInformation
->Name
,
875 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
876 SubKeyCell
->ClassNameOffset
,
878 RtlCopyMemory (NodeInformation
->Name
+ SubKeyCell
->NameSize
,
885 case KeyFullInformation
:
886 ClassSize
= SubKeyCell
->ClassSize
;
888 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) +
891 /* Check size of buffer */
892 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]))
894 Status
= STATUS_BUFFER_TOO_SMALL
;
898 /* Fill buffer with requested info */
899 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
900 FullInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
901 FullInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
902 FullInformation
->TitleIndex
= Index
;
903 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) -
905 FullInformation
->ClassLength
= SubKeyCell
->ClassSize
;
906 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //SubKeyCell->NumberOfSubKeys;
907 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
908 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
909 FullInformation
->Values
= SubKeyCell
->NumberOfValues
;
910 FullInformation
->MaxValueNameLen
=
911 CmiGetMaxValueNameLength(RegistryHive
, SubKeyCell
);
912 FullInformation
->MaxValueDataLen
=
913 CmiGetMaxValueDataLength(RegistryHive
, SubKeyCell
);
915 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
917 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
918 Status
= STATUS_BUFFER_OVERFLOW
;
924 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
925 SubKeyCell
->ClassNameOffset
,
927 RtlCopyMemory (FullInformation
->Class
,
935 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
939 ExReleaseResourceLite(&CmiRegistryLock
);
940 KeLeaveCriticalRegion();
942 PostOperationInfo
.Status
= Status
;
943 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
945 ObDereferenceObject(KeyObject
);
947 DPRINT("Returning status %x\n", Status
);
954 NtEnumerateValueKey(IN HANDLE KeyHandle
,
956 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
957 OUT PVOID KeyValueInformation
,
959 OUT PULONG ResultLength
)
962 PKEY_OBJECT KeyObject
;
963 PREGISTRY_HIVE RegistryHive
;
965 PVALUE_CELL ValueCell
;
967 ULONG NameSize
, DataSize
;
968 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
969 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
970 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
974 DPRINT("KH 0x%p I %d KVIC %x KVI 0x%p L %d RL 0x%p\n",
977 KeyValueInformationClass
,
982 /* Verify that the handle is valid and is a registry key */
983 Status
= ObReferenceObjectByHandle(KeyHandle
,
987 (PVOID
*) &KeyObject
,
990 if (!NT_SUCCESS(Status
))
995 /* Acquire hive lock */
996 KeEnterCriticalRegion();
997 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
999 VERIFY_KEY_OBJECT(KeyObject
);
1001 /* Get pointer to KeyCell */
1002 KeyCell
= KeyObject
->KeyCell
;
1003 RegistryHive
= KeyObject
->RegistryHive
;
1005 /* Get Value block of interest */
1006 Status
= CmiGetValueFromKeyByIndex(RegistryHive
,
1011 if (!NT_SUCCESS(Status
))
1013 ExReleaseResourceLite(&CmiRegistryLock
);
1014 KeLeaveCriticalRegion();
1015 ObDereferenceObject(KeyObject
);
1019 if (ValueCell
!= NULL
)
1021 switch (KeyValueInformationClass
)
1023 case KeyValueBasicInformation
:
1024 NameSize
= ValueCell
->NameSize
;
1025 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1027 NameSize
*= sizeof(WCHAR
);
1030 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) + NameSize
;
1032 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1034 Status
= STATUS_BUFFER_TOO_SMALL
;
1038 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1039 KeyValueInformation
;
1040 ValueBasicInformation
->TitleIndex
= 0;
1041 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1042 ValueBasicInformation
->NameLength
= NameSize
;
1044 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1047 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1048 Status
= STATUS_BUFFER_OVERFLOW
;
1052 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1054 CmiCopyPackedName(ValueBasicInformation
->Name
,
1056 NameSize
/ sizeof(WCHAR
));
1060 RtlCopyMemory(ValueBasicInformation
->Name
,
1067 case KeyValuePartialInformation
:
1068 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1070 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1073 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1075 Status
= STATUS_BUFFER_TOO_SMALL
;
1079 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1080 KeyValueInformation
;
1081 ValuePartialInformation
->TitleIndex
= 0;
1082 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1083 ValuePartialInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1085 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1088 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1089 Status
= STATUS_BUFFER_OVERFLOW
;
1093 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1095 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1096 RtlCopyMemory(ValuePartialInformation
->Data
,
1102 RtlCopyMemory(ValuePartialInformation
->Data
,
1103 &ValueCell
->DataOffset
,
1109 case KeyValueFullInformation
:
1110 NameSize
= ValueCell
->NameSize
;
1111 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1113 NameSize
*= sizeof(WCHAR
);
1115 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1117 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1118 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1120 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1122 Status
= STATUS_BUFFER_TOO_SMALL
;
1126 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1127 KeyValueInformation
;
1128 ValueFullInformation
->TitleIndex
= 0;
1129 ValueFullInformation
->Type
= ValueCell
->DataType
;
1130 ValueFullInformation
->NameLength
= NameSize
;
1131 ValueFullInformation
->DataOffset
=
1132 (ULONG_PTR
)ValueFullInformation
->Name
-
1133 (ULONG_PTR
)ValueFullInformation
+
1134 ValueFullInformation
->NameLength
;
1135 ValueFullInformation
->DataOffset
=
1136 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1137 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1139 if (Length
< ValueFullInformation
->DataOffset
)
1141 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1143 Status
= STATUS_BUFFER_OVERFLOW
;
1146 else if (Length
- ValueFullInformation
->DataOffset
< DataSize
)
1148 DataSize
= Length
- ValueFullInformation
->DataOffset
;
1149 Status
= STATUS_BUFFER_OVERFLOW
;
1153 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1155 CmiCopyPackedName(ValueFullInformation
->Name
,
1157 NameSize
/ sizeof(WCHAR
));
1161 RtlCopyMemory(ValueFullInformation
->Name
,
1166 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1168 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1169 RtlCopyMemory((PCHAR
) ValueFullInformation
1170 + ValueFullInformation
->DataOffset
,
1171 DataCell
->Data
, DataSize
);
1175 RtlCopyMemory((PCHAR
) ValueFullInformation
1176 + ValueFullInformation
->DataOffset
,
1177 &ValueCell
->DataOffset
, DataSize
);
1183 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1189 Status
= STATUS_UNSUCCESSFUL
;
1192 ExReleaseResourceLite(&CmiRegistryLock
);
1193 KeLeaveCriticalRegion();
1194 ObDereferenceObject(KeyObject
);
1201 NtFlushKey(IN HANDLE KeyHandle
)
1204 PKEY_OBJECT KeyObject
;
1205 PREGISTRY_HIVE RegistryHive
;
1206 KPROCESSOR_MODE PreviousMode
;
1210 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle
);
1212 PreviousMode
= ExGetPreviousMode();
1214 /* Verify that the handle is valid and is a registry key */
1215 Status
= ObReferenceObjectByHandle(KeyHandle
,
1219 (PVOID
*)&KeyObject
,
1221 if (!NT_SUCCESS(Status
))
1226 VERIFY_KEY_OBJECT(KeyObject
);
1228 RegistryHive
= KeyObject
->RegistryHive
;
1230 /* Acquire hive lock */
1231 KeEnterCriticalRegion();
1232 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1234 if (IsNoFileHive(RegistryHive
))
1236 Status
= STATUS_SUCCESS
;
1240 /* Flush non-volatile hive */
1241 Status
= CmiFlushRegistryHive(RegistryHive
);
1244 ExReleaseResourceLite(&CmiRegistryLock
);
1245 KeLeaveCriticalRegion();
1247 ObDereferenceObject(KeyObject
);
1249 return STATUS_SUCCESS
;
1254 NtOpenKey(OUT PHANDLE KeyHandle
,
1255 IN ACCESS_MASK DesiredAccess
,
1256 IN POBJECT_ATTRIBUTES ObjectAttributes
)
1258 UNICODE_STRING RemainingPath
;
1259 KPROCESSOR_MODE PreviousMode
;
1260 PVOID Object
= NULL
;
1262 NTSTATUS Status
= STATUS_SUCCESS
;
1263 UNICODE_STRING ObjectName
;
1264 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
1265 REG_PRE_OPEN_KEY_INFORMATION PreOpenKeyInfo
;
1266 REG_POST_OPEN_KEY_INFORMATION PostOpenKeyInfo
;
1270 DPRINT("NtOpenKey(KH 0x%p DA %x OA 0x%p OA->ON '%wZ'\n",
1274 ObjectAttributes
? ObjectAttributes
->ObjectName
: NULL
);
1276 /* Check place for result handle, if it's null - return immediately */
1277 if (KeyHandle
== NULL
)
1278 return(STATUS_INVALID_PARAMETER
);
1280 PreviousMode
= ExGetPreviousMode();
1282 if(PreviousMode
!= KernelMode
)
1286 ProbeForWriteHandle(KeyHandle
);
1290 Status
= _SEH_GetExceptionCode();
1294 if(!NT_SUCCESS(Status
))
1300 /* WINE checks for the length also */
1301 /*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
1302 return(STATUS_BUFFER_OVERFLOW);*/
1304 /* Capture all the info */
1305 DPRINT("Capturing Create Info\n");
1306 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
1311 if (!NT_SUCCESS(Status
))
1313 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
1317 PostOpenKeyInfo
.CompleteName
= &ObjectName
;
1318 PreOpenKeyInfo
.CompleteName
= &ObjectName
;
1319 Status
= CmiCallRegisteredCallbacks(RegNtPreOpenKey
, &PreOpenKeyInfo
);
1320 if (!NT_SUCCESS(Status
))
1322 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
1323 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
1328 RemainingPath
.Buffer
= NULL
;
1330 Status
= ObFindObject(&ObjectCreateInfo
,
1335 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
1336 if (!NT_SUCCESS(Status
))
1338 DPRINT("CmpFindObject() returned 0x%08lx\n", Status
);
1339 Status
= STATUS_INVALID_HANDLE
; /* Because CmpFindObject returns STATUS_UNSUCCESSFUL */
1340 hKey
= *KeyHandle
; /* Preserve hkResult value */
1341 goto openkey_cleanup
;
1344 VERIFY_KEY_OBJECT((PKEY_OBJECT
) Object
);
1346 DPRINT("RemainingPath '%wZ'\n", &RemainingPath
);
1348 if ((RemainingPath
.Buffer
!= NULL
) && (RemainingPath
.Buffer
[0] != 0))
1350 RtlFreeUnicodeString(&RemainingPath
);
1351 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1353 goto openkey_cleanup
;
1356 RtlFreeUnicodeString(&RemainingPath
);
1358 /* Fail if the key has been deleted */
1359 if (((PKEY_OBJECT
)Object
)->Flags
& KO_MARKED_FOR_DELETE
)
1361 Status
= STATUS_UNSUCCESSFUL
;
1363 goto openkey_cleanup
;
1366 Status
= ObpCreateHandle(PsGetCurrentProcess(),
1372 if (!NT_SUCCESS(Status
))
1377 PostOpenKeyInfo
.Object
= NT_SUCCESS(Status
) ? (PVOID
)Object
: NULL
;
1378 PostOpenKeyInfo
.Status
= Status
;
1379 CmiCallRegisteredCallbacks (RegNtPostOpenKey
, &PostOpenKeyInfo
);
1380 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
1384 ObDereferenceObject(Object
);
1393 Status
= _SEH_GetExceptionCode();
1402 NtQueryKey(IN HANDLE KeyHandle
,
1403 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1404 OUT PVOID KeyInformation
,
1406 OUT PULONG ResultLength
)
1408 PKEY_BASIC_INFORMATION BasicInformation
;
1409 PKEY_NODE_INFORMATION NodeInformation
;
1410 PKEY_FULL_INFORMATION FullInformation
;
1411 PREGISTRY_HIVE RegistryHive
;
1412 PDATA_CELL ClassCell
;
1413 PKEY_OBJECT KeyObject
;
1415 ULONG NameSize
, ClassSize
;
1417 REG_QUERY_KEY_INFORMATION QueryKeyInfo
;
1418 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1422 DPRINT("NtQueryKey(KH 0x%p KIC %x KI 0x%p L %d RL 0x%p)\n",
1424 KeyInformationClass
,
1429 /* Verify that the handle is valid and is a registry key */
1430 Status
= ObReferenceObjectByHandle(KeyHandle
,
1431 (KeyInformationClass
!= KeyNameInformation
? KEY_QUERY_VALUE
: 0),
1433 ExGetPreviousMode(),
1434 (PVOID
*) &KeyObject
,
1436 if (!NT_SUCCESS(Status
))
1441 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1442 QueryKeyInfo
.Object
= (PVOID
)KeyObject
;
1443 QueryKeyInfo
.KeyInformationClass
= KeyInformationClass
;
1444 QueryKeyInfo
.KeyInformation
= KeyInformation
;
1445 QueryKeyInfo
.Length
= Length
;
1446 QueryKeyInfo
.ResultLength
= ResultLength
;
1448 Status
= CmiCallRegisteredCallbacks(RegNtQueryKey
, &QueryKeyInfo
);
1449 if (!NT_SUCCESS(Status
))
1451 ObDereferenceObject(KeyObject
);
1455 /* Acquire hive lock */
1456 KeEnterCriticalRegion();
1457 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1459 VERIFY_KEY_OBJECT(KeyObject
);
1461 /* Get pointer to KeyCell */
1462 KeyCell
= KeyObject
->KeyCell
;
1463 RegistryHive
= KeyObject
->RegistryHive
;
1465 Status
= STATUS_SUCCESS
;
1466 switch (KeyInformationClass
)
1468 case KeyBasicInformation
:
1469 NameSize
= KeyObject
->Name
.Length
;
1471 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1473 /* Check size of buffer */
1474 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
1476 Status
= STATUS_BUFFER_TOO_SMALL
;
1480 /* Fill buffer with requested info */
1481 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
1482 BasicInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1483 BasicInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1484 BasicInformation
->TitleIndex
= 0;
1485 BasicInformation
->NameLength
= KeyObject
->Name
.Length
;
1487 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) <
1490 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1491 Status
= STATUS_BUFFER_OVERFLOW
;
1495 RtlCopyMemory(BasicInformation
->Name
,
1496 KeyObject
->Name
.Buffer
,
1501 case KeyNodeInformation
:
1502 NameSize
= KeyObject
->Name
.Length
;
1503 ClassSize
= KeyCell
->ClassSize
;
1505 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
1506 NameSize
+ ClassSize
;
1508 /* Check size of buffer */
1509 if (Length
< *ResultLength
)
1511 Status
= STATUS_BUFFER_TOO_SMALL
;
1515 /* Fill buffer with requested info */
1516 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
1517 NodeInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1518 NodeInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1519 NodeInformation
->TitleIndex
= 0;
1520 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
1521 KeyObject
->Name
.Length
;
1522 NodeInformation
->ClassLength
= KeyCell
->ClassSize
;
1523 NodeInformation
->NameLength
= KeyObject
->Name
.Length
;
1525 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
1527 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
1529 Status
= STATUS_BUFFER_OVERFLOW
;
1532 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1533 NameSize
< ClassSize
)
1535 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1537 Status
= STATUS_BUFFER_OVERFLOW
;
1541 RtlCopyMemory(NodeInformation
->Name
,
1542 KeyObject
->Name
.Buffer
,
1547 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1548 KeyCell
->ClassNameOffset
,
1550 RtlCopyMemory (NodeInformation
->Name
+ KeyObject
->Name
.Length
,
1557 case KeyFullInformation
:
1558 ClassSize
= KeyCell
->ClassSize
;
1560 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
1563 /* Check size of buffer */
1564 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
))
1566 Status
= STATUS_BUFFER_TOO_SMALL
;
1570 /* Fill buffer with requested info */
1571 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
1572 FullInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1573 FullInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1574 FullInformation
->TitleIndex
= 0;
1575 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) - sizeof(WCHAR
);
1576 FullInformation
->ClassLength
= KeyCell
->ClassSize
;
1577 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //KeyCell->NumberOfSubKeys;
1578 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
1579 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
1580 FullInformation
->Values
= KeyCell
->NumberOfValues
;
1581 FullInformation
->MaxValueNameLen
=
1582 CmiGetMaxValueNameLength(RegistryHive
, KeyCell
);
1583 FullInformation
->MaxValueDataLen
=
1584 CmiGetMaxValueDataLength(RegistryHive
, KeyCell
);
1586 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
1588 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
1589 Status
= STATUS_BUFFER_OVERFLOW
;
1595 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1596 KeyCell
->ClassNameOffset
,
1598 RtlCopyMemory (FullInformation
->Class
,
1599 ClassCell
->Data
, ClassSize
);
1604 case KeyNameInformation
:
1605 case KeyCachedInformation
:
1606 case KeyFlagsInformation
:
1607 DPRINT1("Key information class 0x%x not yet implemented!\n", KeyInformationClass
);
1608 Status
= STATUS_NOT_IMPLEMENTED
;
1612 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
1613 Status
= STATUS_INVALID_INFO_CLASS
;
1617 ExReleaseResourceLite(&CmiRegistryLock
);
1618 KeLeaveCriticalRegion();
1620 PostOperationInfo
.Status
= Status
;
1621 CmiCallRegisteredCallbacks(RegNtPostQueryKey
, &PostOperationInfo
);
1623 ObDereferenceObject(KeyObject
);
1630 NtQueryValueKey(IN HANDLE KeyHandle
,
1631 IN PUNICODE_STRING ValueName
,
1632 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1633 OUT PVOID KeyValueInformation
,
1635 OUT PULONG ResultLength
)
1638 ULONG NameSize
, DataSize
;
1639 PKEY_OBJECT KeyObject
;
1640 PREGISTRY_HIVE RegistryHive
;
1642 PVALUE_CELL ValueCell
;
1643 PDATA_CELL DataCell
;
1644 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
1645 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
1646 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
1647 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo
;
1648 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1652 DPRINT("NtQueryValueKey(KeyHandle 0x%p ValueName %S Length %x)\n",
1653 KeyHandle
, ValueName
->Buffer
, Length
);
1655 /* Verify that the handle is valid and is a registry key */
1656 Status
= ObReferenceObjectByHandle(KeyHandle
,
1659 ExGetPreviousMode(),
1660 (PVOID
*)&KeyObject
,
1663 if (!NT_SUCCESS(Status
))
1665 DPRINT1("ObReferenceObjectByHandle() failed with status %x %p\n", Status
, KeyHandle
);
1669 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1670 QueryValueKeyInfo
.Object
= (PVOID
)KeyObject
;
1671 QueryValueKeyInfo
.ValueName
= ValueName
;
1672 QueryValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
1673 QueryValueKeyInfo
.Length
= Length
;
1674 QueryValueKeyInfo
.ResultLength
= ResultLength
;
1676 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
1677 if (!NT_SUCCESS(Status
))
1679 ObDereferenceObject(KeyObject
);
1683 /* Acquire hive lock */
1684 KeEnterCriticalRegion();
1685 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1687 VERIFY_KEY_OBJECT(KeyObject
);
1689 /* Get pointer to KeyCell */
1690 KeyCell
= KeyObject
->KeyCell
;
1691 RegistryHive
= KeyObject
->RegistryHive
;
1693 /* Get value cell by name */
1694 Status
= CmiScanKeyForValue(RegistryHive
,
1699 if (!NT_SUCCESS(Status
))
1701 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
1705 Status
= STATUS_SUCCESS
;
1706 switch (KeyValueInformationClass
)
1708 case KeyValueBasicInformation
:
1709 NameSize
= ValueCell
->NameSize
;
1710 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1712 NameSize
*= sizeof(WCHAR
);
1715 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) +
1718 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1720 Status
= STATUS_BUFFER_TOO_SMALL
;
1724 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1725 KeyValueInformation
;
1726 ValueBasicInformation
->TitleIndex
= 0;
1727 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1728 ValueBasicInformation
->NameLength
= NameSize
;
1730 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1733 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1734 Status
= STATUS_BUFFER_OVERFLOW
;
1738 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1740 CmiCopyPackedName(ValueBasicInformation
->Name
,
1742 NameSize
/ sizeof(WCHAR
));
1746 RtlCopyMemory(ValueBasicInformation
->Name
,
1753 case KeyValuePartialInformation
:
1754 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1756 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1759 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1761 Status
= STATUS_BUFFER_TOO_SMALL
;
1765 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1766 KeyValueInformation
;
1767 ValuePartialInformation
->TitleIndex
= 0;
1768 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1769 ValuePartialInformation
->DataLength
= DataSize
;
1771 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1774 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1775 Status
= STATUS_BUFFER_OVERFLOW
;
1779 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1781 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1782 RtlCopyMemory(ValuePartialInformation
->Data
,
1788 RtlCopyMemory(ValuePartialInformation
->Data
,
1789 &ValueCell
->DataOffset
,
1795 case KeyValueFullInformation
:
1796 NameSize
= ValueCell
->NameSize
;
1797 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1799 NameSize
*= sizeof(WCHAR
);
1801 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1803 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1804 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1806 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1808 Status
= STATUS_BUFFER_TOO_SMALL
;
1812 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1813 KeyValueInformation
;
1814 ValueFullInformation
->TitleIndex
= 0;
1815 ValueFullInformation
->Type
= ValueCell
->DataType
;
1816 ValueFullInformation
->NameLength
= NameSize
;
1817 ValueFullInformation
->DataOffset
=
1818 (ULONG_PTR
)ValueFullInformation
->Name
-
1819 (ULONG_PTR
)ValueFullInformation
+
1820 ValueFullInformation
->NameLength
;
1821 ValueFullInformation
->DataOffset
=
1822 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1823 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1825 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1828 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1830 Status
= STATUS_BUFFER_OVERFLOW
;
1833 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1834 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1836 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1837 Name
[0]) - NameSize
, sizeof(PVOID
));
1838 Status
= STATUS_BUFFER_OVERFLOW
;
1842 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1844 CmiCopyPackedName(ValueFullInformation
->Name
,
1846 NameSize
/ sizeof(WCHAR
));
1850 RtlCopyMemory(ValueFullInformation
->Name
,
1854 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1856 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1857 RtlCopyMemory((PCHAR
) ValueFullInformation
1858 + ValueFullInformation
->DataOffset
,
1864 RtlCopyMemory((PCHAR
) ValueFullInformation
1865 + ValueFullInformation
->DataOffset
,
1866 &ValueCell
->DataOffset
,
1873 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1874 Status
= STATUS_INVALID_INFO_CLASS
;
1879 ExReleaseResourceLite(&CmiRegistryLock
);
1880 KeLeaveCriticalRegion();
1882 PostOperationInfo
.Status
= Status
;
1883 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
1884 ObDereferenceObject(KeyObject
);
1891 NtSetValueKey(IN HANDLE KeyHandle
,
1892 IN PUNICODE_STRING ValueName
,
1893 IN ULONG TitleIndex
,
1899 PKEY_OBJECT KeyObject
;
1900 PREGISTRY_HIVE RegistryHive
;
1902 PVALUE_CELL ValueCell
;
1903 BLOCK_OFFSET ValueCellOffset
;
1904 PDATA_CELL DataCell
;
1905 PDATA_CELL NewDataCell
;
1906 ULONG DesiredAccess
;
1907 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo
;
1908 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1913 DPRINT("NtSetValueKey(KeyHandle 0x%p ValueName '%wZ' Type %d)\n",
1914 KeyHandle
, ValueName
, Type
);
1916 DesiredAccess
= KEY_SET_VALUE
;
1918 /* Verify that the handle is valid and is a registry key */
1919 Status
= ObReferenceObjectByHandle(KeyHandle
,
1922 ExGetPreviousMode(),
1923 (PVOID
*)&KeyObject
,
1925 if (!NT_SUCCESS(Status
))
1928 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1929 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
1930 SetValueKeyInfo
.ValueName
= ValueName
;
1931 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
1932 SetValueKeyInfo
.Type
= Type
;
1933 SetValueKeyInfo
.Data
= Data
;
1934 SetValueKeyInfo
.DataSize
= DataSize
;
1935 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
1936 if (!NT_SUCCESS(Status
))
1938 ObDereferenceObject(KeyObject
);
1942 /* Acquire hive lock exclucively */
1943 KeEnterCriticalRegion();
1944 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1946 VERIFY_KEY_OBJECT(KeyObject
);
1948 /* Get pointer to key cell */
1949 KeyCell
= KeyObject
->KeyCell
;
1950 RegistryHive
= KeyObject
->RegistryHive
;
1951 Status
= CmiScanKeyForValue(RegistryHive
,
1956 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1958 DPRINT("Allocate new value cell\n");
1959 Status
= CmiAddValueToKey(RegistryHive
,
1961 KeyObject
->KeyCellOffset
,
1967 if (!NT_SUCCESS(Status
))
1969 DPRINT("Cannot add value. Status 0x%X\n", Status
);
1971 ExReleaseResourceLite(&CmiRegistryLock
);
1972 KeLeaveCriticalRegion();
1973 PostOperationInfo
.Status
= Status
;
1974 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
1975 ObDereferenceObject(KeyObject
);
1979 DPRINT("DataSize %lu\n", DataSize
);
1980 DPRINT("ValueCell %p\n", ValueCell
);
1981 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1983 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1984 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1986 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1987 DataCellSize
= (DataCell
->CellSize
< 0 ? -DataCell
->CellSize
: DataCell
->CellSize
) - sizeof(CELL_HEADER
);
1996 if (DataSize
<= sizeof(BLOCK_OFFSET
))
1998 /* If data size <= sizeof(BLOCK_OFFSET) then store data in the data offset */
1999 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
2002 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
2005 RtlCopyMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
2006 ValueCell
->DataSize
= DataSize
| REG_DATA_IN_OFFSET
;
2007 ValueCell
->DataType
= Type
;
2008 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
2012 if (DataSize
> DataCellSize
)
2015 * New data size is larger than the current, destroy current
2016 * data block and allocate a new one.
2018 BLOCK_OFFSET NewOffset
;
2020 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
2022 Status
= CmiAllocateCell (RegistryHive
,
2023 sizeof(CELL_HEADER
) + DataSize
,
2024 (PVOID
*)&NewDataCell
,
2026 if (!NT_SUCCESS(Status
))
2028 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status
);
2030 ExReleaseResourceLite(&CmiRegistryLock
);
2031 KeLeaveCriticalRegion();
2032 PostOperationInfo
.Status
= Status
;
2033 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
2034 ObDereferenceObject(KeyObject
);
2041 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
2044 ValueCell
->DataOffset
= NewOffset
;
2045 DataCell
= NewDataCell
;
2048 RtlCopyMemory(DataCell
->Data
, Data
, DataSize
);
2049 ValueCell
->DataSize
= DataSize
& REG_DATA_SIZE_MASK
;
2050 ValueCell
->DataType
= Type
;
2051 CmiMarkBlockDirty(RegistryHive
, ValueCell
->DataOffset
);
2052 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
2056 if ((Type
== REG_LINK
) &&
2057 (_wcsicmp(ValueName
->Buffer
, L
"SymbolicLinkValue") == 0))
2059 KeyCell
->Flags
|= REG_KEY_LINK_CELL
;
2062 KeQuerySystemTime (&KeyCell
->LastWriteTime
);
2063 CmiMarkBlockDirty (RegistryHive
, KeyObject
->KeyCellOffset
);
2065 ExReleaseResourceLite(&CmiRegistryLock
);
2066 KeLeaveCriticalRegion();
2067 PostOperationInfo
.Status
= Status
;
2068 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
2069 ObDereferenceObject(KeyObject
);
2073 DPRINT("Return Status 0x%X\n", Status
);
2080 NtDeleteValueKey (IN HANDLE KeyHandle
,
2081 IN PUNICODE_STRING ValueName
)
2083 PKEY_OBJECT KeyObject
;
2085 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
2086 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2087 KPROCESSOR_MODE PreviousMode
;
2088 UNICODE_STRING CapturedValueName
;
2092 PreviousMode
= ExGetPreviousMode();
2094 /* Verify that the handle is valid and is a registry key */
2095 Status
= ObReferenceObjectByHandle(KeyHandle
,
2099 (PVOID
*)&KeyObject
,
2101 if (!NT_SUCCESS(Status
))
2106 Status
= ProbeAndCaptureUnicodeString(&CapturedValueName
,
2109 if (!NT_SUCCESS(Status
))
2113 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
2114 DeleteValueKeyInfo
.ValueName
= &CapturedValueName
;
2116 /* FIXME - check if value exists before calling the callbacks? */
2117 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
, &DeleteValueKeyInfo
);
2118 if (!NT_SUCCESS(Status
))
2120 ReleaseCapturedUnicodeString(&CapturedValueName
,
2123 ObDereferenceObject(KeyObject
);
2127 /* Acquire hive lock */
2128 KeEnterCriticalRegion();
2129 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2131 VERIFY_KEY_OBJECT(KeyObject
);
2133 Status
= CmiDeleteValueFromKey(KeyObject
->RegistryHive
,
2135 KeyObject
->KeyCellOffset
,
2138 KeQuerySystemTime (&KeyObject
->KeyCell
->LastWriteTime
);
2139 CmiMarkBlockDirty (KeyObject
->RegistryHive
, KeyObject
->KeyCellOffset
);
2141 /* Release hive lock */
2142 ExReleaseResourceLite(&CmiRegistryLock
);
2143 KeLeaveCriticalRegion();
2145 ReleaseCapturedUnicodeString(&CapturedValueName
,
2148 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2149 PostOperationInfo
.Status
= Status
;
2151 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
, &PostOperationInfo
);
2153 ObDereferenceObject (KeyObject
);
2163 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2164 * KeyObjectAttributes->Name specifies the name of the key to load.
2167 NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
2168 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
2170 return NtLoadKey2 (KeyObjectAttributes
,
2171 FileObjectAttributes
,
2178 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2179 * KeyObjectAttributes->Name specifies the name of the key to load.
2180 * Flags can be 0 or REG_NO_LAZY_FLUSH.
2183 NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
2184 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
2187 POBJECT_NAME_INFORMATION NameInfo
;
2188 PUNICODE_STRING NamePointer
;
2196 DPRINT ("NtLoadKey2() called\n");
2199 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, ExGetPreviousMode ()))
2200 return STATUS_PRIVILEGE_NOT_HELD
;
2203 if (FileObjectAttributes
->RootDirectory
!= NULL
)
2206 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2207 Buffer
= ExAllocatePool (NonPagedPool
,
2210 return STATUS_INSUFFICIENT_RESOURCES
;
2212 Status
= ZwQueryObject (FileObjectAttributes
->RootDirectory
,
2213 ObjectNameInformation
,
2217 if (!NT_SUCCESS(Status
))
2219 DPRINT1 ("NtQueryObject() failed (Status %lx)\n", Status
);
2220 ExFreePool (Buffer
);
2224 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2225 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2226 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2228 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2229 if (FileObjectAttributes
->ObjectName
->Buffer
[0] != L
'\\')
2231 RtlAppendUnicodeToString (&NameInfo
->Name
,
2233 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2234 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2236 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2237 FileObjectAttributes
->ObjectName
);
2239 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2240 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2241 NamePointer
= &NameInfo
->Name
;
2245 if (FileObjectAttributes
->ObjectName
->Buffer
[0] == L
'\\')
2248 NamePointer
= FileObjectAttributes
->ObjectName
;
2253 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2254 Buffer
= ExAllocatePool (NonPagedPool
,
2257 return STATUS_INSUFFICIENT_RESOURCES
;
2259 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2260 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2261 NameInfo
->Name
.Length
= 0;
2262 NameInfo
->Name
.Buffer
= (PWSTR
)((ULONG_PTR
)Buffer
+ sizeof(OBJECT_NAME_INFORMATION
));
2263 NameInfo
->Name
.Buffer
[0] = 0;
2265 RtlAppendUnicodeToString (&NameInfo
->Name
,
2267 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2268 FileObjectAttributes
->ObjectName
);
2270 NamePointer
= &NameInfo
->Name
;
2274 DPRINT ("Full name: '%wZ'\n", NamePointer
);
2276 /* Acquire hive lock */
2277 KeEnterCriticalRegion();
2278 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2280 Status
= CmiLoadHive (KeyObjectAttributes
,
2283 if (!NT_SUCCESS (Status
))
2285 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
2288 /* Release hive lock */
2289 ExReleaseResourceLite(&CmiRegistryLock
);
2290 KeLeaveCriticalRegion();
2293 ExFreePool (Buffer
);
2300 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2302 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2303 IN PVOID ApcContext OPTIONAL
,
2304 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2305 IN ULONG CompletionFilter
,
2306 IN BOOLEAN WatchSubtree
,
2309 IN BOOLEAN Asynchronous
)
2312 return(STATUS_NOT_IMPLEMENTED
);
2317 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2319 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2320 IN PVOID ApcContext OPTIONAL
,
2321 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2322 IN ULONG CompletionFilter
,
2323 IN BOOLEAN WatchSubtree
,
2326 IN BOOLEAN Asynchronous
)
2328 return NtNotifyChangeMultipleKeys(KeyHandle
,
2345 NtQueryMultipleValueKey (IN HANDLE KeyHandle
,
2346 IN OUT PKEY_VALUE_ENTRY ValueList
,
2347 IN ULONG NumberOfValues
,
2349 IN OUT PULONG Length
,
2350 OUT PULONG ReturnLength
)
2352 PREGISTRY_HIVE RegistryHive
;
2353 PVALUE_CELL ValueCell
;
2354 PKEY_OBJECT KeyObject
;
2355 PDATA_CELL DataCell
;
2356 ULONG BufferLength
= 0;
2361 REG_QUERY_MULTIPLE_VALUE_KEY_INFORMATION QueryMultipleValueKeyInfo
;
2362 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2366 /* Verify that the handle is valid and is a registry key */
2367 Status
= ObReferenceObjectByHandle(KeyHandle
,
2370 ExGetPreviousMode(),
2371 (PVOID
*) &KeyObject
,
2373 if (!NT_SUCCESS(Status
))
2375 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2379 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2380 QueryMultipleValueKeyInfo
.Object
= (PVOID
)KeyObject
;
2381 QueryMultipleValueKeyInfo
.ValueEntries
= ValueList
;
2382 QueryMultipleValueKeyInfo
.EntryCount
= NumberOfValues
;
2383 QueryMultipleValueKeyInfo
.ValueBuffer
= Buffer
;
2384 QueryMultipleValueKeyInfo
.BufferLength
= Length
;
2385 QueryMultipleValueKeyInfo
.RequiredBufferLength
= ReturnLength
;
2387 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryMultipleValueKey
, &QueryMultipleValueKeyInfo
);
2388 if (!NT_SUCCESS(Status
))
2390 ObDereferenceObject(KeyObject
);
2394 /* Acquire hive lock */
2395 KeEnterCriticalRegion();
2396 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
2398 VERIFY_KEY_OBJECT(KeyObject
);
2400 /* Get pointer to KeyCell */
2401 KeyCell
= KeyObject
->KeyCell
;
2402 RegistryHive
= KeyObject
->RegistryHive
;
2404 DataPtr
= (PUCHAR
) Buffer
;
2406 for (i
= 0; i
< NumberOfValues
; i
++)
2408 DPRINT("ValueName: '%wZ'\n", ValueList
[i
].ValueName
);
2410 /* Get Value block of interest */
2411 Status
= CmiScanKeyForValue(RegistryHive
,
2413 ValueList
[i
].ValueName
,
2417 if (!NT_SUCCESS(Status
))
2419 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
2422 else if (ValueCell
== NULL
)
2424 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
2428 BufferLength
= ROUND_UP(BufferLength
, sizeof(PVOID
));
2430 if (BufferLength
+ (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) <= *Length
)
2432 DataPtr
= (PUCHAR
)ROUND_UP((ULONG_PTR
)DataPtr
, sizeof(PVOID
));
2434 ValueList
[i
].Type
= ValueCell
->DataType
;
2435 ValueList
[i
].DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2436 ValueList
[i
].DataOffset
= (ULONG_PTR
)DataPtr
- (ULONG_PTR
)Buffer
;
2438 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
2440 DataCell
= CmiGetCell (RegistryHive
,
2441 ValueCell
->DataOffset
,
2443 RtlCopyMemory(DataPtr
,
2445 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2449 RtlCopyMemory(DataPtr
,
2450 &ValueCell
->DataOffset
,
2451 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2454 DataPtr
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2458 Status
= STATUS_BUFFER_TOO_SMALL
;
2461 BufferLength
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2464 if (NT_SUCCESS(Status
))
2465 *Length
= BufferLength
;
2467 *ReturnLength
= BufferLength
;
2469 /* Release hive lock */
2470 ExReleaseResourceLite(&CmiRegistryLock
);
2471 KeLeaveCriticalRegion();
2473 PostOperationInfo
.Status
= Status
;
2474 CmiCallRegisteredCallbacks(RegNtPostQueryMultipleValueKey
, &PostOperationInfo
);
2476 ObDereferenceObject(KeyObject
);
2478 DPRINT("Return Status 0x%X\n", Status
);
2485 NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes
,
2487 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
2490 return(STATUS_NOT_IMPLEMENTED
);
2495 NtRestoreKey (IN HANDLE KeyHandle
,
2496 IN HANDLE FileHandle
,
2497 IN ULONG RestoreFlags
)
2500 return(STATUS_NOT_IMPLEMENTED
);
2505 NtSaveKey (IN HANDLE KeyHandle
,
2506 IN HANDLE FileHandle
)
2508 PREGISTRY_HIVE TempHive
;
2509 PKEY_OBJECT KeyObject
;
2514 DPRINT ("NtSaveKey() called\n");
2517 if (!SeSinglePrivilegeCheck (SeBackupPrivilege
, ExGetPreviousMode ()))
2518 return STATUS_PRIVILEGE_NOT_HELD
;
2521 Status
= ObReferenceObjectByHandle (KeyHandle
,
2524 ExGetPreviousMode(),
2525 (PVOID
*)&KeyObject
,
2527 if (!NT_SUCCESS(Status
))
2529 DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
2533 /* Acquire hive lock exclucively */
2534 KeEnterCriticalRegion();
2535 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2537 /* Refuse to save a volatile key */
2538 if (KeyObject
->RegistryHive
== CmiVolatileHive
)
2540 DPRINT1 ("Cannot save a volatile key\n");
2541 ExReleaseResourceLite(&CmiRegistryLock
);
2542 KeLeaveCriticalRegion();
2543 ObDereferenceObject (KeyObject
);
2544 return STATUS_ACCESS_DENIED
;
2547 Status
= CmiCreateTempHive(&TempHive
);
2548 if (!NT_SUCCESS(Status
))
2550 DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status
);
2551 ExReleaseResourceLite(&CmiRegistryLock
);
2552 KeLeaveCriticalRegion();
2553 ObDereferenceObject (KeyObject
);
2557 Status
= CmiCopyKey (TempHive
,
2559 KeyObject
->RegistryHive
,
2560 KeyObject
->KeyCell
);
2561 if (!NT_SUCCESS(Status
))
2563 DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status
);
2564 CmiRemoveRegistryHive (TempHive
);
2565 ExReleaseResourceLite(&CmiRegistryLock
);
2566 KeLeaveCriticalRegion();
2567 ObDereferenceObject (KeyObject
);
2571 Status
= CmiSaveTempHive (TempHive
,
2573 if (!NT_SUCCESS(Status
))
2575 DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status
);
2578 CmiRemoveRegistryHive (TempHive
);
2580 /* Release hive lock */
2581 ExReleaseResourceLite(&CmiRegistryLock
);
2582 KeLeaveCriticalRegion();
2584 ObDereferenceObject (KeyObject
);
2586 DPRINT ("NtSaveKey() done\n");
2588 return STATUS_SUCCESS
;
2597 IN HANDLE KeyHandle
,
2598 IN HANDLE FileHandle
,
2599 IN ULONG Flags
// REG_STANDARD_FORMAT, etc..
2603 return STATUS_NOT_IMPLEMENTED
;
2608 NtSetInformationKey (IN HANDLE KeyHandle
,
2609 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
2610 IN PVOID KeyInformation
,
2611 IN ULONG KeyInformationLength
)
2613 PKEY_OBJECT KeyObject
;
2615 REG_SET_INFORMATION_KEY_INFORMATION SetInformationKeyInfo
;
2616 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2620 /* Verify that the handle is valid and is a registry key */
2621 Status
= ObReferenceObjectByHandle (KeyHandle
,
2624 ExGetPreviousMode(),
2625 (PVOID
*)&KeyObject
,
2627 if (!NT_SUCCESS (Status
))
2629 DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2633 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2634 SetInformationKeyInfo
.Object
= (PVOID
)KeyObject
;
2635 SetInformationKeyInfo
.KeySetInformationClass
= KeyInformationClass
;
2636 SetInformationKeyInfo
.KeySetInformation
= KeyInformation
;
2637 SetInformationKeyInfo
.KeySetInformationLength
= KeyInformationLength
;
2639 Status
= CmiCallRegisteredCallbacks(RegNtSetInformationKey
, &SetInformationKeyInfo
);
2640 if (!NT_SUCCESS(Status
))
2642 ObDereferenceObject (KeyObject
);
2646 if (KeyInformationClass
!= KeyWriteTimeInformation
)
2648 Status
= STATUS_INVALID_INFO_CLASS
;
2651 else if (KeyInformationLength
!= sizeof (KEY_WRITE_TIME_INFORMATION
))
2653 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2657 /* Acquire hive lock */
2658 KeEnterCriticalRegion();
2659 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2661 VERIFY_KEY_OBJECT(KeyObject
);
2663 KeyObject
->KeyCell
->LastWriteTime
.QuadPart
=
2664 ((PKEY_WRITE_TIME_INFORMATION
)KeyInformation
)->LastWriteTime
.QuadPart
;
2666 CmiMarkBlockDirty (KeyObject
->RegistryHive
,
2667 KeyObject
->KeyCellOffset
);
2669 /* Release hive lock */
2670 ExReleaseResourceLite(&CmiRegistryLock
);
2671 KeLeaveCriticalRegion();
2674 PostOperationInfo
.Status
= Status
;
2675 CmiCallRegisteredCallbacks(RegNtPostSetInformationKey
, &PostOperationInfo
);
2677 ObDereferenceObject (KeyObject
);
2679 if (NT_SUCCESS(Status
))
2684 DPRINT ("NtSaveKey() done\n");
2686 return STATUS_SUCCESS
;
2692 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2693 * KeyObjectAttributes->Name specifies the name of the key to unload.
2696 NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
2698 PREGISTRY_HIVE RegistryHive
;
2703 DPRINT ("NtUnloadKey() called\n");
2706 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, ExGetPreviousMode ()))
2707 return STATUS_PRIVILEGE_NOT_HELD
;
2710 /* Acquire registry lock exclusively */
2711 KeEnterCriticalRegion();
2712 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2714 Status
= CmiDisconnectHive (KeyObjectAttributes
,
2716 if (!NT_SUCCESS (Status
))
2718 DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status
);
2719 ExReleaseResourceLite (&CmiRegistryLock
);
2720 KeLeaveCriticalRegion();
2724 DPRINT ("RegistryHive %p\n", RegistryHive
);
2728 if (!IsNoFileHive (RegistryHive
))
2729 CmiFlushRegistryHive (RegistryHive
);
2732 CmiRemoveRegistryHive (RegistryHive
);
2734 /* Release registry lock */
2735 ExReleaseResourceLite (&CmiRegistryLock
);
2736 KeLeaveCriticalRegion();
2738 DPRINT ("NtUnloadKey() done\n");
2740 return STATUS_SUCCESS
;
2745 NtInitializeRegistry (IN BOOLEAN SetUpBoot
)
2751 if (CmiRegistryInitialized
== TRUE
)
2752 return STATUS_ACCESS_DENIED
;
2754 /* Save boot log file */
2755 IopSaveBootLogToFile();
2757 Status
= CmiInitHives (SetUpBoot
);
2759 CmiRegistryInitialized
= TRUE
;