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
;
188 PKEY_OBJECT KeyObject
;
192 UNICODE_STRING ObjectName
;
193 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
195 REG_PRE_CREATE_KEY_INFORMATION PreCreateKeyInfo
;
196 REG_POST_CREATE_KEY_INFORMATION PostCreateKeyInfo
;
200 DPRINT("NtCreateKey (Name %wZ KeyHandle 0x%p Root 0x%p)\n",
201 ObjectAttributes
->ObjectName
,
203 ObjectAttributes
->RootDirectory
);
205 /* Capture all the info */
206 DPRINT("Capturing Create Info\n");
207 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
212 if (!NT_SUCCESS(Status
))
214 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
218 PostCreateKeyInfo
.CompleteName
= &ObjectName
;
219 PreCreateKeyInfo
.CompleteName
= &ObjectName
;
220 Status
= CmiCallRegisteredCallbacks(RegNtPreCreateKey
, &PreCreateKeyInfo
);
221 if (!NT_SUCCESS(Status
))
223 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
224 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
228 Status
= ObFindObject(&ObjectCreateInfo
,
233 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
234 if (!NT_SUCCESS(Status
))
236 PostCreateKeyInfo
.Object
= NULL
;
237 PostCreateKeyInfo
.Status
= Status
;
238 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
239 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
240 DPRINT("CmpFindObject failed, Status: 0x%x\n", Status
);
244 DPRINT("RemainingPath %wZ\n", &RemainingPath
);
246 if (RemainingPath
.Length
== 0)
248 /* Fail if the key has been deleted */
249 if (((PKEY_OBJECT
) Object
)->Flags
& KO_MARKED_FOR_DELETE
)
251 ObDereferenceObject(Object
);
252 RtlFreeUnicodeString(&RemainingPath
);
253 PostCreateKeyInfo
.Object
= NULL
;
254 PostCreateKeyInfo
.Status
= STATUS_UNSUCCESSFUL
;
255 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
256 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
257 DPRINT("Object marked for delete!\n");
258 return(STATUS_UNSUCCESSFUL
);
262 *Disposition
= REG_OPENED_EXISTING_KEY
;
264 Status
= ObpCreateHandle(PsGetCurrentProcess(),
270 DPRINT("ObpCreateHandle failed Status 0x%x\n", Status
);
271 ObDereferenceObject(Object
);
272 RtlFreeUnicodeString(&RemainingPath
);
273 PostCreateKeyInfo
.Object
= NULL
;
274 PostCreateKeyInfo
.Status
= Status
;
275 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
276 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
280 /* If RemainingPath contains \ we must return error
281 because NtCreateKey doesn't create trees */
282 Start
= RemainingPath
.Buffer
;
286 for (i
= 1; i
< RemainingPath
.Length
/ sizeof(WCHAR
); i
++)
288 if (L
'\\' == RemainingPath
.Buffer
[i
])
290 ObDereferenceObject(Object
);
291 DPRINT1("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath
);
292 RtlFreeUnicodeString(&RemainingPath
);
293 PostCreateKeyInfo
.Object
= NULL
;
294 PostCreateKeyInfo
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
295 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
296 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
297 return STATUS_OBJECT_NAME_NOT_FOUND
;
301 DPRINT("RemainingPath %S ParentObject 0x%p\n", RemainingPath
.Buffer
, Object
);
303 Status
= ObCreateObject(ExGetPreviousMode(),
312 if (!NT_SUCCESS(Status
))
314 DPRINT1("ObCreateObject() failed!\n");
315 PostCreateKeyInfo
.Object
= NULL
;
316 PostCreateKeyInfo
.Status
= Status
;
317 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
318 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
322 Status
= ObInsertObject((PVOID
)KeyObject
,
328 if (!NT_SUCCESS(Status
))
330 ObDereferenceObject(KeyObject
);
331 RtlFreeUnicodeString(&RemainingPath
);
332 DPRINT1("ObInsertObject() failed!\n");
333 PostCreateKeyInfo
.Object
= NULL
;
334 PostCreateKeyInfo
.Status
= Status
;
335 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
336 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
340 KeyObject
->ParentKey
= Object
;
342 if (CreateOptions
& REG_OPTION_VOLATILE
)
343 KeyObject
->RegistryHive
= CmiVolatileHive
;
345 KeyObject
->RegistryHive
= KeyObject
->ParentKey
->RegistryHive
;
347 KeyObject
->Flags
= 0;
348 KeyObject
->NumberOfSubKeys
= 0;
349 KeyObject
->SizeOfSubKeys
= 0;
350 KeyObject
->SubKeys
= NULL
;
352 /* Acquire hive lock */
353 KeEnterCriticalRegion();
354 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
356 InsertTailList(&CmiKeyObjectListHead
, &KeyObject
->ListEntry
);
358 /* add key to subkeys of parent if needed */
359 Status
= CmiAddSubKey(KeyObject
->RegistryHive
,
360 KeyObject
->ParentKey
,
366 if (!NT_SUCCESS(Status
))
368 DPRINT("CmiAddSubKey() failed (Status %lx)\n", Status
);
369 /* Release hive lock */
370 ExReleaseResourceLite(&CmiRegistryLock
);
371 KeLeaveCriticalRegion();
372 ObDereferenceObject(KeyObject
);
373 ObDereferenceObject(Object
);
374 RtlFreeUnicodeString(&RemainingPath
);
375 PostCreateKeyInfo
.Object
= NULL
;
376 PostCreateKeyInfo
.Status
= STATUS_UNSUCCESSFUL
;
377 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
378 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
379 return STATUS_UNSUCCESSFUL
;
382 if (Start
== RemainingPath
.Buffer
)
384 KeyObject
->Name
= RemainingPath
;
388 RtlpCreateUnicodeString(&KeyObject
->Name
, Start
, NonPagedPool
);
389 RtlFreeUnicodeString(&RemainingPath
);
392 if (KeyObject
->RegistryHive
== KeyObject
->ParentKey
->RegistryHive
)
394 KeyObject
->KeyCell
->ParentKeyOffset
= KeyObject
->ParentKey
->KeyCellOffset
;
395 KeyObject
->KeyCell
->SecurityKeyOffset
= KeyObject
->ParentKey
->KeyCell
->SecurityKeyOffset
;
399 KeyObject
->KeyCell
->ParentKeyOffset
= -1;
400 KeyObject
->KeyCell
->SecurityKeyOffset
= -1;
401 /* This key must remain in memory unless it is deleted
402 or file is unloaded */
403 ObReferenceObjectByPointer(KeyObject
,
404 STANDARD_RIGHTS_REQUIRED
,
409 CmiAddKeyToList(KeyObject
->ParentKey
, KeyObject
);
411 VERIFY_KEY_OBJECT(KeyObject
);
413 /* Release hive lock */
414 ExReleaseResourceLite(&CmiRegistryLock
);
415 KeLeaveCriticalRegion();
418 ObDereferenceObject(Object
);
421 *Disposition
= REG_CREATED_NEW_KEY
;
423 PostCreateKeyInfo
.Object
= KeyObject
;
424 PostCreateKeyInfo
.Status
= Status
;
425 CmiCallRegisteredCallbacks(RegNtPostCreateKey
, &PostCreateKeyInfo
);
426 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
435 NtDeleteKey(IN HANDLE KeyHandle
)
437 KPROCESSOR_MODE PreviousMode
;
438 PKEY_OBJECT KeyObject
;
440 REG_DELETE_KEY_INFORMATION DeleteKeyInfo
;
441 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
445 DPRINT("NtDeleteKey(KeyHandle 0x%p) called\n", KeyHandle
);
447 PreviousMode
= ExGetPreviousMode();
449 /* Verify that the handle is valid and is a registry key */
450 Status
= ObReferenceObjectByHandle(KeyHandle
,
456 if (!NT_SUCCESS(Status
))
458 DPRINT1("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
462 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
463 DeleteKeyInfo
.Object
= (PVOID
)KeyObject
;
464 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &DeleteKeyInfo
);
465 if (!NT_SUCCESS(Status
))
467 PostOperationInfo
.Status
= Status
;
468 CmiCallRegisteredCallbacks(RegNtDeleteKey
, &PostOperationInfo
);
469 ObDereferenceObject(KeyObject
);
473 /* Acquire hive lock */
474 KeEnterCriticalRegion();
475 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
477 VERIFY_KEY_OBJECT(KeyObject
);
479 /* Check for subkeys */
480 if (KeyObject
->NumberOfSubKeys
!= 0)
482 Status
= STATUS_CANNOT_DELETE
;
486 /* Set the marked for delete bit in the key object */
487 KeyObject
->Flags
|= KO_MARKED_FOR_DELETE
;
488 Status
= STATUS_SUCCESS
;
491 /* Release hive lock */
492 ExReleaseResourceLite(&CmiRegistryLock
);
493 KeLeaveCriticalRegion();
495 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
497 /* Remove the keep-alive reference */
498 ObDereferenceObject(KeyObject
);
500 if (KeyObject
->RegistryHive
!= KeyObject
->ParentKey
->RegistryHive
)
501 ObDereferenceObject(KeyObject
);
503 PostOperationInfo
.Status
= Status
;
504 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
506 /* Dereference the object */
507 ObDereferenceObject(KeyObject
);
509 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
510 DPRINT("HandleCount %lu\n", ObGetObjectHandleCount((PVOID
)KeyObject
));
514 * Hive-Synchronization will not be triggered here. This is done in
515 * CmiObjectDelete() (in regobj.c) after all key-related structures
516 * have been released.
524 NtEnumerateKey(IN HANDLE KeyHandle
,
526 IN KEY_INFORMATION_CLASS KeyInformationClass
,
527 OUT PVOID KeyInformation
,
529 OUT PULONG ResultLength
)
531 PKEY_OBJECT KeyObject
;
532 PKEY_OBJECT SubKeyObject
;
533 PREGISTRY_HIVE RegistryHive
;
534 PKEY_CELL KeyCell
, SubKeyCell
;
535 PHASH_TABLE_CELL HashTableBlock
;
536 PKEY_BASIC_INFORMATION BasicInformation
;
537 PKEY_NODE_INFORMATION NodeInformation
;
538 PKEY_FULL_INFORMATION FullInformation
;
539 PDATA_CELL ClassCell
;
540 ULONG NameSize
, ClassSize
;
541 KPROCESSOR_MODE PreviousMode
;
543 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo
;
544 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
548 PreviousMode
= ExGetPreviousMode();
550 DPRINT("KH 0x%p I %d KIC %x KI 0x%p L %d RL 0x%p\n",
558 /* Verify that the handle is valid and is a registry key */
559 Status
= ObReferenceObjectByHandle(KeyHandle
,
560 KEY_ENUMERATE_SUB_KEYS
,
563 (PVOID
*) &KeyObject
,
565 if (!NT_SUCCESS(Status
))
567 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
571 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
572 EnumerateKeyInfo
.Object
= (PVOID
)KeyObject
;
573 EnumerateKeyInfo
.Index
= Index
;
574 EnumerateKeyInfo
.KeyInformationClass
= KeyInformationClass
;
575 EnumerateKeyInfo
.Length
= Length
;
576 EnumerateKeyInfo
.ResultLength
= ResultLength
;
578 Status
= CmiCallRegisteredCallbacks(RegNtEnumerateKey
, &EnumerateKeyInfo
);
579 if (!NT_SUCCESS(Status
))
581 ObDereferenceObject(KeyObject
);
585 /* Acquire hive lock */
586 KeEnterCriticalRegion();
587 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
589 VERIFY_KEY_OBJECT(KeyObject
);
591 /* Get pointer to KeyCell */
592 KeyCell
= KeyObject
->KeyCell
;
593 RegistryHive
= KeyObject
->RegistryHive
;
597 /* Check for hightest possible sub key index */
598 if (Index
>= KeyCell
->NumberOfSubKeys
+ KeyObject
->NumberOfSubKeys
)
600 ExReleaseResourceLite(&CmiRegistryLock
);
601 KeLeaveCriticalRegion();
602 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
603 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
604 ObDereferenceObject(KeyObject
);
605 DPRINT("No more volatile entries\n");
606 return STATUS_NO_MORE_ENTRIES
;
609 /* Get pointer to SubKey */
610 if (Index
>= KeyCell
->NumberOfSubKeys
)
612 PKEY_OBJECT CurKey
= NULL
;
616 /* Search for volatile or 'foreign' keys */
617 j
= KeyCell
->NumberOfSubKeys
;
618 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
620 CurKey
= KeyObject
->SubKeys
[i
];
621 if (CurKey
->RegistryHive
!= RegistryHive
)
629 if (i
>= KeyObject
->NumberOfSubKeys
)
631 ExReleaseResourceLite(&CmiRegistryLock
);
632 KeLeaveCriticalRegion();
633 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
634 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
635 ObDereferenceObject(KeyObject
);
636 DPRINT("No more non-volatile entries\n");
637 return STATUS_NO_MORE_ENTRIES
;
640 SubKeyObject
= CurKey
;
641 SubKeyCell
= CurKey
->KeyCell
;
645 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
647 ExReleaseResourceLite(&CmiRegistryLock
);
648 KeLeaveCriticalRegion();
649 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
650 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
651 ObDereferenceObject(KeyObject
);
652 return STATUS_NO_MORE_ENTRIES
;
655 HashTableBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
656 if (HashTableBlock
== NULL
)
658 DPRINT("CmiGetBlock() failed\n");
659 ExReleaseResourceLite(&CmiRegistryLock
);
660 KeLeaveCriticalRegion();
661 PostOperationInfo
.Status
= STATUS_UNSUCCESSFUL
;
662 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
663 ObDereferenceObject(KeyObject
);
664 return STATUS_UNSUCCESSFUL
;
667 SubKeyCell
= CmiGetKeyFromHashByIndex(RegistryHive
,
672 if (SubKeyCell
== NULL
)
674 ExReleaseResourceLite(&CmiRegistryLock
);
675 KeLeaveCriticalRegion();
676 PostOperationInfo
.Status
= STATUS_NO_MORE_ENTRIES
;
677 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
678 ObDereferenceObject(KeyObject
);
679 DPRINT("No more entries\n");
680 return STATUS_NO_MORE_ENTRIES
;
683 Status
= STATUS_SUCCESS
;
684 switch (KeyInformationClass
)
686 case KeyBasicInformation
:
687 /* Check size of buffer */
688 if (SubKeyObject
!= NULL
)
690 NameSize
= SubKeyObject
->Name
.Length
;
694 NameSize
= SubKeyCell
->NameSize
;
695 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
697 NameSize
*= sizeof(WCHAR
);
701 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) + NameSize
;
704 * NOTE: It's perfetly valid to call NtEnumerateKey to get
705 * all the information but name. Actually the NT4 sound
706 * framework does that while querying parameters from registry.
707 * -- Filip Navara, 19/07/2004
709 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
711 Status
= STATUS_BUFFER_TOO_SMALL
;
715 /* Fill buffer with requested info */
716 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
717 BasicInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
718 BasicInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
719 BasicInformation
->TitleIndex
= Index
;
720 BasicInformation
->NameLength
= NameSize
;
722 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) < NameSize
)
724 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
725 Status
= STATUS_BUFFER_OVERFLOW
;
729 if (SubKeyObject
!= NULL
)
731 RtlCopyMemory(BasicInformation
->Name
,
732 SubKeyObject
->Name
.Buffer
,
737 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
739 CmiCopyPackedName(BasicInformation
->Name
,
741 NameSize
/ sizeof(WCHAR
));
745 RtlCopyMemory(BasicInformation
->Name
,
753 case KeyNodeInformation
:
754 /* Check size of buffer */
755 if (SubKeyObject
!= NULL
)
757 NameSize
= SubKeyObject
->Name
.Length
;
761 NameSize
= SubKeyCell
->NameSize
;
762 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
764 NameSize
*= sizeof(WCHAR
);
767 ClassSize
= SubKeyCell
->ClassSize
;
769 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
770 NameSize
+ ClassSize
;
772 if (Length
< FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]))
774 Status
= STATUS_BUFFER_TOO_SMALL
;
778 /* Fill buffer with requested info */
779 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
780 NodeInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
781 NodeInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
782 NodeInformation
->TitleIndex
= Index
;
783 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) + NameSize
;
784 NodeInformation
->ClassLength
= SubKeyCell
->ClassSize
;
785 NodeInformation
->NameLength
= NameSize
;
787 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
789 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
791 Status
= STATUS_BUFFER_OVERFLOW
;
794 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
795 NameSize
< ClassSize
)
797 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
799 Status
= STATUS_BUFFER_OVERFLOW
;
803 if (SubKeyObject
!= NULL
)
805 RtlCopyMemory(NodeInformation
->Name
,
806 SubKeyObject
->Name
.Buffer
,
811 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
813 CmiCopyPackedName(NodeInformation
->Name
,
815 NameSize
/ sizeof(WCHAR
));
819 RtlCopyMemory(NodeInformation
->Name
,
827 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
828 SubKeyCell
->ClassNameOffset
,
830 RtlCopyMemory (NodeInformation
->Name
+ SubKeyCell
->NameSize
,
837 case KeyFullInformation
:
838 ClassSize
= SubKeyCell
->ClassSize
;
840 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) +
843 /* Check size of buffer */
844 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]))
846 Status
= STATUS_BUFFER_TOO_SMALL
;
850 /* Fill buffer with requested info */
851 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
852 FullInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
853 FullInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
854 FullInformation
->TitleIndex
= Index
;
855 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) -
857 FullInformation
->ClassLength
= SubKeyCell
->ClassSize
;
858 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //SubKeyCell->NumberOfSubKeys;
859 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
860 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
861 FullInformation
->Values
= SubKeyCell
->NumberOfValues
;
862 FullInformation
->MaxValueNameLen
=
863 CmiGetMaxValueNameLength(RegistryHive
, SubKeyCell
);
864 FullInformation
->MaxValueDataLen
=
865 CmiGetMaxValueDataLength(RegistryHive
, SubKeyCell
);
867 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
869 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
870 Status
= STATUS_BUFFER_OVERFLOW
;
876 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
877 SubKeyCell
->ClassNameOffset
,
879 RtlCopyMemory (FullInformation
->Class
,
887 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
891 ExReleaseResourceLite(&CmiRegistryLock
);
892 KeLeaveCriticalRegion();
894 PostOperationInfo
.Status
= Status
;
895 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
897 ObDereferenceObject(KeyObject
);
899 DPRINT("Returning status %x\n", Status
);
906 NtEnumerateValueKey(IN HANDLE KeyHandle
,
908 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
909 OUT PVOID KeyValueInformation
,
911 OUT PULONG ResultLength
)
914 PKEY_OBJECT KeyObject
;
915 PREGISTRY_HIVE RegistryHive
;
917 PVALUE_CELL ValueCell
;
919 ULONG NameSize
, DataSize
;
920 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
921 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
922 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
926 DPRINT("KH 0x%p I %d KVIC %x KVI 0x%p L %d RL 0x%p\n",
929 KeyValueInformationClass
,
934 /* Verify that the handle is valid and is a registry key */
935 Status
= ObReferenceObjectByHandle(KeyHandle
,
939 (PVOID
*) &KeyObject
,
942 if (!NT_SUCCESS(Status
))
947 /* Acquire hive lock */
948 KeEnterCriticalRegion();
949 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
951 VERIFY_KEY_OBJECT(KeyObject
);
953 /* Get pointer to KeyCell */
954 KeyCell
= KeyObject
->KeyCell
;
955 RegistryHive
= KeyObject
->RegistryHive
;
957 /* Get Value block of interest */
958 Status
= CmiGetValueFromKeyByIndex(RegistryHive
,
963 if (!NT_SUCCESS(Status
))
965 ExReleaseResourceLite(&CmiRegistryLock
);
966 KeLeaveCriticalRegion();
967 ObDereferenceObject(KeyObject
);
971 if (ValueCell
!= NULL
)
973 switch (KeyValueInformationClass
)
975 case KeyValueBasicInformation
:
976 NameSize
= ValueCell
->NameSize
;
977 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
979 NameSize
*= sizeof(WCHAR
);
982 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) + NameSize
;
984 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
986 Status
= STATUS_BUFFER_TOO_SMALL
;
990 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
992 ValueBasicInformation
->TitleIndex
= 0;
993 ValueBasicInformation
->Type
= ValueCell
->DataType
;
994 ValueBasicInformation
->NameLength
= NameSize
;
996 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
999 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1000 Status
= STATUS_BUFFER_OVERFLOW
;
1004 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1006 CmiCopyPackedName(ValueBasicInformation
->Name
,
1008 NameSize
/ sizeof(WCHAR
));
1012 RtlCopyMemory(ValueBasicInformation
->Name
,
1019 case KeyValuePartialInformation
:
1020 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1022 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1025 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1027 Status
= STATUS_BUFFER_TOO_SMALL
;
1031 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1032 KeyValueInformation
;
1033 ValuePartialInformation
->TitleIndex
= 0;
1034 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1035 ValuePartialInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1037 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1040 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1041 Status
= STATUS_BUFFER_OVERFLOW
;
1045 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1047 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1048 RtlCopyMemory(ValuePartialInformation
->Data
,
1054 RtlCopyMemory(ValuePartialInformation
->Data
,
1055 &ValueCell
->DataOffset
,
1061 case KeyValueFullInformation
:
1062 NameSize
= ValueCell
->NameSize
;
1063 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1065 NameSize
*= sizeof(WCHAR
);
1067 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1069 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1070 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1072 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1074 Status
= STATUS_BUFFER_TOO_SMALL
;
1078 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1079 KeyValueInformation
;
1080 ValueFullInformation
->TitleIndex
= 0;
1081 ValueFullInformation
->Type
= ValueCell
->DataType
;
1082 ValueFullInformation
->NameLength
= NameSize
;
1083 ValueFullInformation
->DataOffset
=
1084 (ULONG_PTR
)ValueFullInformation
->Name
-
1085 (ULONG_PTR
)ValueFullInformation
+
1086 ValueFullInformation
->NameLength
;
1087 ValueFullInformation
->DataOffset
=
1088 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1089 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1091 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1094 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1096 Status
= STATUS_BUFFER_OVERFLOW
;
1099 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1100 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1102 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) - NameSize
, sizeof(PVOID
));
1103 Status
= STATUS_BUFFER_OVERFLOW
;
1107 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1109 CmiCopyPackedName(ValueFullInformation
->Name
,
1111 NameSize
/ sizeof(WCHAR
));
1115 RtlCopyMemory(ValueFullInformation
->Name
,
1120 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1122 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1123 RtlCopyMemory((PCHAR
) ValueFullInformation
1124 + ValueFullInformation
->DataOffset
,
1125 DataCell
->Data
, DataSize
);
1129 RtlCopyMemory((PCHAR
) ValueFullInformation
1130 + ValueFullInformation
->DataOffset
,
1131 &ValueCell
->DataOffset
, DataSize
);
1137 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1143 Status
= STATUS_UNSUCCESSFUL
;
1146 ExReleaseResourceLite(&CmiRegistryLock
);
1147 KeLeaveCriticalRegion();
1148 ObDereferenceObject(KeyObject
);
1155 NtFlushKey(IN HANDLE KeyHandle
)
1158 PKEY_OBJECT KeyObject
;
1159 PREGISTRY_HIVE RegistryHive
;
1160 KPROCESSOR_MODE PreviousMode
;
1164 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle
);
1166 PreviousMode
= ExGetPreviousMode();
1168 /* Verify that the handle is valid and is a registry key */
1169 Status
= ObReferenceObjectByHandle(KeyHandle
,
1173 (PVOID
*)&KeyObject
,
1175 if (!NT_SUCCESS(Status
))
1180 VERIFY_KEY_OBJECT(KeyObject
);
1182 RegistryHive
= KeyObject
->RegistryHive
;
1184 /* Acquire hive lock */
1185 KeEnterCriticalRegion();
1186 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1188 if (IsNoFileHive(RegistryHive
))
1190 Status
= STATUS_SUCCESS
;
1194 /* Flush non-volatile hive */
1195 Status
= CmiFlushRegistryHive(RegistryHive
);
1198 ExReleaseResourceLite(&CmiRegistryLock
);
1199 KeLeaveCriticalRegion();
1201 ObDereferenceObject(KeyObject
);
1203 return STATUS_SUCCESS
;
1208 NtOpenKey(OUT PHANDLE KeyHandle
,
1209 IN ACCESS_MASK DesiredAccess
,
1210 IN POBJECT_ATTRIBUTES ObjectAttributes
)
1212 UNICODE_STRING RemainingPath
;
1213 KPROCESSOR_MODE PreviousMode
;
1214 PVOID Object
= NULL
;
1216 NTSTATUS Status
= STATUS_SUCCESS
;
1217 UNICODE_STRING ObjectName
;
1218 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
1219 REG_PRE_OPEN_KEY_INFORMATION PreOpenKeyInfo
;
1220 REG_POST_OPEN_KEY_INFORMATION PostOpenKeyInfo
;
1224 DPRINT("NtOpenKey(KH 0x%p DA %x OA 0x%p OA->ON '%wZ'\n",
1228 ObjectAttributes
? ObjectAttributes
->ObjectName
: NULL
);
1230 /* Check place for result handle, if it's null - return immediately */
1231 if (KeyHandle
== NULL
)
1232 return(STATUS_INVALID_PARAMETER
);
1234 PreviousMode
= ExGetPreviousMode();
1236 if(PreviousMode
!= KernelMode
)
1240 ProbeForWriteHandle(KeyHandle
);
1244 Status
= _SEH_GetExceptionCode();
1248 if(!NT_SUCCESS(Status
))
1254 /* WINE checks for the length also */
1255 /*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
1256 return(STATUS_BUFFER_OVERFLOW);*/
1258 /* Capture all the info */
1259 DPRINT("Capturing Create Info\n");
1260 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
1265 if (!NT_SUCCESS(Status
))
1267 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
1271 PostOpenKeyInfo
.CompleteName
= &ObjectName
;
1272 PreOpenKeyInfo
.CompleteName
= &ObjectName
;
1273 Status
= CmiCallRegisteredCallbacks(RegNtPreOpenKey
, &PreOpenKeyInfo
);
1274 if (!NT_SUCCESS(Status
))
1276 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
1277 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
1282 RemainingPath
.Buffer
= NULL
;
1284 Status
= ObFindObject(&ObjectCreateInfo
,
1289 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
1290 if (!NT_SUCCESS(Status
))
1292 DPRINT("CmpFindObject() returned 0x%08lx\n", Status
);
1293 Status
= STATUS_INVALID_HANDLE
; /* Because CmpFindObject returns STATUS_UNSUCCESSFUL */
1294 hKey
= *KeyHandle
; /* Preserve hkResult value */
1295 goto openkey_cleanup
;
1298 VERIFY_KEY_OBJECT((PKEY_OBJECT
) Object
);
1300 DPRINT("RemainingPath '%wZ'\n", &RemainingPath
);
1302 if ((RemainingPath
.Buffer
!= NULL
) && (RemainingPath
.Buffer
[0] != 0))
1304 RtlFreeUnicodeString(&RemainingPath
);
1305 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1307 goto openkey_cleanup
;
1310 RtlFreeUnicodeString(&RemainingPath
);
1312 /* Fail if the key has been deleted */
1313 if (((PKEY_OBJECT
)Object
)->Flags
& KO_MARKED_FOR_DELETE
)
1315 Status
= STATUS_UNSUCCESSFUL
;
1317 goto openkey_cleanup
;
1320 Status
= ObpCreateHandle(PsGetCurrentProcess(),
1326 if (!NT_SUCCESS(Status
))
1331 PostOpenKeyInfo
.Object
= NT_SUCCESS(Status
) ? (PVOID
)Object
: NULL
;
1332 PostOpenKeyInfo
.Status
= Status
;
1333 CmiCallRegisteredCallbacks (RegNtPostOpenKey
, &PostOpenKeyInfo
);
1334 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
1338 ObDereferenceObject(Object
);
1347 Status
= _SEH_GetExceptionCode();
1356 NtQueryKey(IN HANDLE KeyHandle
,
1357 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1358 OUT PVOID KeyInformation
,
1360 OUT PULONG ResultLength
)
1362 PKEY_BASIC_INFORMATION BasicInformation
;
1363 PKEY_NODE_INFORMATION NodeInformation
;
1364 PKEY_FULL_INFORMATION FullInformation
;
1365 PREGISTRY_HIVE RegistryHive
;
1366 PDATA_CELL ClassCell
;
1367 PKEY_OBJECT KeyObject
;
1369 ULONG NameSize
, ClassSize
;
1371 REG_QUERY_KEY_INFORMATION QueryKeyInfo
;
1372 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1376 DPRINT("NtQueryKey(KH 0x%p KIC %x KI 0x%p L %d RL 0x%p)\n",
1378 KeyInformationClass
,
1383 /* Verify that the handle is valid and is a registry key */
1384 Status
= ObReferenceObjectByHandle(KeyHandle
,
1385 (KeyInformationClass
!= KeyNameInformation
? KEY_QUERY_VALUE
: 0),
1388 (PVOID
*) &KeyObject
,
1390 if (!NT_SUCCESS(Status
))
1395 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1396 QueryKeyInfo
.Object
= (PVOID
)KeyObject
;
1397 QueryKeyInfo
.KeyInformationClass
= KeyInformationClass
;
1398 QueryKeyInfo
.KeyInformation
= KeyInformation
;
1399 QueryKeyInfo
.Length
= Length
;
1400 QueryKeyInfo
.ResultLength
= ResultLength
;
1402 Status
= CmiCallRegisteredCallbacks(RegNtQueryKey
, &QueryKeyInfo
);
1403 if (!NT_SUCCESS(Status
))
1405 ObDereferenceObject(KeyObject
);
1409 /* Acquire hive lock */
1410 KeEnterCriticalRegion();
1411 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1413 VERIFY_KEY_OBJECT(KeyObject
);
1415 /* Get pointer to KeyCell */
1416 KeyCell
= KeyObject
->KeyCell
;
1417 RegistryHive
= KeyObject
->RegistryHive
;
1419 Status
= STATUS_SUCCESS
;
1420 switch (KeyInformationClass
)
1422 case KeyBasicInformation
:
1423 NameSize
= KeyObject
->Name
.Length
;
1425 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1427 /* Check size of buffer */
1428 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
1430 Status
= STATUS_BUFFER_TOO_SMALL
;
1434 /* Fill buffer with requested info */
1435 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
1436 BasicInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1437 BasicInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1438 BasicInformation
->TitleIndex
= 0;
1439 BasicInformation
->NameLength
= KeyObject
->Name
.Length
;
1441 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) <
1444 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1445 Status
= STATUS_BUFFER_OVERFLOW
;
1449 RtlCopyMemory(BasicInformation
->Name
,
1450 KeyObject
->Name
.Buffer
,
1455 case KeyNodeInformation
:
1456 NameSize
= KeyObject
->Name
.Length
;
1457 ClassSize
= KeyCell
->ClassSize
;
1459 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
1460 NameSize
+ ClassSize
;
1462 /* Check size of buffer */
1463 if (Length
< *ResultLength
)
1465 Status
= STATUS_BUFFER_TOO_SMALL
;
1469 /* Fill buffer with requested info */
1470 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
1471 NodeInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1472 NodeInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1473 NodeInformation
->TitleIndex
= 0;
1474 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
1475 KeyObject
->Name
.Length
;
1476 NodeInformation
->ClassLength
= KeyCell
->ClassSize
;
1477 NodeInformation
->NameLength
= KeyObject
->Name
.Length
;
1479 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
1481 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
1483 Status
= STATUS_BUFFER_OVERFLOW
;
1486 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1487 NameSize
< ClassSize
)
1489 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1491 Status
= STATUS_BUFFER_OVERFLOW
;
1495 RtlCopyMemory(NodeInformation
->Name
,
1496 KeyObject
->Name
.Buffer
,
1501 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1502 KeyCell
->ClassNameOffset
,
1504 RtlCopyMemory (NodeInformation
->Name
+ KeyObject
->Name
.Length
,
1511 case KeyFullInformation
:
1512 ClassSize
= KeyCell
->ClassSize
;
1514 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
1517 /* Check size of buffer */
1518 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
))
1520 Status
= STATUS_BUFFER_TOO_SMALL
;
1524 /* Fill buffer with requested info */
1525 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
1526 FullInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1527 FullInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1528 FullInformation
->TitleIndex
= 0;
1529 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) - sizeof(WCHAR
);
1530 FullInformation
->ClassLength
= KeyCell
->ClassSize
;
1531 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //KeyCell->NumberOfSubKeys;
1532 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
1533 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
1534 FullInformation
->Values
= KeyCell
->NumberOfValues
;
1535 FullInformation
->MaxValueNameLen
=
1536 CmiGetMaxValueNameLength(RegistryHive
, KeyCell
);
1537 FullInformation
->MaxValueDataLen
=
1538 CmiGetMaxValueDataLength(RegistryHive
, KeyCell
);
1540 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
1542 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
1543 Status
= STATUS_BUFFER_OVERFLOW
;
1549 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1550 KeyCell
->ClassNameOffset
,
1552 RtlCopyMemory (FullInformation
->Class
,
1553 ClassCell
->Data
, ClassSize
);
1558 case KeyNameInformation
:
1559 case KeyCachedInformation
:
1560 case KeyFlagsInformation
:
1561 DPRINT1("Key information class 0x%x not yet implemented!\n", KeyInformationClass
);
1562 Status
= STATUS_NOT_IMPLEMENTED
;
1566 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
1567 Status
= STATUS_INVALID_INFO_CLASS
;
1571 ExReleaseResourceLite(&CmiRegistryLock
);
1572 KeLeaveCriticalRegion();
1574 PostOperationInfo
.Status
= Status
;
1575 CmiCallRegisteredCallbacks(RegNtPostQueryKey
, &PostOperationInfo
);
1577 ObDereferenceObject(KeyObject
);
1584 NtQueryValueKey(IN HANDLE KeyHandle
,
1585 IN PUNICODE_STRING ValueName
,
1586 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1587 OUT PVOID KeyValueInformation
,
1589 OUT PULONG ResultLength
)
1592 ULONG NameSize
, DataSize
;
1593 PKEY_OBJECT KeyObject
;
1594 PREGISTRY_HIVE RegistryHive
;
1596 PVALUE_CELL ValueCell
;
1597 PDATA_CELL DataCell
;
1598 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
1599 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
1600 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
1601 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo
;
1602 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1606 DPRINT("NtQueryValueKey(KeyHandle 0x%p ValueName %S Length %x)\n",
1607 KeyHandle
, ValueName
->Buffer
, Length
);
1609 /* Verify that the handle is valid and is a registry key */
1610 Status
= ObReferenceObjectByHandle(KeyHandle
,
1614 (PVOID
*)&KeyObject
,
1617 if (!NT_SUCCESS(Status
))
1619 DPRINT1("ObReferenceObjectByHandle() failed with status %x %p\n", Status
, KeyHandle
);
1623 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1624 QueryValueKeyInfo
.Object
= (PVOID
)KeyObject
;
1625 QueryValueKeyInfo
.ValueName
= ValueName
;
1626 QueryValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
1627 QueryValueKeyInfo
.Length
= Length
;
1628 QueryValueKeyInfo
.ResultLength
= ResultLength
;
1630 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
1631 if (!NT_SUCCESS(Status
))
1633 ObDereferenceObject(KeyObject
);
1637 /* Acquire hive lock */
1638 KeEnterCriticalRegion();
1639 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1641 VERIFY_KEY_OBJECT(KeyObject
);
1643 /* Get pointer to KeyCell */
1644 KeyCell
= KeyObject
->KeyCell
;
1645 RegistryHive
= KeyObject
->RegistryHive
;
1647 /* Get value cell by name */
1648 Status
= CmiScanKeyForValue(RegistryHive
,
1653 if (!NT_SUCCESS(Status
))
1655 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
1659 Status
= STATUS_SUCCESS
;
1660 switch (KeyValueInformationClass
)
1662 case KeyValueBasicInformation
:
1663 NameSize
= ValueCell
->NameSize
;
1664 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1666 NameSize
*= sizeof(WCHAR
);
1669 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) +
1672 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1674 Status
= STATUS_BUFFER_TOO_SMALL
;
1678 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1679 KeyValueInformation
;
1680 ValueBasicInformation
->TitleIndex
= 0;
1681 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1682 ValueBasicInformation
->NameLength
= NameSize
;
1684 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1687 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1688 Status
= STATUS_BUFFER_OVERFLOW
;
1692 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1694 CmiCopyPackedName(ValueBasicInformation
->Name
,
1696 NameSize
/ sizeof(WCHAR
));
1700 RtlCopyMemory(ValueBasicInformation
->Name
,
1707 case KeyValuePartialInformation
:
1708 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1710 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1713 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1715 Status
= STATUS_BUFFER_TOO_SMALL
;
1719 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1720 KeyValueInformation
;
1721 ValuePartialInformation
->TitleIndex
= 0;
1722 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1723 ValuePartialInformation
->DataLength
= DataSize
;
1725 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1728 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1729 Status
= STATUS_BUFFER_OVERFLOW
;
1733 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1735 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1736 RtlCopyMemory(ValuePartialInformation
->Data
,
1742 RtlCopyMemory(ValuePartialInformation
->Data
,
1743 &ValueCell
->DataOffset
,
1749 case KeyValueFullInformation
:
1750 NameSize
= ValueCell
->NameSize
;
1751 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1753 NameSize
*= sizeof(WCHAR
);
1755 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1757 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1758 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1760 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1762 Status
= STATUS_BUFFER_TOO_SMALL
;
1766 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1767 KeyValueInformation
;
1768 ValueFullInformation
->TitleIndex
= 0;
1769 ValueFullInformation
->Type
= ValueCell
->DataType
;
1770 ValueFullInformation
->NameLength
= NameSize
;
1771 ValueFullInformation
->DataOffset
=
1772 (ULONG_PTR
)ValueFullInformation
->Name
-
1773 (ULONG_PTR
)ValueFullInformation
+
1774 ValueFullInformation
->NameLength
;
1775 ValueFullInformation
->DataOffset
=
1776 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1777 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1779 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1782 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1784 Status
= STATUS_BUFFER_OVERFLOW
;
1787 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1788 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1790 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1791 Name
[0]) - NameSize
, sizeof(PVOID
));
1792 Status
= STATUS_BUFFER_OVERFLOW
;
1796 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1798 CmiCopyPackedName(ValueFullInformation
->Name
,
1800 NameSize
/ sizeof(WCHAR
));
1804 RtlCopyMemory(ValueFullInformation
->Name
,
1808 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1810 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1811 RtlCopyMemory((PCHAR
) ValueFullInformation
1812 + ValueFullInformation
->DataOffset
,
1818 RtlCopyMemory((PCHAR
) ValueFullInformation
1819 + ValueFullInformation
->DataOffset
,
1820 &ValueCell
->DataOffset
,
1827 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1828 Status
= STATUS_INVALID_INFO_CLASS
;
1833 ExReleaseResourceLite(&CmiRegistryLock
);
1834 KeLeaveCriticalRegion();
1836 PostOperationInfo
.Status
= Status
;
1837 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
1838 ObDereferenceObject(KeyObject
);
1845 NtSetValueKey(IN HANDLE KeyHandle
,
1846 IN PUNICODE_STRING ValueName
,
1847 IN ULONG TitleIndex
,
1853 PKEY_OBJECT KeyObject
;
1854 PREGISTRY_HIVE RegistryHive
;
1856 PVALUE_CELL ValueCell
;
1857 BLOCK_OFFSET ValueCellOffset
;
1858 PDATA_CELL DataCell
;
1859 PDATA_CELL NewDataCell
;
1861 ULONG DesiredAccess
;
1862 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo
;
1863 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1867 DPRINT("NtSetValueKey(KeyHandle 0x%p ValueName '%wZ' Type %d)\n",
1868 KeyHandle
, ValueName
, Type
);
1870 DesiredAccess
= KEY_SET_VALUE
;
1872 /* Verify that the handle is valid and is a registry key */
1873 Status
= ObReferenceObjectByHandle(KeyHandle
,
1876 ExGetPreviousMode(),
1877 (PVOID
*)&KeyObject
,
1879 if (!NT_SUCCESS(Status
))
1882 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1883 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
1884 SetValueKeyInfo
.ValueName
= ValueName
;
1885 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
1886 SetValueKeyInfo
.Type
= Type
;
1887 SetValueKeyInfo
.Data
= Data
;
1888 SetValueKeyInfo
.DataSize
= DataSize
;
1889 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
1890 if (!NT_SUCCESS(Status
))
1892 ObDereferenceObject(KeyObject
);
1896 /* Acquire hive lock exclucively */
1897 KeEnterCriticalRegion();
1898 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1900 VERIFY_KEY_OBJECT(KeyObject
);
1902 /* Get pointer to key cell */
1903 KeyCell
= KeyObject
->KeyCell
;
1904 RegistryHive
= KeyObject
->RegistryHive
;
1905 Status
= CmiScanKeyForValue(RegistryHive
,
1910 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1912 DPRINT("Allocate new value cell\n");
1913 Status
= CmiAddValueToKey(RegistryHive
,
1915 KeyObject
->KeyCellOffset
,
1921 if (!NT_SUCCESS(Status
))
1923 DPRINT("Cannot add value. Status 0x%X\n", Status
);
1925 ExReleaseResourceLite(&CmiRegistryLock
);
1926 KeLeaveCriticalRegion();
1927 PostOperationInfo
.Status
= Status
;
1928 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
1929 ObDereferenceObject(KeyObject
);
1933 DPRINT("DataSize %lu\n", DataSize
);
1934 DPRINT("ValueCell %p\n", ValueCell
);
1935 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1937 if (DataSize
<= sizeof(BLOCK_OFFSET
))
1939 /* If data size <= sizeof(BLOCK_OFFSET) then store data in the data offset */
1940 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1941 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1942 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1944 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1945 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
1948 RtlCopyMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
1949 ValueCell
->DataSize
= DataSize
| REG_DATA_IN_OFFSET
;
1950 ValueCell
->DataType
= Type
;
1951 RtlMoveMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
1952 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
1954 else if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1955 (DataSize
<= (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
1957 /* If new data size is <= current then overwrite current data */
1958 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
,&pBin
);
1959 RtlZeroMemory(DataCell
->Data
, ValueCell
->DataSize
);
1960 RtlCopyMemory(DataCell
->Data
, Data
, DataSize
);
1961 ValueCell
->DataSize
= DataSize
;
1962 ValueCell
->DataType
= Type
;
1967 * New data size is larger than the current, destroy current
1968 * data block and allocate a new one.
1970 BLOCK_OFFSET NewOffset
;
1972 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1974 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1975 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1977 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1978 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
1979 ValueCell
->DataSize
= 0;
1980 ValueCell
->DataType
= 0;
1981 ValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
1984 Status
= CmiAllocateCell (RegistryHive
,
1985 sizeof(CELL_HEADER
) + DataSize
,
1986 (PVOID
*)&NewDataCell
,
1988 if (!NT_SUCCESS(Status
))
1990 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status
);
1992 ExReleaseResourceLite(&CmiRegistryLock
);
1993 KeLeaveCriticalRegion();
1994 PostOperationInfo
.Status
= Status
;
1995 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
1996 ObDereferenceObject(KeyObject
);
2001 RtlCopyMemory(&NewDataCell
->Data
[0], Data
, DataSize
);
2002 ValueCell
->DataSize
= DataSize
& REG_DATA_SIZE_MASK
;
2003 ValueCell
->DataType
= Type
;
2004 ValueCell
->DataOffset
= NewOffset
;
2005 CmiMarkBlockDirty(RegistryHive
, ValueCell
->DataOffset
);
2006 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
2010 if ((Type
== REG_LINK
) &&
2011 (_wcsicmp(ValueName
->Buffer
, L
"SymbolicLinkValue") == 0))
2013 KeyCell
->Flags
|= REG_KEY_LINK_CELL
;
2016 KeQuerySystemTime (&KeyCell
->LastWriteTime
);
2017 CmiMarkBlockDirty (RegistryHive
, KeyObject
->KeyCellOffset
);
2019 ExReleaseResourceLite(&CmiRegistryLock
);
2020 KeLeaveCriticalRegion();
2021 PostOperationInfo
.Status
= Status
;
2022 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
2023 ObDereferenceObject(KeyObject
);
2027 DPRINT("Return Status 0x%X\n", Status
);
2034 NtDeleteValueKey (IN HANDLE KeyHandle
,
2035 IN PUNICODE_STRING ValueName
)
2037 PKEY_OBJECT KeyObject
;
2039 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
2040 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2041 KPROCESSOR_MODE PreviousMode
;
2042 UNICODE_STRING CapturedValueName
;
2046 PreviousMode
= KeGetPreviousMode();
2048 /* Verify that the handle is valid and is a registry key */
2049 Status
= ObReferenceObjectByHandle(KeyHandle
,
2053 (PVOID
*)&KeyObject
,
2055 if (!NT_SUCCESS(Status
))
2060 Status
= ProbeAndCaptureUnicodeString(&CapturedValueName
,
2063 if (!NT_SUCCESS(Status
))
2067 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
2068 DeleteValueKeyInfo
.ValueName
= &CapturedValueName
;
2070 /* FIXME - check if value exists before calling the callbacks? */
2071 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
, &DeleteValueKeyInfo
);
2072 if (!NT_SUCCESS(Status
))
2074 ReleaseCapturedUnicodeString(&CapturedValueName
,
2077 ObDereferenceObject(KeyObject
);
2081 /* Acquire hive lock */
2082 KeEnterCriticalRegion();
2083 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2085 VERIFY_KEY_OBJECT(KeyObject
);
2087 Status
= CmiDeleteValueFromKey(KeyObject
->RegistryHive
,
2089 KeyObject
->KeyCellOffset
,
2092 KeQuerySystemTime (&KeyObject
->KeyCell
->LastWriteTime
);
2093 CmiMarkBlockDirty (KeyObject
->RegistryHive
, KeyObject
->KeyCellOffset
);
2095 /* Release hive lock */
2096 ExReleaseResourceLite(&CmiRegistryLock
);
2097 KeLeaveCriticalRegion();
2099 ReleaseCapturedUnicodeString(&CapturedValueName
,
2102 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2103 PostOperationInfo
.Status
= Status
;
2105 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
, &PostOperationInfo
);
2107 ObDereferenceObject (KeyObject
);
2117 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2118 * KeyObjectAttributes->Name specifies the name of the key to load.
2121 NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
2122 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
2124 return NtLoadKey2 (KeyObjectAttributes
,
2125 FileObjectAttributes
,
2132 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2133 * KeyObjectAttributes->Name specifies the name of the key to load.
2134 * Flags can be 0 or REG_NO_LAZY_FLUSH.
2137 NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
2138 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
2141 POBJECT_NAME_INFORMATION NameInfo
;
2142 PUNICODE_STRING NamePointer
;
2150 DPRINT ("NtLoadKey2() called\n");
2153 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, KeGetPreviousMode ()))
2154 return STATUS_PRIVILEGE_NOT_HELD
;
2157 if (FileObjectAttributes
->RootDirectory
!= NULL
)
2160 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2161 Buffer
= ExAllocatePool (NonPagedPool
,
2164 return STATUS_INSUFFICIENT_RESOURCES
;
2166 Status
= ZwQueryObject (FileObjectAttributes
->RootDirectory
,
2167 ObjectNameInformation
,
2171 if (!NT_SUCCESS(Status
))
2173 DPRINT1 ("NtQueryObject() failed (Status %lx)\n", Status
);
2174 ExFreePool (Buffer
);
2178 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2179 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2180 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2182 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2183 if (FileObjectAttributes
->ObjectName
->Buffer
[0] != L
'\\')
2185 RtlAppendUnicodeToString (&NameInfo
->Name
,
2187 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2188 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2190 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2191 FileObjectAttributes
->ObjectName
);
2193 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2194 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2195 NamePointer
= &NameInfo
->Name
;
2199 if (FileObjectAttributes
->ObjectName
->Buffer
[0] == L
'\\')
2202 NamePointer
= FileObjectAttributes
->ObjectName
;
2207 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2208 Buffer
= ExAllocatePool (NonPagedPool
,
2211 return STATUS_INSUFFICIENT_RESOURCES
;
2213 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2214 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2215 NameInfo
->Name
.Length
= 0;
2216 NameInfo
->Name
.Buffer
= (PWSTR
)((ULONG_PTR
)Buffer
+ sizeof(OBJECT_NAME_INFORMATION
));
2217 NameInfo
->Name
.Buffer
[0] = 0;
2219 RtlAppendUnicodeToString (&NameInfo
->Name
,
2221 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2222 FileObjectAttributes
->ObjectName
);
2224 NamePointer
= &NameInfo
->Name
;
2228 DPRINT ("Full name: '%wZ'\n", NamePointer
);
2230 /* Acquire hive lock */
2231 KeEnterCriticalRegion();
2232 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2234 Status
= CmiLoadHive (KeyObjectAttributes
,
2237 if (!NT_SUCCESS (Status
))
2239 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
2242 /* Release hive lock */
2243 ExReleaseResourceLite(&CmiRegistryLock
);
2244 KeLeaveCriticalRegion();
2247 ExFreePool (Buffer
);
2254 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2256 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2257 IN PVOID ApcContext OPTIONAL
,
2258 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2259 IN ULONG CompletionFilter
,
2260 IN BOOLEAN WatchSubtree
,
2263 IN BOOLEAN Asynchronous
)
2266 return(STATUS_NOT_IMPLEMENTED
);
2271 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2273 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2274 IN PVOID ApcContext OPTIONAL
,
2275 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2276 IN ULONG CompletionFilter
,
2277 IN BOOLEAN WatchSubtree
,
2280 IN BOOLEAN Asynchronous
)
2282 return NtNotifyChangeMultipleKeys(KeyHandle
,
2299 NtQueryMultipleValueKey (IN HANDLE KeyHandle
,
2300 IN OUT PKEY_VALUE_ENTRY ValueList
,
2301 IN ULONG NumberOfValues
,
2303 IN OUT PULONG Length
,
2304 OUT PULONG ReturnLength
)
2306 PREGISTRY_HIVE RegistryHive
;
2307 PVALUE_CELL ValueCell
;
2308 PKEY_OBJECT KeyObject
;
2309 PDATA_CELL DataCell
;
2310 ULONG BufferLength
= 0;
2315 REG_QUERY_MULTIPLE_VALUE_KEY_INFORMATION QueryMultipleValueKeyInfo
;
2316 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2320 /* Verify that the handle is valid and is a registry key */
2321 Status
= ObReferenceObjectByHandle(KeyHandle
,
2325 (PVOID
*) &KeyObject
,
2327 if (!NT_SUCCESS(Status
))
2329 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2333 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2334 QueryMultipleValueKeyInfo
.Object
= (PVOID
)KeyObject
;
2335 QueryMultipleValueKeyInfo
.ValueEntries
= ValueList
;
2336 QueryMultipleValueKeyInfo
.EntryCount
= NumberOfValues
;
2337 QueryMultipleValueKeyInfo
.ValueBuffer
= Buffer
;
2338 QueryMultipleValueKeyInfo
.BufferLength
= Length
;
2339 QueryMultipleValueKeyInfo
.RequiredBufferLength
= ReturnLength
;
2341 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryMultipleValueKey
, &QueryMultipleValueKeyInfo
);
2342 if (!NT_SUCCESS(Status
))
2344 ObDereferenceObject(KeyObject
);
2348 /* Acquire hive lock */
2349 KeEnterCriticalRegion();
2350 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
2352 VERIFY_KEY_OBJECT(KeyObject
);
2354 /* Get pointer to KeyCell */
2355 KeyCell
= KeyObject
->KeyCell
;
2356 RegistryHive
= KeyObject
->RegistryHive
;
2358 DataPtr
= (PUCHAR
) Buffer
;
2360 for (i
= 0; i
< NumberOfValues
; i
++)
2362 DPRINT("ValueName: '%wZ'\n", ValueList
[i
].ValueName
);
2364 /* Get Value block of interest */
2365 Status
= CmiScanKeyForValue(RegistryHive
,
2367 ValueList
[i
].ValueName
,
2371 if (!NT_SUCCESS(Status
))
2373 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
2376 else if (ValueCell
== NULL
)
2378 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
2382 BufferLength
= ROUND_UP(BufferLength
, sizeof(PVOID
));
2384 if (BufferLength
+ (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) <= *Length
)
2386 DataPtr
= (PUCHAR
)ROUND_UP((ULONG_PTR
)DataPtr
, sizeof(PVOID
));
2388 ValueList
[i
].Type
= ValueCell
->DataType
;
2389 ValueList
[i
].DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2390 ValueList
[i
].DataOffset
= (ULONG_PTR
)DataPtr
- (ULONG_PTR
)Buffer
;
2392 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
2394 DataCell
= CmiGetCell (RegistryHive
,
2395 ValueCell
->DataOffset
,
2397 RtlCopyMemory(DataPtr
,
2399 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2403 RtlCopyMemory(DataPtr
,
2404 &ValueCell
->DataOffset
,
2405 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2408 DataPtr
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2412 Status
= STATUS_BUFFER_TOO_SMALL
;
2415 BufferLength
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2418 if (NT_SUCCESS(Status
))
2419 *Length
= BufferLength
;
2421 *ReturnLength
= BufferLength
;
2423 /* Release hive lock */
2424 ExReleaseResourceLite(&CmiRegistryLock
);
2425 KeLeaveCriticalRegion();
2427 PostOperationInfo
.Status
= Status
;
2428 CmiCallRegisteredCallbacks(RegNtPostQueryMultipleValueKey
, &PostOperationInfo
);
2430 ObDereferenceObject(KeyObject
);
2432 DPRINT("Return Status 0x%X\n", Status
);
2439 NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes
,
2441 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
2444 return(STATUS_NOT_IMPLEMENTED
);
2449 NtRestoreKey (IN HANDLE KeyHandle
,
2450 IN HANDLE FileHandle
,
2451 IN ULONG RestoreFlags
)
2454 return(STATUS_NOT_IMPLEMENTED
);
2459 NtSaveKey (IN HANDLE KeyHandle
,
2460 IN HANDLE FileHandle
)
2462 PREGISTRY_HIVE TempHive
;
2463 PKEY_OBJECT KeyObject
;
2468 DPRINT ("NtSaveKey() called\n");
2471 if (!SeSinglePrivilegeCheck (SeBackupPrivilege
, KeGetPreviousMode ()))
2472 return STATUS_PRIVILEGE_NOT_HELD
;
2475 Status
= ObReferenceObjectByHandle (KeyHandle
,
2478 KeGetPreviousMode(),
2479 (PVOID
*)&KeyObject
,
2481 if (!NT_SUCCESS(Status
))
2483 DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
2487 /* Acquire hive lock exclucively */
2488 KeEnterCriticalRegion();
2489 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2491 /* Refuse to save a volatile key */
2492 if (KeyObject
->RegistryHive
== CmiVolatileHive
)
2494 DPRINT1 ("Cannot save a volatile key\n");
2495 ExReleaseResourceLite(&CmiRegistryLock
);
2496 KeLeaveCriticalRegion();
2497 ObDereferenceObject (KeyObject
);
2498 return STATUS_ACCESS_DENIED
;
2501 Status
= CmiCreateTempHive(&TempHive
);
2502 if (!NT_SUCCESS(Status
))
2504 DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status
);
2505 ExReleaseResourceLite(&CmiRegistryLock
);
2506 KeLeaveCriticalRegion();
2507 ObDereferenceObject (KeyObject
);
2511 Status
= CmiCopyKey (TempHive
,
2513 KeyObject
->RegistryHive
,
2514 KeyObject
->KeyCell
);
2515 if (!NT_SUCCESS(Status
))
2517 DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status
);
2518 CmiRemoveRegistryHive (TempHive
);
2519 ExReleaseResourceLite(&CmiRegistryLock
);
2520 KeLeaveCriticalRegion();
2521 ObDereferenceObject (KeyObject
);
2525 Status
= CmiSaveTempHive (TempHive
,
2527 if (!NT_SUCCESS(Status
))
2529 DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status
);
2532 CmiRemoveRegistryHive (TempHive
);
2534 /* Release hive lock */
2535 ExReleaseResourceLite(&CmiRegistryLock
);
2536 KeLeaveCriticalRegion();
2538 ObDereferenceObject (KeyObject
);
2540 DPRINT ("NtSaveKey() done\n");
2542 return STATUS_SUCCESS
;
2551 IN HANDLE KeyHandle
,
2552 IN HANDLE FileHandle
,
2553 IN ULONG Flags
// REG_STANDARD_FORMAT, etc..
2557 return STATUS_NOT_IMPLEMENTED
;
2562 NtSetInformationKey (IN HANDLE KeyHandle
,
2563 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
2564 IN PVOID KeyInformation
,
2565 IN ULONG KeyInformationLength
)
2567 PKEY_OBJECT KeyObject
;
2569 REG_SET_INFORMATION_KEY_INFORMATION SetInformationKeyInfo
;
2570 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
2574 /* Verify that the handle is valid and is a registry key */
2575 Status
= ObReferenceObjectByHandle (KeyHandle
,
2579 (PVOID
*)&KeyObject
,
2581 if (!NT_SUCCESS (Status
))
2583 DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2587 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
2588 SetInformationKeyInfo
.Object
= (PVOID
)KeyObject
;
2589 SetInformationKeyInfo
.KeySetInformationClass
= KeyInformationClass
;
2590 SetInformationKeyInfo
.KeySetInformation
= KeyInformation
;
2591 SetInformationKeyInfo
.KeySetInformationLength
= KeyInformationLength
;
2593 Status
= CmiCallRegisteredCallbacks(RegNtSetInformationKey
, &SetInformationKeyInfo
);
2594 if (!NT_SUCCESS(Status
))
2596 ObDereferenceObject (KeyObject
);
2600 if (KeyInformationClass
!= KeyWriteTimeInformation
)
2602 Status
= STATUS_INVALID_INFO_CLASS
;
2605 else if (KeyInformationLength
!= sizeof (KEY_WRITE_TIME_INFORMATION
))
2607 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2611 /* Acquire hive lock */
2612 KeEnterCriticalRegion();
2613 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2615 VERIFY_KEY_OBJECT(KeyObject
);
2617 KeyObject
->KeyCell
->LastWriteTime
.QuadPart
=
2618 ((PKEY_WRITE_TIME_INFORMATION
)KeyInformation
)->LastWriteTime
.QuadPart
;
2620 CmiMarkBlockDirty (KeyObject
->RegistryHive
,
2621 KeyObject
->KeyCellOffset
);
2623 /* Release hive lock */
2624 ExReleaseResourceLite(&CmiRegistryLock
);
2625 KeLeaveCriticalRegion();
2628 PostOperationInfo
.Status
= Status
;
2629 CmiCallRegisteredCallbacks(RegNtPostSetInformationKey
, &PostOperationInfo
);
2631 ObDereferenceObject (KeyObject
);
2633 if (NT_SUCCESS(Status
))
2638 DPRINT ("NtSaveKey() done\n");
2640 return STATUS_SUCCESS
;
2646 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2647 * KeyObjectAttributes->Name specifies the name of the key to unload.
2650 NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
2652 PREGISTRY_HIVE RegistryHive
;
2657 DPRINT ("NtUnloadKey() called\n");
2660 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, KeGetPreviousMode ()))
2661 return STATUS_PRIVILEGE_NOT_HELD
;
2664 /* Acquire registry lock exclusively */
2665 KeEnterCriticalRegion();
2666 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2668 Status
= CmiDisconnectHive (KeyObjectAttributes
,
2670 if (!NT_SUCCESS (Status
))
2672 DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status
);
2673 ExReleaseResourceLite (&CmiRegistryLock
);
2674 KeLeaveCriticalRegion();
2678 DPRINT ("RegistryHive %p\n", RegistryHive
);
2682 if (!IsNoFileHive (RegistryHive
))
2683 CmiFlushRegistryHive (RegistryHive
);
2686 CmiRemoveRegistryHive (RegistryHive
);
2688 /* Release registry lock */
2689 ExReleaseResourceLite (&CmiRegistryLock
);
2690 KeLeaveCriticalRegion();
2692 DPRINT ("NtUnloadKey() done\n");
2694 return STATUS_SUCCESS
;
2699 NtInitializeRegistry (IN BOOLEAN SetUpBoot
)
2705 if (CmiRegistryInitialized
== TRUE
)
2706 return STATUS_ACCESS_DENIED
;
2708 /* Save boot log file */
2709 IopSaveBootLogToFile();
2711 Status
= CmiInitHives (SetUpBoot
);
2713 CmiRegistryInitialized
= TRUE
;