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
;
139 ExAcquireFastMutex(&CmiCallbackLock
);
141 for(CurrentEntry
= CmiCallbackHead
.Flink
;
142 CurrentEntry
!= &CmiCallbackHead
;
143 CurrentEntry
= CurrentEntry
->Flink
)
145 PREGISTRY_CALLBACK CurrentCallback
;
147 CurrentCallback
= CONTAINING_RECORD(CurrentEntry
, REGISTRY_CALLBACK
, ListEntry
);
148 if(!CurrentCallback
->PendingDelete
&&
149 ExAcquireRundownProtectionEx(&CurrentCallback
->RundownRef
, 1))
153 /* don't hold locks during the callbacks! */
154 ExReleaseFastMutex(&CmiCallbackLock
);
156 Status
= CurrentCallback
->Function(CurrentCallback
->Context
,
159 if(!NT_SUCCESS(Status
))
161 /* one callback returned failure, don't call any more callbacks */
165 ExAcquireFastMutex(&CmiCallbackLock
);
166 /* don't release the rundown protection before holding the callback lock
167 so the pointer to the next callback isn't cleared in case this callback
169 ExReleaseRundownProtectionEx(&CurrentCallback
->RundownRef
, 1);
173 ExReleaseFastMutex(&CmiCallbackLock
);
175 return STATUS_SUCCESS
;
180 NtCreateKey(OUT PHANDLE KeyHandle
,
181 IN ACCESS_MASK DesiredAccess
,
182 IN POBJECT_ATTRIBUTES ObjectAttributes
,
184 IN PUNICODE_STRING Class
,
185 IN ULONG CreateOptions
,
186 OUT PULONG Disposition
)
188 UNICODE_STRING RemainingPath
;
189 PKEY_OBJECT KeyObject
;
193 UNICODE_STRING ObjectName
;
194 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
199 DPRINT("NtCreateKey (Name %wZ KeyHandle 0x%p Root 0x%p)\n",
200 ObjectAttributes
->ObjectName
,
202 ObjectAttributes
->RootDirectory
);
204 /* Capture all the info */
205 DPRINT("Capturing Create Info\n");
206 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
211 if (!NT_SUCCESS(Status
))
213 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
217 Status
= ObFindObject(&ObjectCreateInfo
,
222 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
223 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
224 if (!NT_SUCCESS(Status
))
226 DPRINT("CmpFindObject failed, Status: 0x%x\n", Status
);
230 DPRINT("RemainingPath %wZ\n", &RemainingPath
);
232 if (RemainingPath
.Length
== 0)
234 /* Fail if the key has been deleted */
235 if (((PKEY_OBJECT
) Object
)->Flags
& KO_MARKED_FOR_DELETE
)
237 ObDereferenceObject(Object
);
238 RtlFreeUnicodeString(&RemainingPath
);
239 DPRINT("Object marked for delete!\n");
240 return(STATUS_UNSUCCESSFUL
);
244 *Disposition
= REG_OPENED_EXISTING_KEY
;
246 Status
= ObpCreateHandle(PsGetCurrentProcess(),
252 DPRINT("ObpCreateHandle failed Status 0x%x\n", Status
);
253 ObDereferenceObject(Object
);
254 RtlFreeUnicodeString(&RemainingPath
);
258 /* If RemainingPath contains \ we must return error
259 because NtCreateKey doesn't create trees */
260 Start
= RemainingPath
.Buffer
;
264 for (i
= 1; i
< RemainingPath
.Length
/ sizeof(WCHAR
); i
++)
266 if (L
'\\' == RemainingPath
.Buffer
[i
])
268 ObDereferenceObject(Object
);
269 DPRINT1("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath
);
270 RtlFreeUnicodeString(&RemainingPath
);
271 return STATUS_OBJECT_NAME_NOT_FOUND
;
275 DPRINT("RemainingPath %S ParentObject 0x%p\n", RemainingPath
.Buffer
, Object
);
277 Status
= ObCreateObject(ExGetPreviousMode(),
286 if (!NT_SUCCESS(Status
))
288 DPRINT1("ObCreateObject() failed!\n");
292 Status
= ObInsertObject((PVOID
)KeyObject
,
298 if (!NT_SUCCESS(Status
))
300 ObDereferenceObject(KeyObject
);
301 RtlFreeUnicodeString(&RemainingPath
);
302 DPRINT1("ObInsertObject() failed!\n");
306 KeyObject
->ParentKey
= Object
;
308 if (CreateOptions
& REG_OPTION_VOLATILE
)
309 KeyObject
->RegistryHive
= CmiVolatileHive
;
311 KeyObject
->RegistryHive
= KeyObject
->ParentKey
->RegistryHive
;
313 KeyObject
->Flags
= 0;
314 KeyObject
->NumberOfSubKeys
= 0;
315 KeyObject
->SizeOfSubKeys
= 0;
316 KeyObject
->SubKeys
= NULL
;
318 /* Acquire hive lock */
319 KeEnterCriticalRegion();
320 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
322 InsertTailList(&CmiKeyObjectListHead
, &KeyObject
->ListEntry
);
324 /* add key to subkeys of parent if needed */
325 Status
= CmiAddSubKey(KeyObject
->RegistryHive
,
326 KeyObject
->ParentKey
,
332 if (!NT_SUCCESS(Status
))
334 DPRINT("CmiAddSubKey() failed (Status %lx)\n", Status
);
335 /* Release hive lock */
336 ExReleaseResourceLite(&CmiRegistryLock
);
337 KeLeaveCriticalRegion();
338 ObDereferenceObject(KeyObject
);
339 ObDereferenceObject(Object
);
340 RtlFreeUnicodeString(&RemainingPath
);
341 return STATUS_UNSUCCESSFUL
;
344 if (Start
== RemainingPath
.Buffer
)
346 KeyObject
->Name
= RemainingPath
;
350 RtlpCreateUnicodeString(&KeyObject
->Name
, Start
, NonPagedPool
);
351 RtlFreeUnicodeString(&RemainingPath
);
354 if (KeyObject
->RegistryHive
== KeyObject
->ParentKey
->RegistryHive
)
356 KeyObject
->KeyCell
->ParentKeyOffset
= KeyObject
->ParentKey
->KeyCellOffset
;
357 KeyObject
->KeyCell
->SecurityKeyOffset
= KeyObject
->ParentKey
->KeyCell
->SecurityKeyOffset
;
361 KeyObject
->KeyCell
->ParentKeyOffset
= -1;
362 KeyObject
->KeyCell
->SecurityKeyOffset
= -1;
363 /* This key must remain in memory unless it is deleted
364 or file is unloaded */
365 ObReferenceObjectByPointer(KeyObject
,
366 STANDARD_RIGHTS_REQUIRED
,
371 CmiAddKeyToList(KeyObject
->ParentKey
, KeyObject
);
373 VERIFY_KEY_OBJECT(KeyObject
);
375 /* Release hive lock */
376 ExReleaseResourceLite(&CmiRegistryLock
);
377 KeLeaveCriticalRegion();
380 ObDereferenceObject(Object
);
383 *Disposition
= REG_CREATED_NEW_KEY
;
392 NtDeleteKey(IN HANDLE KeyHandle
)
394 KPROCESSOR_MODE PreviousMode
;
395 PKEY_OBJECT KeyObject
;
400 DPRINT("NtDeleteKey(KeyHandle 0x%p) called\n", KeyHandle
);
402 PreviousMode
= ExGetPreviousMode();
404 /* Verify that the handle is valid and is a registry key */
405 Status
= ObReferenceObjectByHandle(KeyHandle
,
411 if (!NT_SUCCESS(Status
))
413 DPRINT1("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
417 /* Acquire hive lock */
418 KeEnterCriticalRegion();
419 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
421 VERIFY_KEY_OBJECT(KeyObject
);
423 /* Check for subkeys */
424 if (KeyObject
->NumberOfSubKeys
!= 0)
426 Status
= STATUS_CANNOT_DELETE
;
430 /* Set the marked for delete bit in the key object */
431 KeyObject
->Flags
|= KO_MARKED_FOR_DELETE
;
432 Status
= STATUS_SUCCESS
;
435 /* Release hive lock */
436 ExReleaseResourceLite(&CmiRegistryLock
);
437 KeLeaveCriticalRegion();
439 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
441 /* Dereference the object */
442 ObDereferenceObject(KeyObject
);
443 /* Remove the keep-alive reference */
444 ObDereferenceObject(KeyObject
);
446 if (KeyObject
->RegistryHive
!= KeyObject
->ParentKey
->RegistryHive
)
447 ObDereferenceObject(KeyObject
);
449 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
450 DPRINT("HandleCount %lu\n", ObGetObjectHandleCount((PVOID
)KeyObject
));
454 * Hive-Synchronization will not be triggered here. This is done in
455 * CmiObjectDelete() (in regobj.c) after all key-related structures
456 * have been released.
464 NtEnumerateKey(IN HANDLE KeyHandle
,
466 IN KEY_INFORMATION_CLASS KeyInformationClass
,
467 OUT PVOID KeyInformation
,
469 OUT PULONG ResultLength
)
471 PKEY_OBJECT KeyObject
;
472 PKEY_OBJECT SubKeyObject
;
473 PREGISTRY_HIVE RegistryHive
;
474 PKEY_CELL KeyCell
, SubKeyCell
;
475 PHASH_TABLE_CELL HashTableBlock
;
476 PKEY_BASIC_INFORMATION BasicInformation
;
477 PKEY_NODE_INFORMATION NodeInformation
;
478 PKEY_FULL_INFORMATION FullInformation
;
479 PDATA_CELL ClassCell
;
480 ULONG NameSize
, ClassSize
;
481 KPROCESSOR_MODE PreviousMode
;
486 PreviousMode
= ExGetPreviousMode();
488 DPRINT("KH 0x%p I %d KIC %x KI 0x%p L %d RL 0x%p\n",
496 /* Verify that the handle is valid and is a registry key */
497 Status
= ObReferenceObjectByHandle(KeyHandle
,
498 KEY_ENUMERATE_SUB_KEYS
,
501 (PVOID
*) &KeyObject
,
503 if (!NT_SUCCESS(Status
))
505 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
509 /* Acquire hive lock */
510 KeEnterCriticalRegion();
511 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
513 VERIFY_KEY_OBJECT(KeyObject
);
515 /* Get pointer to KeyCell */
516 KeyCell
= KeyObject
->KeyCell
;
517 RegistryHive
= KeyObject
->RegistryHive
;
521 /* Check for hightest possible sub key index */
522 if (Index
>= KeyCell
->NumberOfSubKeys
+ KeyObject
->NumberOfSubKeys
)
524 ExReleaseResourceLite(&CmiRegistryLock
);
525 KeLeaveCriticalRegion();
526 ObDereferenceObject(KeyObject
);
527 DPRINT("No more volatile entries\n");
528 return STATUS_NO_MORE_ENTRIES
;
531 /* Get pointer to SubKey */
532 if (Index
>= KeyCell
->NumberOfSubKeys
)
534 PKEY_OBJECT CurKey
= NULL
;
538 /* Search for volatile or 'foreign' keys */
539 j
= KeyCell
->NumberOfSubKeys
;
540 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
542 CurKey
= KeyObject
->SubKeys
[i
];
543 if (CurKey
->RegistryHive
!= RegistryHive
)
551 if (i
>= KeyObject
->NumberOfSubKeys
)
553 ExReleaseResourceLite(&CmiRegistryLock
);
554 KeLeaveCriticalRegion();
555 ObDereferenceObject(KeyObject
);
556 DPRINT("No more non-volatile entries\n");
557 return STATUS_NO_MORE_ENTRIES
;
560 SubKeyObject
= CurKey
;
561 SubKeyCell
= CurKey
->KeyCell
;
565 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
567 ExReleaseResourceLite(&CmiRegistryLock
);
568 KeLeaveCriticalRegion();
569 ObDereferenceObject(KeyObject
);
570 return STATUS_NO_MORE_ENTRIES
;
573 HashTableBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
574 if (HashTableBlock
== NULL
)
576 DPRINT("CmiGetBlock() failed\n");
577 ExReleaseResourceLite(&CmiRegistryLock
);
578 KeLeaveCriticalRegion();
579 ObDereferenceObject(KeyObject
);
580 return STATUS_UNSUCCESSFUL
;
583 SubKeyCell
= CmiGetKeyFromHashByIndex(RegistryHive
,
588 if (SubKeyCell
== NULL
)
590 ExReleaseResourceLite(&CmiRegistryLock
);
591 KeLeaveCriticalRegion();
592 ObDereferenceObject(KeyObject
);
593 DPRINT("No more entries\n");
594 return STATUS_NO_MORE_ENTRIES
;
597 Status
= STATUS_SUCCESS
;
598 switch (KeyInformationClass
)
600 case KeyBasicInformation
:
601 /* Check size of buffer */
602 if (SubKeyObject
!= NULL
)
604 NameSize
= SubKeyObject
->Name
.Length
;
608 NameSize
= SubKeyCell
->NameSize
;
609 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
611 NameSize
*= sizeof(WCHAR
);
615 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) + NameSize
;
618 * NOTE: It's perfetly valid to call NtEnumerateKey to get
619 * all the information but name. Actually the NT4 sound
620 * framework does that while querying parameters from registry.
621 * -- Filip Navara, 19/07/2004
623 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
625 Status
= STATUS_BUFFER_TOO_SMALL
;
629 /* Fill buffer with requested info */
630 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
631 BasicInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
632 BasicInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
633 BasicInformation
->TitleIndex
= Index
;
634 BasicInformation
->NameLength
= NameSize
;
636 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) < NameSize
)
638 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
639 Status
= STATUS_BUFFER_OVERFLOW
;
643 if (SubKeyObject
!= NULL
)
645 RtlCopyMemory(BasicInformation
->Name
,
646 SubKeyObject
->Name
.Buffer
,
651 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
653 CmiCopyPackedName(BasicInformation
->Name
,
655 NameSize
/ sizeof(WCHAR
));
659 RtlCopyMemory(BasicInformation
->Name
,
667 case KeyNodeInformation
:
668 /* Check size of buffer */
669 if (SubKeyObject
!= NULL
)
671 NameSize
= SubKeyObject
->Name
.Length
;
675 NameSize
= SubKeyCell
->NameSize
;
676 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
678 NameSize
*= sizeof(WCHAR
);
681 ClassSize
= SubKeyCell
->ClassSize
;
683 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
684 NameSize
+ ClassSize
;
686 if (Length
< FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]))
688 Status
= STATUS_BUFFER_TOO_SMALL
;
692 /* Fill buffer with requested info */
693 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
694 NodeInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
695 NodeInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
696 NodeInformation
->TitleIndex
= Index
;
697 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) + NameSize
;
698 NodeInformation
->ClassLength
= SubKeyCell
->ClassSize
;
699 NodeInformation
->NameLength
= NameSize
;
701 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
703 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
705 Status
= STATUS_BUFFER_OVERFLOW
;
708 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
709 NameSize
< ClassSize
)
711 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
713 Status
= STATUS_BUFFER_OVERFLOW
;
717 if (SubKeyObject
!= NULL
)
719 RtlCopyMemory(NodeInformation
->Name
,
720 SubKeyObject
->Name
.Buffer
,
725 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
727 CmiCopyPackedName(NodeInformation
->Name
,
729 NameSize
/ sizeof(WCHAR
));
733 RtlCopyMemory(NodeInformation
->Name
,
741 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
742 SubKeyCell
->ClassNameOffset
,
744 RtlCopyMemory (NodeInformation
->Name
+ SubKeyCell
->NameSize
,
751 case KeyFullInformation
:
752 ClassSize
= SubKeyCell
->ClassSize
;
754 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) +
757 /* Check size of buffer */
758 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]))
760 Status
= STATUS_BUFFER_TOO_SMALL
;
764 /* Fill buffer with requested info */
765 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
766 FullInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
767 FullInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
768 FullInformation
->TitleIndex
= Index
;
769 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) -
771 FullInformation
->ClassLength
= SubKeyCell
->ClassSize
;
772 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //SubKeyCell->NumberOfSubKeys;
773 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
774 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
775 FullInformation
->Values
= SubKeyCell
->NumberOfValues
;
776 FullInformation
->MaxValueNameLen
=
777 CmiGetMaxValueNameLength(RegistryHive
, SubKeyCell
);
778 FullInformation
->MaxValueDataLen
=
779 CmiGetMaxValueDataLength(RegistryHive
, SubKeyCell
);
781 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
783 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
784 Status
= STATUS_BUFFER_OVERFLOW
;
790 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
791 SubKeyCell
->ClassNameOffset
,
793 RtlCopyMemory (FullInformation
->Class
,
801 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
805 ExReleaseResourceLite(&CmiRegistryLock
);
806 KeLeaveCriticalRegion();
807 ObDereferenceObject(KeyObject
);
809 DPRINT("Returning status %x\n", Status
);
816 NtEnumerateValueKey(IN HANDLE KeyHandle
,
818 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
819 OUT PVOID KeyValueInformation
,
821 OUT PULONG ResultLength
)
824 PKEY_OBJECT KeyObject
;
825 PREGISTRY_HIVE RegistryHive
;
827 PVALUE_CELL ValueCell
;
829 ULONG NameSize
, DataSize
;
830 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
831 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
832 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
836 DPRINT("KH 0x%p I %d KVIC %x KVI 0x%p L %d RL 0x%p\n",
839 KeyValueInformationClass
,
844 /* Verify that the handle is valid and is a registry key */
845 Status
= ObReferenceObjectByHandle(KeyHandle
,
849 (PVOID
*) &KeyObject
,
852 if (!NT_SUCCESS(Status
))
857 /* Acquire hive lock */
858 KeEnterCriticalRegion();
859 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
861 VERIFY_KEY_OBJECT(KeyObject
);
863 /* Get pointer to KeyCell */
864 KeyCell
= KeyObject
->KeyCell
;
865 RegistryHive
= KeyObject
->RegistryHive
;
867 /* Get Value block of interest */
868 Status
= CmiGetValueFromKeyByIndex(RegistryHive
,
873 if (!NT_SUCCESS(Status
))
875 ExReleaseResourceLite(&CmiRegistryLock
);
876 KeLeaveCriticalRegion();
877 ObDereferenceObject(KeyObject
);
881 if (ValueCell
!= NULL
)
883 switch (KeyValueInformationClass
)
885 case KeyValueBasicInformation
:
886 NameSize
= ValueCell
->NameSize
;
887 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
889 NameSize
*= sizeof(WCHAR
);
892 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) + NameSize
;
894 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
896 Status
= STATUS_BUFFER_TOO_SMALL
;
900 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
902 ValueBasicInformation
->TitleIndex
= 0;
903 ValueBasicInformation
->Type
= ValueCell
->DataType
;
904 ValueBasicInformation
->NameLength
= NameSize
;
906 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
909 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
910 Status
= STATUS_BUFFER_OVERFLOW
;
914 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
916 CmiCopyPackedName(ValueBasicInformation
->Name
,
918 NameSize
/ sizeof(WCHAR
));
922 RtlCopyMemory(ValueBasicInformation
->Name
,
929 case KeyValuePartialInformation
:
930 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
932 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
935 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
937 Status
= STATUS_BUFFER_TOO_SMALL
;
941 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
943 ValuePartialInformation
->TitleIndex
= 0;
944 ValuePartialInformation
->Type
= ValueCell
->DataType
;
945 ValuePartialInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
947 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
950 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
951 Status
= STATUS_BUFFER_OVERFLOW
;
955 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
957 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
958 RtlCopyMemory(ValuePartialInformation
->Data
,
964 RtlCopyMemory(ValuePartialInformation
->Data
,
965 &ValueCell
->DataOffset
,
971 case KeyValueFullInformation
:
972 NameSize
= ValueCell
->NameSize
;
973 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
975 NameSize
*= sizeof(WCHAR
);
977 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
979 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
980 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
982 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
984 Status
= STATUS_BUFFER_TOO_SMALL
;
988 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
990 ValueFullInformation
->TitleIndex
= 0;
991 ValueFullInformation
->Type
= ValueCell
->DataType
;
992 ValueFullInformation
->NameLength
= NameSize
;
993 ValueFullInformation
->DataOffset
=
994 (ULONG_PTR
)ValueFullInformation
->Name
-
995 (ULONG_PTR
)ValueFullInformation
+
996 ValueFullInformation
->NameLength
;
997 ValueFullInformation
->DataOffset
=
998 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
999 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1001 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1004 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1006 Status
= STATUS_BUFFER_OVERFLOW
;
1009 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1010 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1012 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) - NameSize
, sizeof(PVOID
));
1013 Status
= STATUS_BUFFER_OVERFLOW
;
1017 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1019 CmiCopyPackedName(ValueFullInformation
->Name
,
1021 NameSize
/ sizeof(WCHAR
));
1025 RtlCopyMemory(ValueFullInformation
->Name
,
1030 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1032 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1033 RtlCopyMemory((PCHAR
) ValueFullInformation
1034 + ValueFullInformation
->DataOffset
,
1035 DataCell
->Data
, DataSize
);
1039 RtlCopyMemory((PCHAR
) ValueFullInformation
1040 + ValueFullInformation
->DataOffset
,
1041 &ValueCell
->DataOffset
, DataSize
);
1047 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1053 Status
= STATUS_UNSUCCESSFUL
;
1056 ExReleaseResourceLite(&CmiRegistryLock
);
1057 KeLeaveCriticalRegion();
1058 ObDereferenceObject(KeyObject
);
1065 NtFlushKey(IN HANDLE KeyHandle
)
1068 PKEY_OBJECT KeyObject
;
1069 PREGISTRY_HIVE RegistryHive
;
1070 KPROCESSOR_MODE PreviousMode
;
1074 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle
);
1076 PreviousMode
= ExGetPreviousMode();
1078 /* Verify that the handle is valid and is a registry key */
1079 Status
= ObReferenceObjectByHandle(KeyHandle
,
1083 (PVOID
*)&KeyObject
,
1085 if (!NT_SUCCESS(Status
))
1090 VERIFY_KEY_OBJECT(KeyObject
);
1092 RegistryHive
= KeyObject
->RegistryHive
;
1094 /* Acquire hive lock */
1095 KeEnterCriticalRegion();
1096 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1098 if (IsNoFileHive(RegistryHive
))
1100 Status
= STATUS_SUCCESS
;
1104 /* Flush non-volatile hive */
1105 Status
= CmiFlushRegistryHive(RegistryHive
);
1108 ExReleaseResourceLite(&CmiRegistryLock
);
1109 KeLeaveCriticalRegion();
1111 ObDereferenceObject(KeyObject
);
1113 return STATUS_SUCCESS
;
1118 NtOpenKey(OUT PHANDLE KeyHandle
,
1119 IN ACCESS_MASK DesiredAccess
,
1120 IN POBJECT_ATTRIBUTES ObjectAttributes
)
1122 UNICODE_STRING RemainingPath
;
1123 KPROCESSOR_MODE PreviousMode
;
1126 NTSTATUS Status
= STATUS_SUCCESS
;
1127 UNICODE_STRING ObjectName
;
1128 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
1132 DPRINT("NtOpenKey(KH 0x%p DA %x OA 0x%p OA->ON '%wZ'\n",
1136 ObjectAttributes
? ObjectAttributes
->ObjectName
: NULL
);
1138 /* Check place for result handle, if it's null - return immediately */
1139 if (KeyHandle
== NULL
)
1140 return(STATUS_INVALID_PARAMETER
);
1142 PreviousMode
= ExGetPreviousMode();
1144 if(PreviousMode
!= KernelMode
)
1148 ProbeForWriteHandle(KeyHandle
);
1152 Status
= _SEH_GetExceptionCode();
1156 if(!NT_SUCCESS(Status
))
1162 /* WINE checks for the length also */
1163 /*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
1164 return(STATUS_BUFFER_OVERFLOW);*/
1166 /* Capture all the info */
1167 DPRINT("Capturing Create Info\n");
1168 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
1173 if (!NT_SUCCESS(Status
))
1175 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
1179 RemainingPath
.Buffer
= NULL
;
1181 Status
= ObFindObject(&ObjectCreateInfo
,
1186 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
1187 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
1188 if (!NT_SUCCESS(Status
))
1190 DPRINT("CmpFindObject() returned 0x%08lx\n", Status
);
1191 Status
= STATUS_INVALID_HANDLE
; /* Because CmpFindObject returns STATUS_UNSUCCESSFUL */
1192 hKey
= *KeyHandle
; /* Preserve hkResult value */
1193 goto openkey_cleanup
;
1196 VERIFY_KEY_OBJECT((PKEY_OBJECT
) Object
);
1198 DPRINT("RemainingPath '%wZ'\n", &RemainingPath
);
1200 if ((RemainingPath
.Buffer
!= NULL
) && (RemainingPath
.Buffer
[0] != 0))
1202 ObDereferenceObject(Object
);
1203 RtlFreeUnicodeString(&RemainingPath
);
1204 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1206 goto openkey_cleanup
;
1209 RtlFreeUnicodeString(&RemainingPath
);
1211 /* Fail if the key has been deleted */
1212 if (((PKEY_OBJECT
)Object
)->Flags
& KO_MARKED_FOR_DELETE
)
1214 ObDereferenceObject(Object
);
1215 Status
= STATUS_UNSUCCESSFUL
;
1217 goto openkey_cleanup
;
1220 Status
= ObpCreateHandle(PsGetCurrentProcess(),
1225 ObDereferenceObject(Object
);
1227 if (!NT_SUCCESS(Status
))
1237 Status
= _SEH_GetExceptionCode();
1246 NtQueryKey(IN HANDLE KeyHandle
,
1247 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1248 OUT PVOID KeyInformation
,
1250 OUT PULONG ResultLength
)
1252 PKEY_BASIC_INFORMATION BasicInformation
;
1253 PKEY_NODE_INFORMATION NodeInformation
;
1254 PKEY_FULL_INFORMATION FullInformation
;
1255 PREGISTRY_HIVE RegistryHive
;
1256 PDATA_CELL ClassCell
;
1257 PKEY_OBJECT KeyObject
;
1259 ULONG NameSize
, ClassSize
;
1264 DPRINT("NtQueryKey(KH 0x%p KIC %x KI 0x%p L %d RL 0x%p)\n",
1266 KeyInformationClass
,
1271 /* Verify that the handle is valid and is a registry key */
1272 Status
= ObReferenceObjectByHandle(KeyHandle
,
1273 (KeyInformationClass
!= KeyNameInformation
? KEY_QUERY_VALUE
: 0),
1276 (PVOID
*) &KeyObject
,
1278 if (!NT_SUCCESS(Status
))
1283 /* Acquire hive lock */
1284 KeEnterCriticalRegion();
1285 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1287 VERIFY_KEY_OBJECT(KeyObject
);
1289 /* Get pointer to KeyCell */
1290 KeyCell
= KeyObject
->KeyCell
;
1291 RegistryHive
= KeyObject
->RegistryHive
;
1293 Status
= STATUS_SUCCESS
;
1294 switch (KeyInformationClass
)
1296 case KeyBasicInformation
:
1297 NameSize
= KeyObject
->Name
.Length
;
1299 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1301 /* Check size of buffer */
1302 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
1304 Status
= STATUS_BUFFER_TOO_SMALL
;
1308 /* Fill buffer with requested info */
1309 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
1310 BasicInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1311 BasicInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1312 BasicInformation
->TitleIndex
= 0;
1313 BasicInformation
->NameLength
= KeyObject
->Name
.Length
;
1315 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) <
1318 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1319 Status
= STATUS_BUFFER_OVERFLOW
;
1323 RtlCopyMemory(BasicInformation
->Name
,
1324 KeyObject
->Name
.Buffer
,
1329 case KeyNodeInformation
:
1330 NameSize
= KeyObject
->Name
.Length
;
1331 ClassSize
= KeyCell
->ClassSize
;
1333 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
1334 NameSize
+ ClassSize
;
1336 /* Check size of buffer */
1337 if (Length
< *ResultLength
)
1339 Status
= STATUS_BUFFER_TOO_SMALL
;
1343 /* Fill buffer with requested info */
1344 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
1345 NodeInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1346 NodeInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1347 NodeInformation
->TitleIndex
= 0;
1348 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
1349 KeyObject
->Name
.Length
;
1350 NodeInformation
->ClassLength
= KeyCell
->ClassSize
;
1351 NodeInformation
->NameLength
= KeyObject
->Name
.Length
;
1353 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
1355 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
1357 Status
= STATUS_BUFFER_OVERFLOW
;
1360 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1361 NameSize
< ClassSize
)
1363 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1365 Status
= STATUS_BUFFER_OVERFLOW
;
1369 RtlCopyMemory(NodeInformation
->Name
,
1370 KeyObject
->Name
.Buffer
,
1375 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1376 KeyCell
->ClassNameOffset
,
1378 RtlCopyMemory (NodeInformation
->Name
+ KeyObject
->Name
.Length
,
1385 case KeyFullInformation
:
1386 ClassSize
= KeyCell
->ClassSize
;
1388 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
1391 /* Check size of buffer */
1392 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
))
1394 Status
= STATUS_BUFFER_TOO_SMALL
;
1398 /* Fill buffer with requested info */
1399 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
1400 FullInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1401 FullInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1402 FullInformation
->TitleIndex
= 0;
1403 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) - sizeof(WCHAR
);
1404 FullInformation
->ClassLength
= KeyCell
->ClassSize
;
1405 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //KeyCell->NumberOfSubKeys;
1406 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
1407 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
1408 FullInformation
->Values
= KeyCell
->NumberOfValues
;
1409 FullInformation
->MaxValueNameLen
=
1410 CmiGetMaxValueNameLength(RegistryHive
, KeyCell
);
1411 FullInformation
->MaxValueDataLen
=
1412 CmiGetMaxValueDataLength(RegistryHive
, KeyCell
);
1414 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
1416 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
1417 Status
= STATUS_BUFFER_OVERFLOW
;
1423 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1424 KeyCell
->ClassNameOffset
,
1426 RtlCopyMemory (FullInformation
->Class
,
1427 ClassCell
->Data
, ClassSize
);
1432 case KeyNameInformation
:
1433 case KeyCachedInformation
:
1434 case KeyFlagsInformation
:
1435 DPRINT1("Key information class 0x%x not yet implemented!\n", KeyInformationClass
);
1436 Status
= STATUS_NOT_IMPLEMENTED
;
1440 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
1441 Status
= STATUS_INVALID_INFO_CLASS
;
1445 ExReleaseResourceLite(&CmiRegistryLock
);
1446 KeLeaveCriticalRegion();
1447 ObDereferenceObject(KeyObject
);
1454 NtQueryValueKey(IN HANDLE KeyHandle
,
1455 IN PUNICODE_STRING ValueName
,
1456 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1457 OUT PVOID KeyValueInformation
,
1459 OUT PULONG ResultLength
)
1462 ULONG NameSize
, DataSize
;
1463 PKEY_OBJECT KeyObject
;
1464 PREGISTRY_HIVE RegistryHive
;
1466 PVALUE_CELL ValueCell
;
1467 PDATA_CELL DataCell
;
1468 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
1469 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
1470 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
1474 DPRINT("NtQueryValueKey(KeyHandle 0x%p ValueName %S Length %x)\n",
1475 KeyHandle
, ValueName
->Buffer
, Length
);
1477 /* Verify that the handle is valid and is a registry key */
1478 Status
= ObReferenceObjectByHandle(KeyHandle
,
1482 (PVOID
*)&KeyObject
,
1485 if (!NT_SUCCESS(Status
))
1487 DPRINT1("ObReferenceObjectByHandle() failed with status %x\n", Status
);
1491 /* Acquire hive lock */
1492 KeEnterCriticalRegion();
1493 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1495 VERIFY_KEY_OBJECT(KeyObject
);
1497 /* Get pointer to KeyCell */
1498 KeyCell
= KeyObject
->KeyCell
;
1499 RegistryHive
= KeyObject
->RegistryHive
;
1501 /* Get value cell by name */
1502 Status
= CmiScanKeyForValue(RegistryHive
,
1507 if (!NT_SUCCESS(Status
))
1509 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
1513 Status
= STATUS_SUCCESS
;
1514 switch (KeyValueInformationClass
)
1516 case KeyValueBasicInformation
:
1517 NameSize
= ValueCell
->NameSize
;
1518 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1520 NameSize
*= sizeof(WCHAR
);
1523 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) +
1526 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1528 Status
= STATUS_BUFFER_TOO_SMALL
;
1532 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1533 KeyValueInformation
;
1534 ValueBasicInformation
->TitleIndex
= 0;
1535 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1536 ValueBasicInformation
->NameLength
= NameSize
;
1538 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1541 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1542 Status
= STATUS_BUFFER_OVERFLOW
;
1546 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1548 CmiCopyPackedName(ValueBasicInformation
->Name
,
1550 NameSize
/ sizeof(WCHAR
));
1554 RtlCopyMemory(ValueBasicInformation
->Name
,
1561 case KeyValuePartialInformation
:
1562 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1564 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1567 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1569 Status
= STATUS_BUFFER_TOO_SMALL
;
1573 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1574 KeyValueInformation
;
1575 ValuePartialInformation
->TitleIndex
= 0;
1576 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1577 ValuePartialInformation
->DataLength
= DataSize
;
1579 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1582 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1583 Status
= STATUS_BUFFER_OVERFLOW
;
1587 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1589 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1590 RtlCopyMemory(ValuePartialInformation
->Data
,
1596 RtlCopyMemory(ValuePartialInformation
->Data
,
1597 &ValueCell
->DataOffset
,
1603 case KeyValueFullInformation
:
1604 NameSize
= ValueCell
->NameSize
;
1605 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1607 NameSize
*= sizeof(WCHAR
);
1609 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1611 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1612 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1614 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1616 Status
= STATUS_BUFFER_TOO_SMALL
;
1620 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1621 KeyValueInformation
;
1622 ValueFullInformation
->TitleIndex
= 0;
1623 ValueFullInformation
->Type
= ValueCell
->DataType
;
1624 ValueFullInformation
->NameLength
= NameSize
;
1625 ValueFullInformation
->DataOffset
=
1626 (ULONG_PTR
)ValueFullInformation
->Name
-
1627 (ULONG_PTR
)ValueFullInformation
+
1628 ValueFullInformation
->NameLength
;
1629 ValueFullInformation
->DataOffset
=
1630 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1631 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1633 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1636 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1638 Status
= STATUS_BUFFER_OVERFLOW
;
1641 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1642 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1644 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1645 Name
[0]) - NameSize
, sizeof(PVOID
));
1646 Status
= STATUS_BUFFER_OVERFLOW
;
1650 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1652 CmiCopyPackedName(ValueFullInformation
->Name
,
1654 NameSize
/ sizeof(WCHAR
));
1658 RtlCopyMemory(ValueFullInformation
->Name
,
1662 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1664 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1665 RtlCopyMemory((PCHAR
) ValueFullInformation
1666 + ValueFullInformation
->DataOffset
,
1672 RtlCopyMemory((PCHAR
) ValueFullInformation
1673 + ValueFullInformation
->DataOffset
,
1674 &ValueCell
->DataOffset
,
1681 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1682 Status
= STATUS_INVALID_INFO_CLASS
;
1687 ExReleaseResourceLite(&CmiRegistryLock
);
1688 KeLeaveCriticalRegion();
1689 ObDereferenceObject(KeyObject
);
1696 NtSetValueKey(IN HANDLE KeyHandle
,
1697 IN PUNICODE_STRING ValueName
,
1698 IN ULONG TitleIndex
,
1704 PKEY_OBJECT KeyObject
;
1705 PREGISTRY_HIVE RegistryHive
;
1707 PVALUE_CELL ValueCell
;
1708 BLOCK_OFFSET ValueCellOffset
;
1709 PDATA_CELL DataCell
;
1710 PDATA_CELL NewDataCell
;
1712 ULONG DesiredAccess
;
1716 DPRINT("NtSetValueKey(KeyHandle 0x%p ValueName '%wZ' Type %d)\n",
1717 KeyHandle
, ValueName
, Type
);
1719 DesiredAccess
= KEY_SET_VALUE
;
1721 /* Verify that the handle is valid and is a registry key */
1722 Status
= ObReferenceObjectByHandle(KeyHandle
,
1725 ExGetPreviousMode(),
1726 (PVOID
*)&KeyObject
,
1728 if (!NT_SUCCESS(Status
))
1731 /* Acquire hive lock exclucively */
1732 KeEnterCriticalRegion();
1733 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1735 VERIFY_KEY_OBJECT(KeyObject
);
1737 /* Get pointer to key cell */
1738 KeyCell
= KeyObject
->KeyCell
;
1739 RegistryHive
= KeyObject
->RegistryHive
;
1740 Status
= CmiScanKeyForValue(RegistryHive
,
1745 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1747 DPRINT("Allocate new value cell\n");
1748 Status
= CmiAddValueToKey(RegistryHive
,
1750 KeyObject
->KeyCellOffset
,
1756 if (!NT_SUCCESS(Status
))
1758 DPRINT("Cannot add value. Status 0x%X\n", Status
);
1760 ExReleaseResourceLite(&CmiRegistryLock
);
1761 KeLeaveCriticalRegion();
1762 ObDereferenceObject(KeyObject
);
1766 DPRINT("DataSize %lu\n", DataSize
);
1767 DPRINT("ValueCell %p\n", ValueCell
);
1768 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1770 if (DataSize
<= sizeof(BLOCK_OFFSET
))
1772 /* If data size <= sizeof(BLOCK_OFFSET) then store data in the data offset */
1773 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1774 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1775 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1777 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1778 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
1781 RtlCopyMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
1782 ValueCell
->DataSize
= DataSize
| REG_DATA_IN_OFFSET
;
1783 ValueCell
->DataType
= Type
;
1784 RtlMoveMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
1785 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
1787 else if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1788 (DataSize
<= (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
1790 /* If new data size is <= current then overwrite current data */
1791 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
,&pBin
);
1792 RtlZeroMemory(DataCell
->Data
, ValueCell
->DataSize
);
1793 RtlCopyMemory(DataCell
->Data
, Data
, DataSize
);
1794 ValueCell
->DataSize
= DataSize
;
1795 ValueCell
->DataType
= Type
;
1800 * New data size is larger than the current, destroy current
1801 * data block and allocate a new one.
1803 BLOCK_OFFSET NewOffset
;
1805 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1807 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1808 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1810 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1811 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
1812 ValueCell
->DataSize
= 0;
1813 ValueCell
->DataType
= 0;
1814 ValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
1817 Status
= CmiAllocateCell (RegistryHive
,
1818 sizeof(CELL_HEADER
) + DataSize
,
1819 (PVOID
*)&NewDataCell
,
1821 if (!NT_SUCCESS(Status
))
1823 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status
);
1825 ExReleaseResourceLite(&CmiRegistryLock
);
1826 KeLeaveCriticalRegion();
1827 ObDereferenceObject(KeyObject
);
1832 RtlCopyMemory(&NewDataCell
->Data
[0], Data
, DataSize
);
1833 ValueCell
->DataSize
= DataSize
& REG_DATA_SIZE_MASK
;
1834 ValueCell
->DataType
= Type
;
1835 ValueCell
->DataOffset
= NewOffset
;
1836 CmiMarkBlockDirty(RegistryHive
, ValueCell
->DataOffset
);
1837 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
1841 if ((Type
== REG_LINK
) &&
1842 (_wcsicmp(ValueName
->Buffer
, L
"SymbolicLinkValue") == 0))
1844 KeyCell
->Flags
|= REG_KEY_LINK_CELL
;
1847 KeQuerySystemTime (&KeyCell
->LastWriteTime
);
1848 CmiMarkBlockDirty (RegistryHive
, KeyObject
->KeyCellOffset
);
1850 ExReleaseResourceLite(&CmiRegistryLock
);
1851 KeLeaveCriticalRegion();
1852 ObDereferenceObject(KeyObject
);
1856 DPRINT("Return Status 0x%X\n", Status
);
1863 NtDeleteValueKey (IN HANDLE KeyHandle
,
1864 IN PUNICODE_STRING ValueName
)
1866 PKEY_OBJECT KeyObject
;
1871 /* Verify that the handle is valid and is a registry key */
1872 Status
= ObReferenceObjectByHandle(KeyHandle
,
1876 (PVOID
*)&KeyObject
,
1878 if (!NT_SUCCESS(Status
))
1883 /* Acquire hive lock */
1884 KeEnterCriticalRegion();
1885 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1887 VERIFY_KEY_OBJECT(KeyObject
);
1889 Status
= CmiDeleteValueFromKey(KeyObject
->RegistryHive
,
1891 KeyObject
->KeyCellOffset
,
1894 KeQuerySystemTime (&KeyObject
->KeyCell
->LastWriteTime
);
1895 CmiMarkBlockDirty (KeyObject
->RegistryHive
, KeyObject
->KeyCellOffset
);
1897 /* Release hive lock */
1898 ExReleaseResourceLite(&CmiRegistryLock
);
1899 KeLeaveCriticalRegion();
1901 ObDereferenceObject (KeyObject
);
1911 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1912 * KeyObjectAttributes->Name specifies the name of the key to load.
1915 NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1916 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
1918 return NtLoadKey2 (KeyObjectAttributes
,
1919 FileObjectAttributes
,
1926 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1927 * KeyObjectAttributes->Name specifies the name of the key to load.
1928 * Flags can be 0 or REG_NO_LAZY_FLUSH.
1931 NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1932 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
1935 POBJECT_NAME_INFORMATION NameInfo
;
1936 PUNICODE_STRING NamePointer
;
1944 DPRINT ("NtLoadKey2() called\n");
1947 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, KeGetPreviousMode ()))
1948 return STATUS_PRIVILEGE_NOT_HELD
;
1951 if (FileObjectAttributes
->RootDirectory
!= NULL
)
1954 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1955 Buffer
= ExAllocatePool (NonPagedPool
,
1958 return STATUS_INSUFFICIENT_RESOURCES
;
1960 Status
= ZwQueryObject (FileObjectAttributes
->RootDirectory
,
1961 ObjectNameInformation
,
1965 if (!NT_SUCCESS(Status
))
1967 DPRINT1 ("NtQueryObject() failed (Status %lx)\n", Status
);
1968 ExFreePool (Buffer
);
1972 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
1973 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
1974 &NameInfo
->Name
, NameInfo
->Name
.Length
);
1976 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
1977 if (FileObjectAttributes
->ObjectName
->Buffer
[0] != L
'\\')
1979 RtlAppendUnicodeToString (&NameInfo
->Name
,
1981 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
1982 &NameInfo
->Name
, NameInfo
->Name
.Length
);
1984 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
1985 FileObjectAttributes
->ObjectName
);
1987 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
1988 &NameInfo
->Name
, NameInfo
->Name
.Length
);
1989 NamePointer
= &NameInfo
->Name
;
1993 if (FileObjectAttributes
->ObjectName
->Buffer
[0] == L
'\\')
1996 NamePointer
= FileObjectAttributes
->ObjectName
;
2001 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2002 Buffer
= ExAllocatePool (NonPagedPool
,
2005 return STATUS_INSUFFICIENT_RESOURCES
;
2007 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2008 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2009 NameInfo
->Name
.Length
= 0;
2010 NameInfo
->Name
.Buffer
= (PWSTR
)((ULONG_PTR
)Buffer
+ sizeof(OBJECT_NAME_INFORMATION
));
2011 NameInfo
->Name
.Buffer
[0] = 0;
2013 RtlAppendUnicodeToString (&NameInfo
->Name
,
2015 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2016 FileObjectAttributes
->ObjectName
);
2018 NamePointer
= &NameInfo
->Name
;
2022 DPRINT ("Full name: '%wZ'\n", NamePointer
);
2024 /* Acquire hive lock */
2025 KeEnterCriticalRegion();
2026 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2028 Status
= CmiLoadHive (KeyObjectAttributes
,
2031 if (!NT_SUCCESS (Status
))
2033 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
2036 /* Release hive lock */
2037 ExReleaseResourceLite(&CmiRegistryLock
);
2038 KeLeaveCriticalRegion();
2041 ExFreePool (Buffer
);
2048 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2050 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2051 IN PVOID ApcContext OPTIONAL
,
2052 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2053 IN ULONG CompletionFilter
,
2054 IN BOOLEAN WatchSubtree
,
2057 IN BOOLEAN Asynchronous
)
2060 return(STATUS_NOT_IMPLEMENTED
);
2065 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2067 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2068 IN PVOID ApcContext OPTIONAL
,
2069 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2070 IN ULONG CompletionFilter
,
2071 IN BOOLEAN WatchSubtree
,
2074 IN BOOLEAN Asynchronous
)
2076 return NtNotifyChangeMultipleKeys(KeyHandle
,
2093 NtQueryMultipleValueKey (IN HANDLE KeyHandle
,
2094 IN OUT PKEY_VALUE_ENTRY ValueList
,
2095 IN ULONG NumberOfValues
,
2097 IN OUT PULONG Length
,
2098 OUT PULONG ReturnLength
)
2100 PREGISTRY_HIVE RegistryHive
;
2101 PVALUE_CELL ValueCell
;
2102 PKEY_OBJECT KeyObject
;
2103 PDATA_CELL DataCell
;
2104 ULONG BufferLength
= 0;
2112 /* Verify that the handle is valid and is a registry key */
2113 Status
= ObReferenceObjectByHandle(KeyHandle
,
2117 (PVOID
*) &KeyObject
,
2119 if (!NT_SUCCESS(Status
))
2121 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2125 /* Acquire hive lock */
2126 KeEnterCriticalRegion();
2127 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
2129 VERIFY_KEY_OBJECT(KeyObject
);
2131 /* Get pointer to KeyCell */
2132 KeyCell
= KeyObject
->KeyCell
;
2133 RegistryHive
= KeyObject
->RegistryHive
;
2135 DataPtr
= (PUCHAR
) Buffer
;
2137 for (i
= 0; i
< NumberOfValues
; i
++)
2139 DPRINT("ValueName: '%wZ'\n", ValueList
[i
].ValueName
);
2141 /* Get Value block of interest */
2142 Status
= CmiScanKeyForValue(RegistryHive
,
2144 ValueList
[i
].ValueName
,
2148 if (!NT_SUCCESS(Status
))
2150 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
2153 else if (ValueCell
== NULL
)
2155 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
2159 BufferLength
= ROUND_UP(BufferLength
, sizeof(PVOID
));
2161 if (BufferLength
+ (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) <= *Length
)
2163 DataPtr
= (PUCHAR
)ROUND_UP((ULONG_PTR
)DataPtr
, sizeof(PVOID
));
2165 ValueList
[i
].Type
= ValueCell
->DataType
;
2166 ValueList
[i
].DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2167 ValueList
[i
].DataOffset
= (ULONG_PTR
)DataPtr
- (ULONG_PTR
)Buffer
;
2169 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
2171 DataCell
= CmiGetCell (RegistryHive
,
2172 ValueCell
->DataOffset
,
2174 RtlCopyMemory(DataPtr
,
2176 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2180 RtlCopyMemory(DataPtr
,
2181 &ValueCell
->DataOffset
,
2182 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2185 DataPtr
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2189 Status
= STATUS_BUFFER_TOO_SMALL
;
2192 BufferLength
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2195 if (NT_SUCCESS(Status
))
2196 *Length
= BufferLength
;
2198 *ReturnLength
= BufferLength
;
2200 /* Release hive lock */
2201 ExReleaseResourceLite(&CmiRegistryLock
);
2202 KeLeaveCriticalRegion();
2204 ObDereferenceObject(KeyObject
);
2206 DPRINT("Return Status 0x%X\n", Status
);
2213 NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes
,
2215 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
2218 return(STATUS_NOT_IMPLEMENTED
);
2223 NtRestoreKey (IN HANDLE KeyHandle
,
2224 IN HANDLE FileHandle
,
2225 IN ULONG RestoreFlags
)
2228 return(STATUS_NOT_IMPLEMENTED
);
2233 NtSaveKey (IN HANDLE KeyHandle
,
2234 IN HANDLE FileHandle
)
2236 PREGISTRY_HIVE TempHive
;
2237 PKEY_OBJECT KeyObject
;
2242 DPRINT ("NtSaveKey() called\n");
2245 if (!SeSinglePrivilegeCheck (SeBackupPrivilege
, KeGetPreviousMode ()))
2246 return STATUS_PRIVILEGE_NOT_HELD
;
2249 Status
= ObReferenceObjectByHandle (KeyHandle
,
2252 KeGetPreviousMode(),
2253 (PVOID
*)&KeyObject
,
2255 if (!NT_SUCCESS(Status
))
2257 DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
2261 /* Acquire hive lock exclucively */
2262 KeEnterCriticalRegion();
2263 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2265 /* Refuse to save a volatile key */
2266 if (KeyObject
->RegistryHive
== CmiVolatileHive
)
2268 DPRINT1 ("Cannot save a volatile key\n");
2269 ExReleaseResourceLite(&CmiRegistryLock
);
2270 KeLeaveCriticalRegion();
2271 ObDereferenceObject (KeyObject
);
2272 return STATUS_ACCESS_DENIED
;
2275 Status
= CmiCreateTempHive(&TempHive
);
2276 if (!NT_SUCCESS(Status
))
2278 DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status
);
2279 ExReleaseResourceLite(&CmiRegistryLock
);
2280 KeLeaveCriticalRegion();
2281 ObDereferenceObject (KeyObject
);
2285 Status
= CmiCopyKey (TempHive
,
2287 KeyObject
->RegistryHive
,
2288 KeyObject
->KeyCell
);
2289 if (!NT_SUCCESS(Status
))
2291 DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status
);
2292 CmiRemoveRegistryHive (TempHive
);
2293 ExReleaseResourceLite(&CmiRegistryLock
);
2294 KeLeaveCriticalRegion();
2295 ObDereferenceObject (KeyObject
);
2299 Status
= CmiSaveTempHive (TempHive
,
2301 if (!NT_SUCCESS(Status
))
2303 DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status
);
2306 CmiRemoveRegistryHive (TempHive
);
2308 /* Release hive lock */
2309 ExReleaseResourceLite(&CmiRegistryLock
);
2310 KeLeaveCriticalRegion();
2312 ObDereferenceObject (KeyObject
);
2314 DPRINT ("NtSaveKey() done\n");
2316 return STATUS_SUCCESS
;
2325 IN HANDLE KeyHandle
,
2326 IN HANDLE FileHandle
,
2327 IN ULONG Flags
// REG_STANDARD_FORMAT, etc..
2331 return STATUS_NOT_IMPLEMENTED
;
2336 NtSetInformationKey (IN HANDLE KeyHandle
,
2337 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
2338 IN PVOID KeyInformation
,
2339 IN ULONG KeyInformationLength
)
2341 PKEY_OBJECT KeyObject
;
2346 if (KeyInformationClass
!= KeyWriteTimeInformation
)
2347 return STATUS_INVALID_INFO_CLASS
;
2349 if (KeyInformationLength
!= sizeof (KEY_WRITE_TIME_INFORMATION
))
2350 return STATUS_INFO_LENGTH_MISMATCH
;
2352 /* Verify that the handle is valid and is a registry key */
2353 Status
= ObReferenceObjectByHandle (KeyHandle
,
2357 (PVOID
*)&KeyObject
,
2359 if (!NT_SUCCESS (Status
))
2361 DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2365 /* Acquire hive lock */
2366 KeEnterCriticalRegion();
2367 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2369 VERIFY_KEY_OBJECT(KeyObject
);
2371 KeyObject
->KeyCell
->LastWriteTime
.QuadPart
=
2372 ((PKEY_WRITE_TIME_INFORMATION
)KeyInformation
)->LastWriteTime
.QuadPart
;
2374 CmiMarkBlockDirty (KeyObject
->RegistryHive
,
2375 KeyObject
->KeyCellOffset
);
2377 /* Release hive lock */
2378 ExReleaseResourceLite(&CmiRegistryLock
);
2379 KeLeaveCriticalRegion();
2381 ObDereferenceObject (KeyObject
);
2385 DPRINT ("NtSaveKey() done\n");
2387 return STATUS_SUCCESS
;
2393 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2394 * KeyObjectAttributes->Name specifies the name of the key to unload.
2397 NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
2399 PREGISTRY_HIVE RegistryHive
;
2404 DPRINT ("NtUnloadKey() called\n");
2407 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, KeGetPreviousMode ()))
2408 return STATUS_PRIVILEGE_NOT_HELD
;
2411 /* Acquire registry lock exclusively */
2412 KeEnterCriticalRegion();
2413 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2415 Status
= CmiDisconnectHive (KeyObjectAttributes
,
2417 if (!NT_SUCCESS (Status
))
2419 DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status
);
2420 ExReleaseResourceLite (&CmiRegistryLock
);
2421 KeLeaveCriticalRegion();
2425 DPRINT ("RegistryHive %p\n", RegistryHive
);
2429 if (!IsNoFileHive (RegistryHive
))
2430 CmiFlushRegistryHive (RegistryHive
);
2433 CmiRemoveRegistryHive (RegistryHive
);
2435 /* Release registry lock */
2436 ExReleaseResourceLite (&CmiRegistryLock
);
2437 KeLeaveCriticalRegion();
2439 DPRINT ("NtUnloadKey() done\n");
2441 return STATUS_SUCCESS
;
2446 NtInitializeRegistry (IN BOOLEAN SetUpBoot
)
2452 if (CmiRegistryInitialized
== TRUE
)
2453 return STATUS_ACCESS_DENIED
;
2455 /* Save boot log file */
2456 IopSaveBootLogToFile();
2458 Status
= CmiInitHives (SetUpBoot
);
2460 CmiRegistryInitialized
= TRUE
;