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
))
261 Status
= ObFindObject(&ObjectCreateInfo
,
266 if (!NT_SUCCESS(Status
))
268 PostCreateKeyInfo
.Object
= NULL
;
269 PostCreateKeyInfo
.Status
= Status
;
270 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
272 DPRINT1("CmpFindObject failed, Status: 0x%x\n", Status
);
276 DPRINT("RemainingPath %wZ\n", &RemainingPath
);
278 if (RemainingPath
.Length
== 0)
280 /* Fail if the key has been deleted */
281 if (((PKEY_OBJECT
) Object
)->Flags
& KO_MARKED_FOR_DELETE
)
283 PostCreateKeyInfo
.Object
= NULL
;
284 PostCreateKeyInfo
.Status
= STATUS_UNSUCCESSFUL
;
285 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
287 DPRINT1("Object marked for delete!\n");
288 Status
= STATUS_UNSUCCESSFUL
;
292 Status
= ObpCreateHandle(Object
,
294 ObjectCreateInfo
.Attributes
,
297 if (!NT_SUCCESS(Status
))
298 DPRINT1("ObpCreateHandle failed Status 0x%x\n", Status
);
300 PostCreateKeyInfo
.Object
= NULL
;
301 PostCreateKeyInfo
.Status
= Status
;
302 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
304 LocalDisposition
= REG_OPENED_EXISTING_KEY
;
308 /* If RemainingPath contains \ we must return error
309 because NtCreateKey doesn't create trees */
310 Start
= RemainingPath
.Buffer
;
314 for (i
= 1; i
< RemainingPath
.Length
/ sizeof(WCHAR
); i
++)
316 if (L
'\\' == RemainingPath
.Buffer
[i
])
318 DPRINT("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath
);
320 PostCreateKeyInfo
.Object
= NULL
;
321 PostCreateKeyInfo
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
322 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
324 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
329 DPRINT("RemainingPath %S ParentObject 0x%p\n", RemainingPath
.Buffer
, Object
);
331 Status
= ObCreateObject(PreviousMode
,
340 if (!NT_SUCCESS(Status
))
342 DPRINT1("ObCreateObject() failed!\n");
343 PostCreateKeyInfo
.Object
= NULL
;
344 PostCreateKeyInfo
.Status
= Status
;
345 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
350 Status
= ObInsertObject((PVOID
)KeyObject
,
356 if (!NT_SUCCESS(Status
))
358 ObDereferenceObject(KeyObject
);
359 DPRINT1("ObInsertObject() failed!\n");
361 PostCreateKeyInfo
.Object
= NULL
;
362 PostCreateKeyInfo
.Status
= Status
;
363 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
368 KeyObject
->ParentKey
= Object
;
370 if (CreateOptions
& REG_OPTION_VOLATILE
)
371 KeyObject
->RegistryHive
= CmiVolatileHive
;
373 KeyObject
->RegistryHive
= KeyObject
->ParentKey
->RegistryHive
;
375 KeyObject
->Flags
= 0;
376 KeyObject
->NumberOfSubKeys
= 0;
377 KeyObject
->SizeOfSubKeys
= 0;
378 KeyObject
->SubKeys
= NULL
;
380 /* Acquire hive lock */
381 KeEnterCriticalRegion();
382 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
384 InsertTailList(&CmiKeyObjectListHead
, &KeyObject
->ListEntry
);
386 /* add key to subkeys of parent if needed */
387 Status
= CmiAddSubKey(KeyObject
->RegistryHive
,
388 KeyObject
->ParentKey
,
394 if (!NT_SUCCESS(Status
))
396 DPRINT1("CmiAddSubKey() failed (Status %lx)\n", Status
);
397 /* Release hive lock */
398 ExReleaseResourceLite(&CmiRegistryLock
);
399 KeLeaveCriticalRegion();
400 ObDereferenceObject(KeyObject
);
402 PostCreateKeyInfo
.Object
= NULL
;
403 PostCreateKeyInfo
.Status
= STATUS_UNSUCCESSFUL
;
404 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
406 Status
= STATUS_UNSUCCESSFUL
;
410 if (Start
== RemainingPath
.Buffer
)
412 KeyObject
->Name
= RemainingPath
;
413 FreeRemainingPath
= FALSE
;
417 RtlpCreateUnicodeString(&KeyObject
->Name
, Start
, NonPagedPool
);
420 if (KeyObject
->RegistryHive
== KeyObject
->ParentKey
->RegistryHive
)
422 KeyObject
->KeyCell
->ParentKeyOffset
= KeyObject
->ParentKey
->KeyCellOffset
;
423 KeyObject
->KeyCell
->SecurityKeyOffset
= KeyObject
->ParentKey
->KeyCell
->SecurityKeyOffset
;
427 KeyObject
->KeyCell
->ParentKeyOffset
= -1;
428 KeyObject
->KeyCell
->SecurityKeyOffset
= -1;
429 /* This key must remain in memory unless it is deleted
430 or file is unloaded */
431 ObReferenceObject(KeyObject
);
434 CmiAddKeyToList(KeyObject
->ParentKey
, KeyObject
);
436 VERIFY_KEY_OBJECT(KeyObject
);
438 /* Release hive lock */
439 ExReleaseResourceLite(&CmiRegistryLock
);
440 KeLeaveCriticalRegion();
442 PostCreateKeyInfo
.Object
= KeyObject
;
443 PostCreateKeyInfo
.Status
= Status
;
444 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
448 LocalDisposition
= REG_CREATED_NEW_KEY
;
454 if (Disposition
!= NULL
)
456 *Disposition
= LocalDisposition
;
461 Status
= _SEH_GetExceptionCode();
466 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
469 ReleaseCapturedUnicodeString(&CapturedClass
,
472 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
473 if (FreeRemainingPath
) RtlFreeUnicodeString(&RemainingPath
);
474 if (Object
!= NULL
) ObDereferenceObject(Object
);
481 NtDeleteKey(IN HANDLE KeyHandle
)
483 KPROCESSOR_MODE PreviousMode
;
484 PKEY_OBJECT KeyObject
;
486 REG_DELETE_KEY_INFORMATION DeleteKeyInfo
;
487 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
491 DPRINT("NtDeleteKey(KeyHandle 0x%p) called\n", KeyHandle
);
493 PreviousMode
= ExGetPreviousMode();
495 /* Verify that the handle is valid and is a registry key */
496 Status
= ObReferenceObjectByHandle(KeyHandle
,
502 if (!NT_SUCCESS(Status
))
504 DPRINT1("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
508 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
509 DeleteKeyInfo
.Object
= (PVOID
)KeyObject
;
510 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &DeleteKeyInfo
);
511 if (!NT_SUCCESS(Status
))
513 PostOperationInfo
.Status
= Status
;
514 CmiCallRegisteredCallbacks(RegNtDeleteKey
, &PostOperationInfo
);
515 ObDereferenceObject(KeyObject
);
519 /* Acquire hive lock */
520 KeEnterCriticalRegion();
521 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
523 VERIFY_KEY_OBJECT(KeyObject
);
525 /* Check for subkeys */
526 if (KeyObject
->NumberOfSubKeys
!= 0)
528 Status
= STATUS_CANNOT_DELETE
;
532 /* Set the marked for delete bit in the key object */
533 KeyObject
->Flags
|= KO_MARKED_FOR_DELETE
;
534 Status
= STATUS_SUCCESS
;
537 /* Release hive lock */
538 ExReleaseResourceLite(&CmiRegistryLock
);
539 KeLeaveCriticalRegion();
541 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
543 /* Remove the keep-alive reference */
544 ObDereferenceObject(KeyObject
);
546 if (KeyObject
->RegistryHive
!= KeyObject
->ParentKey
->RegistryHive
)
547 ObDereferenceObject(KeyObject
);
549 PostOperationInfo
.Status
= Status
;
550 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
552 /* Dereference the object */
553 ObDereferenceObject(KeyObject
);
555 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
556 DPRINT("HandleCount %lu\n", ObGetObjectHandleCount((PVOID
)KeyObject
));
560 * Hive-Synchronization will not be triggered here. This is done in
561 * CmiObjectDelete() (in regobj.c) after all key-related structures
562 * have been released.
570 NtEnumerateKey(IN HANDLE KeyHandle
,
572 IN KEY_INFORMATION_CLASS KeyInformationClass
,
573 OUT PVOID KeyInformation
,
575 OUT PULONG ResultLength
)
577 PKEY_OBJECT KeyObject
;
578 PKEY_OBJECT SubKeyObject
;
579 PREGISTRY_HIVE RegistryHive
;
580 PKEY_CELL KeyCell
, SubKeyCell
;
581 PHASH_TABLE_CELL HashTableBlock
;
582 PKEY_BASIC_INFORMATION BasicInformation
;
583 PKEY_NODE_INFORMATION NodeInformation
;
584 PKEY_FULL_INFORMATION FullInformation
;
585 PDATA_CELL ClassCell
;
586 ULONG NameSize
, ClassSize
;
587 KPROCESSOR_MODE PreviousMode
;
589 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo
;
590 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
594 PreviousMode
= ExGetPreviousMode();
596 DPRINT("KH 0x%p I %d KIC %x KI 0x%p L %d RL 0x%p\n",
604 /* Verify that the handle is valid and is a registry key */
605 Status
= ObReferenceObjectByHandle(KeyHandle
,
606 KEY_ENUMERATE_SUB_KEYS
,
609 (PVOID
*) &KeyObject
,
611 if (!NT_SUCCESS(Status
))
613 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
617 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
618 EnumerateKeyInfo
.Object
= (PVOID
)KeyObject
;
619 EnumerateKeyInfo
.Index
= Index
;
620 EnumerateKeyInfo
.KeyInformationClass
= KeyInformationClass
;
621 EnumerateKeyInfo
.Length
= Length
;
622 EnumerateKeyInfo
.ResultLength
= ResultLength
;
624 Status
= CmiCallRegisteredCallbacks(RegNtEnumerateKey
, &EnumerateKeyInfo
);
625 if (!NT_SUCCESS(Status
))
627 ObDereferenceObject(KeyObject
);
631 /* Acquire hive lock */
632 KeEnterCriticalRegion();
633 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
635 VERIFY_KEY_OBJECT(KeyObject
);
637 /* Get pointer to KeyCell */
638 KeyCell
= KeyObject
->KeyCell
;
639 RegistryHive
= KeyObject
->RegistryHive
;
643 /* Check for hightest possible sub key index */
644 if (Index
>= KeyCell
->NumberOfSubKeys
+ KeyObject
->NumberOfSubKeys
)
646 ExReleaseResourceLite(&CmiRegistryLock
);
647 KeLeaveCriticalRegion();
648 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
649 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
650 ObDereferenceObject(KeyObject
);
651 DPRINT("No more volatile entries\n");
652 return STATUS_NO_MORE_ENTRIES
;
655 /* Get pointer to SubKey */
656 if (Index
>= KeyCell
->NumberOfSubKeys
)
658 PKEY_OBJECT CurKey
= NULL
;
662 /* Search for volatile or 'foreign' keys */
663 j
= KeyCell
->NumberOfSubKeys
;
664 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
666 CurKey
= KeyObject
->SubKeys
[i
];
667 if (CurKey
->RegistryHive
!= RegistryHive
)
675 if (i
>= KeyObject
->NumberOfSubKeys
)
677 ExReleaseResourceLite(&CmiRegistryLock
);
678 KeLeaveCriticalRegion();
679 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
680 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
681 ObDereferenceObject(KeyObject
);
682 DPRINT("No more non-volatile entries\n");
683 return STATUS_NO_MORE_ENTRIES
;
686 SubKeyObject
= CurKey
;
687 SubKeyCell
= CurKey
->KeyCell
;
691 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
693 ExReleaseResourceLite(&CmiRegistryLock
);
694 KeLeaveCriticalRegion();
695 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
696 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
697 ObDereferenceObject(KeyObject
);
698 return STATUS_NO_MORE_ENTRIES
;
701 HashTableBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
702 if (HashTableBlock
== NULL
)
704 DPRINT("CmiGetBlock() failed\n");
705 ExReleaseResourceLite(&CmiRegistryLock
);
706 KeLeaveCriticalRegion();
707 PostOperationInfo
.Status
= STATUS_UNSUCCESSFUL
;
708 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
709 ObDereferenceObject(KeyObject
);
710 return STATUS_UNSUCCESSFUL
;
713 SubKeyCell
= CmiGetKeyFromHashByIndex(RegistryHive
,
718 if (SubKeyCell
== NULL
)
720 ExReleaseResourceLite(&CmiRegistryLock
);
721 KeLeaveCriticalRegion();
722 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
723 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
724 ObDereferenceObject(KeyObject
);
725 DPRINT("No more entries\n");
726 return STATUS_NO_MORE_ENTRIES
;
729 Status
= STATUS_SUCCESS
;
730 switch (KeyInformationClass
)
732 case KeyBasicInformation
:
733 /* Check size of buffer */
734 if (SubKeyObject
!= NULL
)
736 NameSize
= SubKeyObject
->Name
.Length
;
740 NameSize
= SubKeyCell
->NameSize
;
741 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
743 NameSize
*= sizeof(WCHAR
);
747 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) + NameSize
;
750 * NOTE: It's perfetly valid to call NtEnumerateKey to get
751 * all the information but name. Actually the NT4 sound
752 * framework does that while querying parameters from registry.
753 * -- Filip Navara, 19/07/2004
755 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
757 Status
= STATUS_BUFFER_TOO_SMALL
;
761 /* Fill buffer with requested info */
762 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
763 BasicInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
764 BasicInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
765 BasicInformation
->TitleIndex
= Index
;
766 BasicInformation
->NameLength
= NameSize
;
768 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) < NameSize
)
770 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
771 Status
= STATUS_BUFFER_OVERFLOW
;
775 if (SubKeyObject
!= NULL
)
777 RtlCopyMemory(BasicInformation
->Name
,
778 SubKeyObject
->Name
.Buffer
,
783 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
785 CmiCopyPackedName(BasicInformation
->Name
,
787 NameSize
/ sizeof(WCHAR
));
791 RtlCopyMemory(BasicInformation
->Name
,
799 case KeyNodeInformation
:
800 /* Check size of buffer */
801 if (SubKeyObject
!= NULL
)
803 NameSize
= SubKeyObject
->Name
.Length
;
807 NameSize
= SubKeyCell
->NameSize
;
808 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
810 NameSize
*= sizeof(WCHAR
);
813 ClassSize
= SubKeyCell
->ClassSize
;
815 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
816 NameSize
+ ClassSize
;
818 if (Length
< FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]))
820 Status
= STATUS_BUFFER_TOO_SMALL
;
824 /* Fill buffer with requested info */
825 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
826 NodeInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
827 NodeInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
828 NodeInformation
->TitleIndex
= Index
;
829 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) + NameSize
;
830 NodeInformation
->ClassLength
= SubKeyCell
->ClassSize
;
831 NodeInformation
->NameLength
= NameSize
;
833 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
835 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
837 Status
= STATUS_BUFFER_OVERFLOW
;
840 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
841 NameSize
< ClassSize
)
843 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
845 Status
= STATUS_BUFFER_OVERFLOW
;
849 if (SubKeyObject
!= NULL
)
851 RtlCopyMemory(NodeInformation
->Name
,
852 SubKeyObject
->Name
.Buffer
,
857 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
859 CmiCopyPackedName(NodeInformation
->Name
,
861 NameSize
/ sizeof(WCHAR
));
865 RtlCopyMemory(NodeInformation
->Name
,
873 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
874 SubKeyCell
->ClassNameOffset
,
876 RtlCopyMemory (NodeInformation
->Name
+ SubKeyCell
->NameSize
,
883 case KeyFullInformation
:
884 ClassSize
= SubKeyCell
->ClassSize
;
886 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) +
889 /* Check size of buffer */
890 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]))
892 Status
= STATUS_BUFFER_TOO_SMALL
;
896 /* Fill buffer with requested info */
897 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
898 FullInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
899 FullInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
900 FullInformation
->TitleIndex
= Index
;
901 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) -
903 FullInformation
->ClassLength
= SubKeyCell
->ClassSize
;
904 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //SubKeyCell->NumberOfSubKeys;
905 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
906 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
907 FullInformation
->Values
= SubKeyCell
->NumberOfValues
;
908 FullInformation
->MaxValueNameLen
=
909 CmiGetMaxValueNameLength(RegistryHive
, SubKeyCell
);
910 FullInformation
->MaxValueDataLen
=
911 CmiGetMaxValueDataLength(RegistryHive
, SubKeyCell
);
913 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
915 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
916 Status
= STATUS_BUFFER_OVERFLOW
;
922 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
923 SubKeyCell
->ClassNameOffset
,
925 RtlCopyMemory (FullInformation
->Class
,
933 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
937 ExReleaseResourceLite(&CmiRegistryLock
);
938 KeLeaveCriticalRegion();
940 PostOperationInfo
.Status
= Status
;
941 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
943 ObDereferenceObject(KeyObject
);
945 DPRINT("Returning status %x\n", Status
);
952 NtEnumerateValueKey(IN HANDLE KeyHandle
,
954 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
955 OUT PVOID KeyValueInformation
,
957 OUT PULONG ResultLength
)
960 PKEY_OBJECT KeyObject
;
961 PREGISTRY_HIVE RegistryHive
;
963 PVALUE_CELL ValueCell
;
965 ULONG NameSize
, DataSize
;
966 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
967 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
968 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
972 DPRINT("KH 0x%p I %d KVIC %x KVI 0x%p L %d RL 0x%p\n",
975 KeyValueInformationClass
,
980 /* Verify that the handle is valid and is a registry key */
981 Status
= ObReferenceObjectByHandle(KeyHandle
,
985 (PVOID
*) &KeyObject
,
988 if (!NT_SUCCESS(Status
))
993 /* Acquire hive lock */
994 KeEnterCriticalRegion();
995 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
997 VERIFY_KEY_OBJECT(KeyObject
);
999 /* Get pointer to KeyCell */
1000 KeyCell
= KeyObject
->KeyCell
;
1001 RegistryHive
= KeyObject
->RegistryHive
;
1003 /* Get Value block of interest */
1004 Status
= CmiGetValueFromKeyByIndex(RegistryHive
,
1009 if (!NT_SUCCESS(Status
))
1011 ExReleaseResourceLite(&CmiRegistryLock
);
1012 KeLeaveCriticalRegion();
1013 ObDereferenceObject(KeyObject
);
1017 if (ValueCell
!= NULL
)
1019 switch (KeyValueInformationClass
)
1021 case KeyValueBasicInformation
:
1022 NameSize
= ValueCell
->NameSize
;
1023 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1025 NameSize
*= sizeof(WCHAR
);
1028 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) + NameSize
;
1030 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1032 Status
= STATUS_BUFFER_TOO_SMALL
;
1036 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1037 KeyValueInformation
;
1038 ValueBasicInformation
->TitleIndex
= 0;
1039 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1040 ValueBasicInformation
->NameLength
= NameSize
;
1042 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1045 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1046 Status
= STATUS_BUFFER_OVERFLOW
;
1050 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1052 CmiCopyPackedName(ValueBasicInformation
->Name
,
1054 NameSize
/ sizeof(WCHAR
));
1058 RtlCopyMemory(ValueBasicInformation
->Name
,
1065 case KeyValuePartialInformation
:
1066 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1068 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1071 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1073 Status
= STATUS_BUFFER_TOO_SMALL
;
1077 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1078 KeyValueInformation
;
1079 ValuePartialInformation
->TitleIndex
= 0;
1080 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1081 ValuePartialInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1083 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1086 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1087 Status
= STATUS_BUFFER_OVERFLOW
;
1091 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1093 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1094 RtlCopyMemory(ValuePartialInformation
->Data
,
1100 RtlCopyMemory(ValuePartialInformation
->Data
,
1101 &ValueCell
->DataOffset
,
1107 case KeyValueFullInformation
:
1108 NameSize
= ValueCell
->NameSize
;
1109 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1111 NameSize
*= sizeof(WCHAR
);
1113 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1115 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1116 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1118 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1120 Status
= STATUS_BUFFER_TOO_SMALL
;
1124 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1125 KeyValueInformation
;
1126 ValueFullInformation
->TitleIndex
= 0;
1127 ValueFullInformation
->Type
= ValueCell
->DataType
;
1128 ValueFullInformation
->NameLength
= NameSize
;
1129 ValueFullInformation
->DataOffset
=
1130 (ULONG_PTR
)ValueFullInformation
->Name
-
1131 (ULONG_PTR
)ValueFullInformation
+
1132 ValueFullInformation
->NameLength
;
1133 ValueFullInformation
->DataOffset
=
1134 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1135 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1137 if (Length
< ValueFullInformation
->DataOffset
)
1139 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1141 Status
= STATUS_BUFFER_OVERFLOW
;
1144 else if (Length
- ValueFullInformation
->DataOffset
< DataSize
)
1146 DataSize
= Length
- ValueFullInformation
->DataOffset
;
1147 Status
= STATUS_BUFFER_OVERFLOW
;
1151 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1153 CmiCopyPackedName(ValueFullInformation
->Name
,
1155 NameSize
/ sizeof(WCHAR
));
1159 RtlCopyMemory(ValueFullInformation
->Name
,
1164 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1166 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1167 RtlCopyMemory((PCHAR
) ValueFullInformation
1168 + ValueFullInformation
->DataOffset
,
1169 DataCell
->Data
, DataSize
);
1173 RtlCopyMemory((PCHAR
) ValueFullInformation
1174 + ValueFullInformation
->DataOffset
,
1175 &ValueCell
->DataOffset
, DataSize
);
1181 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1187 Status
= STATUS_UNSUCCESSFUL
;
1190 ExReleaseResourceLite(&CmiRegistryLock
);
1191 KeLeaveCriticalRegion();
1192 ObDereferenceObject(KeyObject
);
1199 NtFlushKey(IN HANDLE KeyHandle
)
1202 PKEY_OBJECT KeyObject
;
1203 PREGISTRY_HIVE RegistryHive
;
1204 KPROCESSOR_MODE PreviousMode
;
1208 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle
);
1210 PreviousMode
= ExGetPreviousMode();
1212 /* Verify that the handle is valid and is a registry key */
1213 Status
= ObReferenceObjectByHandle(KeyHandle
,
1217 (PVOID
*)&KeyObject
,
1219 if (!NT_SUCCESS(Status
))
1224 VERIFY_KEY_OBJECT(KeyObject
);
1226 RegistryHive
= KeyObject
->RegistryHive
;
1228 /* Acquire hive lock */
1229 KeEnterCriticalRegion();
1230 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1232 if (IsNoFileHive(RegistryHive
))
1234 Status
= STATUS_SUCCESS
;
1238 /* Flush non-volatile hive */
1239 Status
= CmiFlushRegistryHive(RegistryHive
);
1242 ExReleaseResourceLite(&CmiRegistryLock
);
1243 KeLeaveCriticalRegion();
1245 ObDereferenceObject(KeyObject
);
1247 return STATUS_SUCCESS
;
1252 NtOpenKey(OUT PHANDLE KeyHandle
,
1253 IN ACCESS_MASK DesiredAccess
,
1254 IN POBJECT_ATTRIBUTES ObjectAttributes
)
1256 UNICODE_STRING RemainingPath
;
1257 KPROCESSOR_MODE PreviousMode
;
1258 PVOID Object
= NULL
;
1260 NTSTATUS Status
= STATUS_SUCCESS
;
1261 UNICODE_STRING ObjectName
;
1262 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
1263 REG_PRE_OPEN_KEY_INFORMATION PreOpenKeyInfo
;
1264 REG_POST_OPEN_KEY_INFORMATION PostOpenKeyInfo
;
1268 DPRINT("NtOpenKey(KH 0x%p DA %x OA 0x%p OA->ON '%wZ'\n",
1272 ObjectAttributes
? ObjectAttributes
->ObjectName
: NULL
);
1274 /* Check place for result handle, if it's null - return immediately */
1275 if (KeyHandle
== NULL
)
1276 return(STATUS_INVALID_PARAMETER
);
1278 PreviousMode
= ExGetPreviousMode();
1280 if(PreviousMode
!= KernelMode
)
1284 ProbeForWriteHandle(KeyHandle
);
1288 Status
= _SEH_GetExceptionCode();
1292 if(!NT_SUCCESS(Status
))
1298 /* WINE checks for the length also */
1299 /*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
1300 return(STATUS_BUFFER_OVERFLOW);*/
1302 /* Capture all the info */
1303 DPRINT("Capturing Create Info\n");
1304 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
1309 if (!NT_SUCCESS(Status
))
1311 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
1315 PostOpenKeyInfo
.CompleteName
= &ObjectName
;
1316 PreOpenKeyInfo
.CompleteName
= &ObjectName
;
1317 Status
= CmiCallRegisteredCallbacks(RegNtPreOpenKey
, &PreOpenKeyInfo
);
1318 if (!NT_SUCCESS(Status
))
1320 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
1321 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
1326 RemainingPath
.Buffer
= NULL
;
1328 Status
= ObFindObject(&ObjectCreateInfo
,
1333 if (!NT_SUCCESS(Status
))
1335 DPRINT("CmpFindObject() returned 0x%08lx\n", Status
);
1336 Status
= STATUS_INVALID_HANDLE
; /* Because ObFindObject returns STATUS_UNSUCCESSFUL */
1337 goto openkey_cleanup
;
1340 VERIFY_KEY_OBJECT((PKEY_OBJECT
) Object
);
1342 DPRINT("RemainingPath '%wZ'\n", &RemainingPath
);
1344 if ((RemainingPath
.Buffer
!= NULL
) && (RemainingPath
.Buffer
[0] != 0))
1346 RtlFreeUnicodeString(&RemainingPath
);
1347 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1348 goto openkey_cleanup
;
1351 RtlFreeUnicodeString(&RemainingPath
);
1353 /* Fail if the key has been deleted */
1354 if (((PKEY_OBJECT
)Object
)->Flags
& KO_MARKED_FOR_DELETE
)
1356 Status
= STATUS_UNSUCCESSFUL
;
1357 goto openkey_cleanup
;
1360 Status
= ObpCreateHandle(Object
,
1362 ObjectCreateInfo
.Attributes
,
1367 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
1368 PostOpenKeyInfo
.Object
= NT_SUCCESS(Status
) ? (PVOID
)Object
: NULL
;
1369 PostOpenKeyInfo
.Status
= Status
;
1370 CmiCallRegisteredCallbacks (RegNtPostOpenKey
, &PostOpenKeyInfo
);
1371 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
1375 ObDereferenceObject(Object
);
1378 if (NT_SUCCESS(Status
))
1386 Status
= _SEH_GetExceptionCode();
1396 NtQueryKey(IN HANDLE KeyHandle
,
1397 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1398 OUT PVOID KeyInformation
,
1400 OUT PULONG ResultLength
)
1402 PKEY_BASIC_INFORMATION BasicInformation
;
1403 PKEY_NODE_INFORMATION NodeInformation
;
1404 PKEY_FULL_INFORMATION FullInformation
;
1405 PREGISTRY_HIVE RegistryHive
;
1406 PDATA_CELL ClassCell
;
1407 PKEY_OBJECT KeyObject
;
1409 ULONG NameSize
, ClassSize
;
1411 REG_QUERY_KEY_INFORMATION QueryKeyInfo
;
1412 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1416 DPRINT("NtQueryKey(KH 0x%p KIC %x KI 0x%p L %d RL 0x%p)\n",
1418 KeyInformationClass
,
1423 /* Verify that the handle is valid and is a registry key */
1424 Status
= ObReferenceObjectByHandle(KeyHandle
,
1425 (KeyInformationClass
!= KeyNameInformation
? KEY_QUERY_VALUE
: 0),
1427 ExGetPreviousMode(),
1428 (PVOID
*) &KeyObject
,
1430 if (!NT_SUCCESS(Status
))
1435 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1436 QueryKeyInfo
.Object
= (PVOID
)KeyObject
;
1437 QueryKeyInfo
.KeyInformationClass
= KeyInformationClass
;
1438 QueryKeyInfo
.KeyInformation
= KeyInformation
;
1439 QueryKeyInfo
.Length
= Length
;
1440 QueryKeyInfo
.ResultLength
= ResultLength
;
1442 Status
= CmiCallRegisteredCallbacks(RegNtQueryKey
, &QueryKeyInfo
);
1443 if (!NT_SUCCESS(Status
))
1445 ObDereferenceObject(KeyObject
);
1449 /* Acquire hive lock */
1450 KeEnterCriticalRegion();
1451 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1453 VERIFY_KEY_OBJECT(KeyObject
);
1455 /* Get pointer to KeyCell */
1456 KeyCell
= KeyObject
->KeyCell
;
1457 RegistryHive
= KeyObject
->RegistryHive
;
1459 Status
= STATUS_SUCCESS
;
1460 switch (KeyInformationClass
)
1462 case KeyBasicInformation
:
1463 NameSize
= KeyObject
->Name
.Length
;
1465 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1467 /* Check size of buffer */
1468 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
1470 Status
= STATUS_BUFFER_TOO_SMALL
;
1474 /* Fill buffer with requested info */
1475 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
1476 BasicInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1477 BasicInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1478 BasicInformation
->TitleIndex
= 0;
1479 BasicInformation
->NameLength
= KeyObject
->Name
.Length
;
1481 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) <
1484 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1485 Status
= STATUS_BUFFER_OVERFLOW
;
1489 RtlCopyMemory(BasicInformation
->Name
,
1490 KeyObject
->Name
.Buffer
,
1495 case KeyNodeInformation
:
1496 NameSize
= KeyObject
->Name
.Length
;
1497 ClassSize
= KeyCell
->ClassSize
;
1499 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
1500 NameSize
+ ClassSize
;
1502 /* Check size of buffer */
1503 if (Length
< *ResultLength
)
1505 Status
= STATUS_BUFFER_TOO_SMALL
;
1509 /* Fill buffer with requested info */
1510 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
1511 NodeInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1512 NodeInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1513 NodeInformation
->TitleIndex
= 0;
1514 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
1515 KeyObject
->Name
.Length
;
1516 NodeInformation
->ClassLength
= KeyCell
->ClassSize
;
1517 NodeInformation
->NameLength
= KeyObject
->Name
.Length
;
1519 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
1521 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
1523 Status
= STATUS_BUFFER_OVERFLOW
;
1526 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1527 NameSize
< ClassSize
)
1529 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1531 Status
= STATUS_BUFFER_OVERFLOW
;
1535 RtlCopyMemory(NodeInformation
->Name
,
1536 KeyObject
->Name
.Buffer
,
1541 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1542 KeyCell
->ClassNameOffset
,
1544 RtlCopyMemory (NodeInformation
->Name
+ KeyObject
->Name
.Length
,
1551 case KeyFullInformation
:
1552 ClassSize
= KeyCell
->ClassSize
;
1554 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
1557 /* Check size of buffer */
1558 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
))
1560 Status
= STATUS_BUFFER_TOO_SMALL
;
1564 /* Fill buffer with requested info */
1565 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
1566 FullInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1567 FullInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1568 FullInformation
->TitleIndex
= 0;
1569 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) - sizeof(WCHAR
);
1570 FullInformation
->ClassLength
= KeyCell
->ClassSize
;
1571 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //KeyCell->NumberOfSubKeys;
1572 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
1573 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
1574 FullInformation
->Values
= KeyCell
->NumberOfValues
;
1575 FullInformation
->MaxValueNameLen
=
1576 CmiGetMaxValueNameLength(RegistryHive
, KeyCell
);
1577 FullInformation
->MaxValueDataLen
=
1578 CmiGetMaxValueDataLength(RegistryHive
, KeyCell
);
1580 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
1582 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
1583 Status
= STATUS_BUFFER_OVERFLOW
;
1589 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1590 KeyCell
->ClassNameOffset
,
1592 RtlCopyMemory (FullInformation
->Class
,
1593 ClassCell
->Data
, ClassSize
);
1598 case KeyNameInformation
:
1599 case KeyCachedInformation
:
1600 case KeyFlagsInformation
:
1601 DPRINT1("Key information class 0x%x not yet implemented!\n", KeyInformationClass
);
1602 Status
= STATUS_NOT_IMPLEMENTED
;
1606 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
1607 Status
= STATUS_INVALID_INFO_CLASS
;
1611 ExReleaseResourceLite(&CmiRegistryLock
);
1612 KeLeaveCriticalRegion();
1614 PostOperationInfo
.Status
= Status
;
1615 CmiCallRegisteredCallbacks(RegNtPostQueryKey
, &PostOperationInfo
);
1617 ObDereferenceObject(KeyObject
);
1624 NtQueryValueKey(IN HANDLE KeyHandle
,
1625 IN PUNICODE_STRING ValueName
,
1626 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1627 OUT PVOID KeyValueInformation
,
1629 OUT PULONG ResultLength
)
1632 ULONG NameSize
, DataSize
;
1633 PKEY_OBJECT KeyObject
;
1634 PREGISTRY_HIVE RegistryHive
;
1636 PVALUE_CELL ValueCell
;
1637 PDATA_CELL DataCell
;
1638 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
1639 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
1640 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
1641 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo
;
1642 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1646 DPRINT("NtQueryValueKey(KeyHandle 0x%p ValueName %S Length %x)\n",
1647 KeyHandle
, ValueName
->Buffer
, Length
);
1649 /* Verify that the handle is valid and is a registry key */
1650 Status
= ObReferenceObjectByHandle(KeyHandle
,
1653 ExGetPreviousMode(),
1654 (PVOID
*)&KeyObject
,
1657 if (!NT_SUCCESS(Status
))
1659 DPRINT1("ObReferenceObjectByHandle() failed with status %x %p\n", Status
, KeyHandle
);
1663 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1664 QueryValueKeyInfo
.Object
= (PVOID
)KeyObject
;
1665 QueryValueKeyInfo
.ValueName
= ValueName
;
1666 QueryValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
1667 QueryValueKeyInfo
.Length
= Length
;
1668 QueryValueKeyInfo
.ResultLength
= ResultLength
;
1670 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
1671 if (!NT_SUCCESS(Status
))
1673 ObDereferenceObject(KeyObject
);
1677 /* Acquire hive lock */
1678 KeEnterCriticalRegion();
1679 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1681 VERIFY_KEY_OBJECT(KeyObject
);
1683 /* Get pointer to KeyCell */
1684 KeyCell
= KeyObject
->KeyCell
;
1685 RegistryHive
= KeyObject
->RegistryHive
;
1687 /* Get value cell by name */
1688 Status
= CmiScanKeyForValue(RegistryHive
,
1693 if (!NT_SUCCESS(Status
))
1695 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
1699 Status
= STATUS_SUCCESS
;
1700 switch (KeyValueInformationClass
)
1702 case KeyValueBasicInformation
:
1703 NameSize
= ValueCell
->NameSize
;
1704 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1706 NameSize
*= sizeof(WCHAR
);
1709 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) +
1712 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1714 Status
= STATUS_BUFFER_TOO_SMALL
;
1718 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1719 KeyValueInformation
;
1720 ValueBasicInformation
->TitleIndex
= 0;
1721 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1722 ValueBasicInformation
->NameLength
= NameSize
;
1724 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1727 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1728 Status
= STATUS_BUFFER_OVERFLOW
;
1732 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1734 CmiCopyPackedName(ValueBasicInformation
->Name
,
1736 NameSize
/ sizeof(WCHAR
));
1740 RtlCopyMemory(ValueBasicInformation
->Name
,
1747 case KeyValuePartialInformation
:
1748 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1750 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1753 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1755 Status
= STATUS_BUFFER_TOO_SMALL
;
1759 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1760 KeyValueInformation
;
1761 ValuePartialInformation
->TitleIndex
= 0;
1762 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1763 ValuePartialInformation
->DataLength
= DataSize
;
1765 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1768 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1769 Status
= STATUS_BUFFER_OVERFLOW
;
1773 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1775 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1776 RtlCopyMemory(ValuePartialInformation
->Data
,
1782 RtlCopyMemory(ValuePartialInformation
->Data
,
1783 &ValueCell
->DataOffset
,
1789 case KeyValueFullInformation
:
1790 NameSize
= ValueCell
->NameSize
;
1791 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1793 NameSize
*= sizeof(WCHAR
);
1795 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1797 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1798 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1800 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1802 Status
= STATUS_BUFFER_TOO_SMALL
;
1806 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1807 KeyValueInformation
;
1808 ValueFullInformation
->TitleIndex
= 0;
1809 ValueFullInformation
->Type
= ValueCell
->DataType
;
1810 ValueFullInformation
->NameLength
= NameSize
;
1811 ValueFullInformation
->DataOffset
=
1812 (ULONG_PTR
)ValueFullInformation
->Name
-
1813 (ULONG_PTR
)ValueFullInformation
+
1814 ValueFullInformation
->NameLength
;
1815 ValueFullInformation
->DataOffset
=
1816 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1817 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1819 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1822 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1824 Status
= STATUS_BUFFER_OVERFLOW
;
1827 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1828 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1830 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1831 Name
[0]) - NameSize
, sizeof(PVOID
));
1832 Status
= STATUS_BUFFER_OVERFLOW
;
1836 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1838 CmiCopyPackedName(ValueFullInformation
->Name
,
1840 NameSize
/ sizeof(WCHAR
));
1844 RtlCopyMemory(ValueFullInformation
->Name
,
1848 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1850 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1851 RtlCopyMemory((PCHAR
) ValueFullInformation
1852 + ValueFullInformation
->DataOffset
,
1858 RtlCopyMemory((PCHAR
) ValueFullInformation
1859 + ValueFullInformation
->DataOffset
,
1860 &ValueCell
->DataOffset
,
1867 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1868 Status
= STATUS_INVALID_INFO_CLASS
;
1873 ExReleaseResourceLite(&CmiRegistryLock
);
1874 KeLeaveCriticalRegion();
1876 PostOperationInfo
.Status
= Status
;
1877 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
1878 ObDereferenceObject(KeyObject
);
1885 NtSetValueKey(IN HANDLE KeyHandle
,
1886 IN PUNICODE_STRING ValueName
,
1887 IN ULONG TitleIndex
,
1893 PKEY_OBJECT KeyObject
;
1894 PREGISTRY_HIVE RegistryHive
;
1896 PVALUE_CELL ValueCell
;
1897 BLOCK_OFFSET ValueCellOffset
;
1898 PDATA_CELL DataCell
;
1899 PDATA_CELL NewDataCell
;
1900 ULONG DesiredAccess
;
1901 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo
;
1902 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1907 DPRINT("NtSetValueKey(KeyHandle 0x%p ValueName '%wZ' Type %d)\n",
1908 KeyHandle
, ValueName
, Type
);
1910 DesiredAccess
= KEY_SET_VALUE
;
1912 /* Verify that the handle is valid and is a registry key */
1913 Status
= ObReferenceObjectByHandle(KeyHandle
,
1916 ExGetPreviousMode(),
1917 (PVOID
*)&KeyObject
,
1919 if (!NT_SUCCESS(Status
))
1922 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1923 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
1924 SetValueKeyInfo
.ValueName
= ValueName
;
1925 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
1926 SetValueKeyInfo
.Type
= Type
;
1927 SetValueKeyInfo
.Data
= Data
;
1928 SetValueKeyInfo
.DataSize
= DataSize
;
1929 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
1930 if (!NT_SUCCESS(Status
))
1932 ObDereferenceObject(KeyObject
);
1936 /* Acquire hive lock exclucively */
1937 KeEnterCriticalRegion();
1938 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1940 VERIFY_KEY_OBJECT(KeyObject
);
1942 /* Get pointer to key cell */
1943 KeyCell
= KeyObject
->KeyCell
;
1944 RegistryHive
= KeyObject
->RegistryHive
;
1945 Status
= CmiScanKeyForValue(RegistryHive
,
1950 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1952 DPRINT("Allocate new value cell\n");
1953 Status
= CmiAddValueToKey(RegistryHive
,
1955 KeyObject
->KeyCellOffset
,
1961 if (!NT_SUCCESS(Status
))
1963 DPRINT("Cannot add value. Status 0x%X\n", Status
);
1965 ExReleaseResourceLite(&CmiRegistryLock
);
1966 KeLeaveCriticalRegion();
1967 PostOperationInfo
.Status
= Status
;
1968 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
1969 ObDereferenceObject(KeyObject
);
1973 DPRINT("DataSize %lu\n", DataSize
);
1974 DPRINT("ValueCell %p\n", ValueCell
);
1975 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1977 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1978 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1980 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1981 DataCellSize
= (DataCell
->CellSize
< 0 ? -DataCell
->CellSize
: DataCell
->CellSize
) - sizeof(CELL_HEADER
);
1990 if (DataSize
<= sizeof(BLOCK_OFFSET
))
1992 /* If data size <= sizeof(BLOCK_OFFSET) then store data in the data offset */
1993 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1996 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
1999 RtlCopyMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
2000 ValueCell
->DataSize
= DataSize
| REG_DATA_IN_OFFSET
;
2001 ValueCell
->DataType
= Type
;
2002 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
2006 if (DataSize
> DataCellSize
)
2009 * New data size is larger than the current, destroy current
2010 * data block and allocate a new one.
2012 BLOCK_OFFSET NewOffset
;
2014 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
2016 Status
= CmiAllocateCell (RegistryHive
,
2017 sizeof(CELL_HEADER
) + DataSize
,
2018 (PVOID
*)&NewDataCell
,
2020 if (!NT_SUCCESS(Status
))
2022 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status
);
2024 ExReleaseResourceLite(&CmiRegistryLock
);
2025 KeLeaveCriticalRegion();
2026 PostOperationInfo
.Status
= Status
;
2027 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
2028 ObDereferenceObject(KeyObject
);
2035 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
2038 ValueCell
->DataOffset
= NewOffset
;
2039 DataCell
= NewDataCell
;
2042 RtlCopyMemory(DataCell
->Data
, Data
, DataSize
);
2043 ValueCell
->DataSize
= DataSize
& REG_DATA_SIZE_MASK
;
2044 ValueCell
->DataType
= Type
;
2045 CmiMarkBlockDirty(RegistryHive
, ValueCell
->DataOffset
);
2046 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
2050 if ((Type
== REG_LINK
) &&
2051 (_wcsicmp(ValueName
->Buffer
, L
"SymbolicLinkValue") == 0))
2053 KeyCell
->Flags
|= REG_KEY_LINK_CELL
;
2056 KeQuerySystemTime (&KeyCell
->LastWriteTime
);
2057 CmiMarkBlockDirty (RegistryHive
, KeyObject
->KeyCellOffset
);
2059 ExReleaseResourceLite(&CmiRegistryLock
);
2060 KeLeaveCriticalRegion();
2061 PostOperationInfo
.Status
= Status
;
2062 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
2063 ObDereferenceObject(KeyObject
);
2067 DPRINT("Return Status 0x%X\n", Status
);
2074 NtDeleteValueKey (IN HANDLE KeyHandle
,
2075 IN PUNICODE_STRING ValueName
)
2077 PKEY_OBJECT KeyObject
;
2079 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
2080 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2081 KPROCESSOR_MODE PreviousMode
;
2082 UNICODE_STRING CapturedValueName
;
2086 PreviousMode
= ExGetPreviousMode();
2088 /* Verify that the handle is valid and is a registry key */
2089 Status
= ObReferenceObjectByHandle(KeyHandle
,
2093 (PVOID
*)&KeyObject
,
2095 if (!NT_SUCCESS(Status
))
2100 Status
= ProbeAndCaptureUnicodeString(&CapturedValueName
,
2103 if (!NT_SUCCESS(Status
))
2107 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
2108 DeleteValueKeyInfo
.ValueName
= &CapturedValueName
;
2110 /* FIXME - check if value exists before calling the callbacks? */
2111 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
, &DeleteValueKeyInfo
);
2112 if (!NT_SUCCESS(Status
))
2114 ReleaseCapturedUnicodeString(&CapturedValueName
,
2117 ObDereferenceObject(KeyObject
);
2121 /* Acquire hive lock */
2122 KeEnterCriticalRegion();
2123 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2125 VERIFY_KEY_OBJECT(KeyObject
);
2127 Status
= CmiDeleteValueFromKey(KeyObject
->RegistryHive
,
2129 KeyObject
->KeyCellOffset
,
2132 KeQuerySystemTime (&KeyObject
->KeyCell
->LastWriteTime
);
2133 CmiMarkBlockDirty (KeyObject
->RegistryHive
, KeyObject
->KeyCellOffset
);
2135 /* Release hive lock */
2136 ExReleaseResourceLite(&CmiRegistryLock
);
2137 KeLeaveCriticalRegion();
2139 ReleaseCapturedUnicodeString(&CapturedValueName
,
2142 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2143 PostOperationInfo
.Status
= Status
;
2145 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
, &PostOperationInfo
);
2147 ObDereferenceObject (KeyObject
);
2157 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2158 * KeyObjectAttributes->Name specifies the name of the key to load.
2161 NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
2162 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
2164 return NtLoadKey2 (KeyObjectAttributes
,
2165 FileObjectAttributes
,
2172 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2173 * KeyObjectAttributes->Name specifies the name of the key to load.
2174 * Flags can be 0 or REG_NO_LAZY_FLUSH.
2177 NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
2178 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
2181 POBJECT_NAME_INFORMATION NameInfo
;
2182 PUNICODE_STRING NamePointer
;
2190 DPRINT ("NtLoadKey2() called\n");
2193 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, ExGetPreviousMode ()))
2194 return STATUS_PRIVILEGE_NOT_HELD
;
2197 if (FileObjectAttributes
->RootDirectory
!= NULL
)
2200 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2201 Buffer
= ExAllocatePool (NonPagedPool
,
2204 return STATUS_INSUFFICIENT_RESOURCES
;
2206 Status
= ZwQueryObject (FileObjectAttributes
->RootDirectory
,
2207 ObjectNameInformation
,
2211 if (!NT_SUCCESS(Status
))
2213 DPRINT1 ("NtQueryObject() failed (Status %lx)\n", Status
);
2214 ExFreePool (Buffer
);
2218 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2219 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2220 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2222 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2223 if (FileObjectAttributes
->ObjectName
->Buffer
[0] != L
'\\')
2225 RtlAppendUnicodeToString (&NameInfo
->Name
,
2227 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2228 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2230 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2231 FileObjectAttributes
->ObjectName
);
2233 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2234 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2235 NamePointer
= &NameInfo
->Name
;
2239 if (FileObjectAttributes
->ObjectName
->Buffer
[0] == L
'\\')
2242 NamePointer
= FileObjectAttributes
->ObjectName
;
2247 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2248 Buffer
= ExAllocatePool (NonPagedPool
,
2251 return STATUS_INSUFFICIENT_RESOURCES
;
2253 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2254 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2255 NameInfo
->Name
.Length
= 0;
2256 NameInfo
->Name
.Buffer
= (PWSTR
)((ULONG_PTR
)Buffer
+ sizeof(OBJECT_NAME_INFORMATION
));
2257 NameInfo
->Name
.Buffer
[0] = 0;
2259 RtlAppendUnicodeToString (&NameInfo
->Name
,
2261 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2262 FileObjectAttributes
->ObjectName
);
2264 NamePointer
= &NameInfo
->Name
;
2268 DPRINT ("Full name: '%wZ'\n", NamePointer
);
2270 /* Acquire hive lock */
2271 KeEnterCriticalRegion();
2272 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2274 Status
= CmiLoadHive (KeyObjectAttributes
,
2277 if (!NT_SUCCESS (Status
))
2279 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
2282 /* Release hive lock */
2283 ExReleaseResourceLite(&CmiRegistryLock
);
2284 KeLeaveCriticalRegion();
2287 ExFreePool (Buffer
);
2294 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2296 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2297 IN PVOID ApcContext OPTIONAL
,
2298 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2299 IN ULONG CompletionFilter
,
2300 IN BOOLEAN WatchSubtree
,
2303 IN BOOLEAN Asynchronous
)
2306 return(STATUS_NOT_IMPLEMENTED
);
2311 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2313 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2314 IN PVOID ApcContext OPTIONAL
,
2315 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2316 IN ULONG CompletionFilter
,
2317 IN BOOLEAN WatchSubtree
,
2320 IN BOOLEAN Asynchronous
)
2322 return NtNotifyChangeMultipleKeys(KeyHandle
,
2339 NtQueryMultipleValueKey (IN HANDLE KeyHandle
,
2340 IN OUT PKEY_VALUE_ENTRY ValueList
,
2341 IN ULONG NumberOfValues
,
2343 IN OUT PULONG Length
,
2344 OUT PULONG ReturnLength
)
2346 PREGISTRY_HIVE RegistryHive
;
2347 PVALUE_CELL ValueCell
;
2348 PKEY_OBJECT KeyObject
;
2349 PDATA_CELL DataCell
;
2350 ULONG BufferLength
= 0;
2355 REG_QUERY_MULTIPLE_VALUE_KEY_INFORMATION QueryMultipleValueKeyInfo
;
2356 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2360 /* Verify that the handle is valid and is a registry key */
2361 Status
= ObReferenceObjectByHandle(KeyHandle
,
2364 ExGetPreviousMode(),
2365 (PVOID
*) &KeyObject
,
2367 if (!NT_SUCCESS(Status
))
2369 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2373 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2374 QueryMultipleValueKeyInfo
.Object
= (PVOID
)KeyObject
;
2375 QueryMultipleValueKeyInfo
.ValueEntries
= ValueList
;
2376 QueryMultipleValueKeyInfo
.EntryCount
= NumberOfValues
;
2377 QueryMultipleValueKeyInfo
.ValueBuffer
= Buffer
;
2378 QueryMultipleValueKeyInfo
.BufferLength
= Length
;
2379 QueryMultipleValueKeyInfo
.RequiredBufferLength
= ReturnLength
;
2381 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryMultipleValueKey
, &QueryMultipleValueKeyInfo
);
2382 if (!NT_SUCCESS(Status
))
2384 ObDereferenceObject(KeyObject
);
2388 /* Acquire hive lock */
2389 KeEnterCriticalRegion();
2390 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
2392 VERIFY_KEY_OBJECT(KeyObject
);
2394 /* Get pointer to KeyCell */
2395 KeyCell
= KeyObject
->KeyCell
;
2396 RegistryHive
= KeyObject
->RegistryHive
;
2398 DataPtr
= (PUCHAR
) Buffer
;
2400 for (i
= 0; i
< NumberOfValues
; i
++)
2402 DPRINT("ValueName: '%wZ'\n", ValueList
[i
].ValueName
);
2404 /* Get Value block of interest */
2405 Status
= CmiScanKeyForValue(RegistryHive
,
2407 ValueList
[i
].ValueName
,
2411 if (!NT_SUCCESS(Status
))
2413 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
2416 else if (ValueCell
== NULL
)
2418 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
2422 BufferLength
= ROUND_UP(BufferLength
, sizeof(PVOID
));
2424 if (BufferLength
+ (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) <= *Length
)
2426 DataPtr
= (PUCHAR
)ROUND_UP((ULONG_PTR
)DataPtr
, sizeof(PVOID
));
2428 ValueList
[i
].Type
= ValueCell
->DataType
;
2429 ValueList
[i
].DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2430 ValueList
[i
].DataOffset
= (ULONG_PTR
)DataPtr
- (ULONG_PTR
)Buffer
;
2432 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
2434 DataCell
= CmiGetCell (RegistryHive
,
2435 ValueCell
->DataOffset
,
2437 RtlCopyMemory(DataPtr
,
2439 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2443 RtlCopyMemory(DataPtr
,
2444 &ValueCell
->DataOffset
,
2445 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2448 DataPtr
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2452 Status
= STATUS_BUFFER_TOO_SMALL
;
2455 BufferLength
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2458 if (NT_SUCCESS(Status
))
2459 *Length
= BufferLength
;
2461 *ReturnLength
= BufferLength
;
2463 /* Release hive lock */
2464 ExReleaseResourceLite(&CmiRegistryLock
);
2465 KeLeaveCriticalRegion();
2467 PostOperationInfo
.Status
= Status
;
2468 CmiCallRegisteredCallbacks(RegNtPostQueryMultipleValueKey
, &PostOperationInfo
);
2470 ObDereferenceObject(KeyObject
);
2472 DPRINT("Return Status 0x%X\n", Status
);
2479 NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes
,
2481 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
2484 return(STATUS_NOT_IMPLEMENTED
);
2489 NtRestoreKey (IN HANDLE KeyHandle
,
2490 IN HANDLE FileHandle
,
2491 IN ULONG RestoreFlags
)
2494 return(STATUS_NOT_IMPLEMENTED
);
2499 NtSaveKey (IN HANDLE KeyHandle
,
2500 IN HANDLE FileHandle
)
2502 PREGISTRY_HIVE TempHive
;
2503 PKEY_OBJECT KeyObject
;
2508 DPRINT ("NtSaveKey() called\n");
2511 if (!SeSinglePrivilegeCheck (SeBackupPrivilege
, ExGetPreviousMode ()))
2512 return STATUS_PRIVILEGE_NOT_HELD
;
2515 Status
= ObReferenceObjectByHandle (KeyHandle
,
2518 ExGetPreviousMode(),
2519 (PVOID
*)&KeyObject
,
2521 if (!NT_SUCCESS(Status
))
2523 DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
2527 /* Acquire hive lock exclucively */
2528 KeEnterCriticalRegion();
2529 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2531 /* Refuse to save a volatile key */
2532 if (KeyObject
->RegistryHive
== CmiVolatileHive
)
2534 DPRINT1 ("Cannot save a volatile key\n");
2535 ExReleaseResourceLite(&CmiRegistryLock
);
2536 KeLeaveCriticalRegion();
2537 ObDereferenceObject (KeyObject
);
2538 return STATUS_ACCESS_DENIED
;
2541 Status
= CmiCreateTempHive(&TempHive
);
2542 if (!NT_SUCCESS(Status
))
2544 DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status
);
2545 ExReleaseResourceLite(&CmiRegistryLock
);
2546 KeLeaveCriticalRegion();
2547 ObDereferenceObject (KeyObject
);
2551 Status
= CmiCopyKey (TempHive
,
2553 KeyObject
->RegistryHive
,
2554 KeyObject
->KeyCell
);
2555 if (!NT_SUCCESS(Status
))
2557 DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status
);
2558 CmiRemoveRegistryHive (TempHive
);
2559 ExReleaseResourceLite(&CmiRegistryLock
);
2560 KeLeaveCriticalRegion();
2561 ObDereferenceObject (KeyObject
);
2565 Status
= CmiSaveTempHive (TempHive
,
2567 if (!NT_SUCCESS(Status
))
2569 DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status
);
2572 CmiRemoveRegistryHive (TempHive
);
2574 /* Release hive lock */
2575 ExReleaseResourceLite(&CmiRegistryLock
);
2576 KeLeaveCriticalRegion();
2578 ObDereferenceObject (KeyObject
);
2580 DPRINT ("NtSaveKey() done\n");
2582 return STATUS_SUCCESS
;
2591 IN HANDLE KeyHandle
,
2592 IN HANDLE FileHandle
,
2593 IN ULONG Flags
// REG_STANDARD_FORMAT, etc..
2597 return STATUS_NOT_IMPLEMENTED
;
2602 NtSetInformationKey (IN HANDLE KeyHandle
,
2603 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
2604 IN PVOID KeyInformation
,
2605 IN ULONG KeyInformationLength
)
2607 PKEY_OBJECT KeyObject
;
2609 REG_SET_INFORMATION_KEY_INFORMATION SetInformationKeyInfo
;
2610 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2614 /* Verify that the handle is valid and is a registry key */
2615 Status
= ObReferenceObjectByHandle (KeyHandle
,
2618 ExGetPreviousMode(),
2619 (PVOID
*)&KeyObject
,
2621 if (!NT_SUCCESS (Status
))
2623 DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2627 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2628 SetInformationKeyInfo
.Object
= (PVOID
)KeyObject
;
2629 SetInformationKeyInfo
.KeySetInformationClass
= KeyInformationClass
;
2630 SetInformationKeyInfo
.KeySetInformation
= KeyInformation
;
2631 SetInformationKeyInfo
.KeySetInformationLength
= KeyInformationLength
;
2633 Status
= CmiCallRegisteredCallbacks(RegNtSetInformationKey
, &SetInformationKeyInfo
);
2634 if (!NT_SUCCESS(Status
))
2636 ObDereferenceObject (KeyObject
);
2640 if (KeyInformationClass
!= KeyWriteTimeInformation
)
2642 Status
= STATUS_INVALID_INFO_CLASS
;
2645 else if (KeyInformationLength
!= sizeof (KEY_WRITE_TIME_INFORMATION
))
2647 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2651 /* Acquire hive lock */
2652 KeEnterCriticalRegion();
2653 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2655 VERIFY_KEY_OBJECT(KeyObject
);
2657 KeyObject
->KeyCell
->LastWriteTime
.QuadPart
=
2658 ((PKEY_WRITE_TIME_INFORMATION
)KeyInformation
)->LastWriteTime
.QuadPart
;
2660 CmiMarkBlockDirty (KeyObject
->RegistryHive
,
2661 KeyObject
->KeyCellOffset
);
2663 /* Release hive lock */
2664 ExReleaseResourceLite(&CmiRegistryLock
);
2665 KeLeaveCriticalRegion();
2668 PostOperationInfo
.Status
= Status
;
2669 CmiCallRegisteredCallbacks(RegNtPostSetInformationKey
, &PostOperationInfo
);
2671 ObDereferenceObject (KeyObject
);
2673 if (NT_SUCCESS(Status
))
2678 DPRINT ("NtSaveKey() done\n");
2680 return STATUS_SUCCESS
;
2686 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2687 * KeyObjectAttributes->Name specifies the name of the key to unload.
2690 NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
2692 PREGISTRY_HIVE RegistryHive
;
2697 DPRINT ("NtUnloadKey() called\n");
2700 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, ExGetPreviousMode ()))
2701 return STATUS_PRIVILEGE_NOT_HELD
;
2704 /* Acquire registry lock exclusively */
2705 KeEnterCriticalRegion();
2706 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2708 Status
= CmiDisconnectHive (KeyObjectAttributes
,
2710 if (!NT_SUCCESS (Status
))
2712 DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status
);
2713 ExReleaseResourceLite (&CmiRegistryLock
);
2714 KeLeaveCriticalRegion();
2718 DPRINT ("RegistryHive %p\n", RegistryHive
);
2722 if (!IsNoFileHive (RegistryHive
))
2723 CmiFlushRegistryHive (RegistryHive
);
2726 CmiRemoveRegistryHive (RegistryHive
);
2728 /* Release registry lock */
2729 ExReleaseResourceLite (&CmiRegistryLock
);
2730 KeLeaveCriticalRegion();
2732 DPRINT ("NtUnloadKey() done\n");
2734 return STATUS_SUCCESS
;
2739 NtInitializeRegistry (IN BOOLEAN SetUpBoot
)
2745 if (CmiRegistryInitialized
== TRUE
)
2746 return STATUS_ACCESS_DENIED
;
2748 /* Save boot log file */
2749 IopSaveBootLogToFile();
2751 Status
= CmiInitHives (SetUpBoot
);
2753 CmiRegistryInitialized
= TRUE
;