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 ****************************************************************/
33 /* TEMPORARY HACK UNTIL PROPER PARSE ROUTINES SOON. DO NOT REMOVE -- Alex */
35 CmpFindObject(POBJECT_ATTRIBUTES ObjectAttributes
,
36 PVOID
* ReturnedObject
,
37 PUNICODE_STRING RemainingPath
,
38 POBJECT_TYPE ObjectType
)
43 POBJECT_HEADER CurrentHeader
;
46 UNICODE_STRING PathString
;
48 PUNICODE_STRING ObjectName
;
52 DPRINT("CmpFindObject(ObjectAttributes %x, ReturnedObject %x, "
53 "RemainingPath %x)\n",ObjectAttributes
,ReturnedObject
,RemainingPath
);
54 DPRINT("ObjectAttributes->ObjectName %wZ\n",
55 ObjectAttributes
->ObjectName
);
57 RtlInitUnicodeString (RemainingPath
, NULL
);
59 if (ObjectAttributes
->RootDirectory
== NULL
)
61 ObReferenceObjectByPointer(NameSpaceRoot
,
65 CurrentObject
= NameSpaceRoot
;
69 Status
= ObReferenceObjectByHandle(ObjectAttributes
->RootDirectory
,
75 if (!NT_SUCCESS(Status
))
81 ObjectName
= ObjectAttributes
->ObjectName
;
82 if (ObjectName
->Length
== 0 ||
83 ObjectName
->Buffer
[0] == UNICODE_NULL
)
85 *ReturnedObject
= CurrentObject
;
86 return STATUS_SUCCESS
;
89 if (ObjectAttributes
->RootDirectory
== NULL
&&
90 ObjectName
->Buffer
[0] != L
'\\')
92 ObDereferenceObject (CurrentObject
);
93 return STATUS_UNSUCCESSFUL
;
96 /* Create a zero-terminated copy of the object name */
97 PathString
.Length
= ObjectName
->Length
;
98 PathString
.MaximumLength
= ObjectName
->Length
+ sizeof(WCHAR
);
99 PathString
.Buffer
= ExAllocatePool (NonPagedPool
,
100 PathString
.MaximumLength
);
101 if (PathString
.Buffer
== NULL
)
103 ObDereferenceObject (CurrentObject
);
104 return STATUS_INSUFFICIENT_RESOURCES
;
107 RtlCopyMemory (PathString
.Buffer
,
110 PathString
.Buffer
[PathString
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
112 current
= PathString
.Buffer
;
114 RootObject
= CurrentObject
;
115 Attributes
= ObjectAttributes
->Attributes
;
116 if (ObjectType
== ObSymbolicLinkType
)
117 Attributes
|= OBJ_OPENLINK
;
121 DPRINT("current %S\n",current
);
122 CurrentHeader
= BODY_TO_HEADER(CurrentObject
);
124 DPRINT("Current ObjectType %wZ\n",
125 &CurrentHeader
->Type
->TypeName
);
127 if (CurrentHeader
->Type
->TypeInfo
.ParseProcedure
== NULL
)
129 DPRINT("Current object can't parse\n");
132 Status
= CurrentHeader
->Type
->TypeInfo
.ParseProcedure(CurrentObject
,
137 if (Status
== STATUS_REPARSE
)
139 /* reparse the object path */
140 NextObject
= NameSpaceRoot
;
141 current
= PathString
.Buffer
;
143 ObReferenceObjectByPointer(NextObject
,
149 if (NextObject
== NULL
)
153 ObDereferenceObject(CurrentObject
);
154 CurrentObject
= NextObject
;
158 RtlpCreateUnicodeString (RemainingPath
, current
, NonPagedPool
);
159 RtlFreeUnicodeString (&PathString
);
160 *ReturnedObject
= CurrentObject
;
162 return STATUS_SUCCESS
;
169 CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function
,
171 IN OUT PLARGE_INTEGER Cookie
)
173 PREGISTRY_CALLBACK Callback
;
177 ASSERT(Function
&& Cookie
);
179 Callback
= ExAllocatePoolWithTag(PagedPool
,
180 sizeof(REGISTRY_CALLBACK
),
181 TAG('C', 'M', 'c', 'b'));
184 /* initialize the callback */
185 ExInitializeRundownProtection(&Callback
->RundownRef
);
186 Callback
->Function
= Function
;
187 Callback
->Context
= Context
;
188 Callback
->PendingDelete
= FALSE
;
190 /* add it to the callback list and receive a cookie for the callback */
191 ExAcquireFastMutex(&CmiCallbackLock
);
192 /* FIXME - to receive a unique cookie we'll just return the pointer to the
194 Callback
->Cookie
.QuadPart
= (ULONG_PTR
)Callback
;
195 InsertTailList(&CmiCallbackHead
, &Callback
->ListEntry
);
197 ExReleaseFastMutex(&CmiCallbackLock
);
199 *Cookie
= Callback
->Cookie
;
200 return STATUS_SUCCESS
;
203 return STATUS_INSUFFICIENT_RESOURCES
;
211 CmUnRegisterCallback(IN LARGE_INTEGER Cookie
)
213 PLIST_ENTRY CurrentEntry
;
217 ExAcquireFastMutex(&CmiCallbackLock
);
219 for(CurrentEntry
= CmiCallbackHead
.Flink
;
220 CurrentEntry
!= &CmiCallbackHead
;
221 CurrentEntry
= CurrentEntry
->Flink
)
223 PREGISTRY_CALLBACK CurrentCallback
;
225 CurrentCallback
= CONTAINING_RECORD(CurrentEntry
, REGISTRY_CALLBACK
, ListEntry
);
226 if(CurrentCallback
->Cookie
.QuadPart
== Cookie
.QuadPart
)
228 if(!CurrentCallback
->PendingDelete
)
230 /* found the callback, don't unlink it from the list yet so we don't screw
232 CurrentCallback
->PendingDelete
= TRUE
;
233 ExReleaseFastMutex(&CmiCallbackLock
);
235 /* if the callback is currently executing, wait until it finished */
236 ExWaitForRundownProtectionRelease(&CurrentCallback
->RundownRef
);
238 /* time to unlink it. It's now safe because every attempt to acquire a
239 runtime protection on this callback will fail */
240 ExAcquireFastMutex(&CmiCallbackLock
);
241 RemoveEntryList(&CurrentCallback
->ListEntry
);
242 ExReleaseFastMutex(&CmiCallbackLock
);
244 /* free the callback */
245 ExFreePool(CurrentCallback
);
246 return STATUS_SUCCESS
;
250 /* pending delete, pretend like it already is deleted */
251 ExReleaseFastMutex(&CmiCallbackLock
);
252 return STATUS_UNSUCCESSFUL
;
257 ExReleaseFastMutex(&CmiCallbackLock
);
259 return STATUS_UNSUCCESSFUL
;
264 CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1
,
267 PLIST_ENTRY CurrentEntry
;
271 ExAcquireFastMutex(&CmiCallbackLock
);
273 for(CurrentEntry
= CmiCallbackHead
.Flink
;
274 CurrentEntry
!= &CmiCallbackHead
;
275 CurrentEntry
= CurrentEntry
->Flink
)
277 PREGISTRY_CALLBACK CurrentCallback
;
279 CurrentCallback
= CONTAINING_RECORD(CurrentEntry
, REGISTRY_CALLBACK
, ListEntry
);
280 if(!CurrentCallback
->PendingDelete
&&
281 ExAcquireRundownProtectionEx(&CurrentCallback
->RundownRef
, 1))
285 /* don't hold locks during the callbacks! */
286 ExReleaseFastMutex(&CmiCallbackLock
);
288 Status
= CurrentCallback
->Function(CurrentCallback
->Context
,
291 if(!NT_SUCCESS(Status
))
293 /* one callback returned failure, don't call any more callbacks */
297 ExAcquireFastMutex(&CmiCallbackLock
);
298 /* don't release the rundown protection before holding the callback lock
299 so the pointer to the next callback isn't cleared in case this callback
301 ExReleaseRundownProtectionEx(&CurrentCallback
->RundownRef
, 1);
305 ExReleaseFastMutex(&CmiCallbackLock
);
307 return STATUS_SUCCESS
;
312 NtCreateKey(OUT PHANDLE KeyHandle
,
313 IN ACCESS_MASK DesiredAccess
,
314 IN POBJECT_ATTRIBUTES ObjectAttributes
,
316 IN PUNICODE_STRING Class
,
317 IN ULONG CreateOptions
,
318 OUT PULONG Disposition
)
320 UNICODE_STRING RemainingPath
;
321 PKEY_OBJECT KeyObject
;
329 DPRINT("NtCreateKey (Name %wZ KeyHandle %x Root %x)\n",
330 ObjectAttributes
->ObjectName
,
332 ObjectAttributes
->RootDirectory
);
334 Status
= CmpFindObject(ObjectAttributes
,
338 if (!NT_SUCCESS(Status
))
340 DPRINT("CmpFindObject failed, Status: 0x%x\n", Status
);
344 DPRINT("RemainingPath %wZ\n", &RemainingPath
);
346 if (RemainingPath
.Length
== 0)
348 /* Fail if the key has been deleted */
349 if (((PKEY_OBJECT
) Object
)->Flags
& KO_MARKED_FOR_DELETE
)
351 ObDereferenceObject(Object
);
352 RtlFreeUnicodeString(&RemainingPath
);
353 DPRINT("Object marked for delete!\n");
354 return(STATUS_UNSUCCESSFUL
);
358 *Disposition
= REG_OPENED_EXISTING_KEY
;
360 Status
= ObpCreateHandle(PsGetCurrentProcess(),
366 DPRINT("ObpCreateHandle failed Status 0x%x\n", Status
);
367 ObDereferenceObject(Object
);
368 RtlFreeUnicodeString(&RemainingPath
);
372 /* If RemainingPath contains \ we must return error
373 because NtCreateKey doesn't create trees */
374 Start
= RemainingPath
.Buffer
;
378 for (i
= 1; i
< RemainingPath
.Length
/ sizeof(WCHAR
); i
++)
380 if (L
'\\' == RemainingPath
.Buffer
[i
])
382 ObDereferenceObject(Object
);
383 DPRINT1("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath
);
384 RtlFreeUnicodeString(&RemainingPath
);
385 return STATUS_OBJECT_NAME_NOT_FOUND
;
389 DPRINT("RemainingPath %S ParentObject %x\n", RemainingPath
.Buffer
, Object
);
391 Status
= ObCreateObject(ExGetPreviousMode(),
400 if (!NT_SUCCESS(Status
))
402 DPRINT1("ObCreateObject() failed!\n");
406 Status
= ObInsertObject((PVOID
)KeyObject
,
412 if (!NT_SUCCESS(Status
))
414 ObDereferenceObject(KeyObject
);
415 RtlFreeUnicodeString(&RemainingPath
);
416 DPRINT1("ObInsertObject() failed!\n");
420 KeyObject
->ParentKey
= Object
;
422 if (CreateOptions
& REG_OPTION_VOLATILE
)
423 KeyObject
->RegistryHive
= CmiVolatileHive
;
425 KeyObject
->RegistryHive
= KeyObject
->ParentKey
->RegistryHive
;
427 KeyObject
->Flags
= 0;
428 KeyObject
->NumberOfSubKeys
= 0;
429 KeyObject
->SizeOfSubKeys
= 0;
430 KeyObject
->SubKeys
= NULL
;
432 /* Acquire hive lock */
433 KeEnterCriticalRegion();
434 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
436 InsertTailList(&CmiKeyObjectListHead
, &KeyObject
->ListEntry
);
438 /* add key to subkeys of parent if needed */
439 Status
= CmiAddSubKey(KeyObject
->RegistryHive
,
440 KeyObject
->ParentKey
,
446 if (!NT_SUCCESS(Status
))
448 DPRINT("CmiAddSubKey() failed (Status %lx)\n", Status
);
449 /* Release hive lock */
450 ExReleaseResourceLite(&CmiRegistryLock
);
451 KeLeaveCriticalRegion();
452 ObDereferenceObject(KeyObject
);
453 ObDereferenceObject(Object
);
454 RtlFreeUnicodeString(&RemainingPath
);
455 return STATUS_UNSUCCESSFUL
;
458 if (Start
== RemainingPath
.Buffer
)
460 KeyObject
->Name
= RemainingPath
;
464 RtlpCreateUnicodeString(&KeyObject
->Name
, Start
, NonPagedPool
);
465 RtlFreeUnicodeString(&RemainingPath
);
468 if (KeyObject
->RegistryHive
== KeyObject
->ParentKey
->RegistryHive
)
470 KeyObject
->KeyCell
->ParentKeyOffset
= KeyObject
->ParentKey
->KeyCellOffset
;
471 KeyObject
->KeyCell
->SecurityKeyOffset
= KeyObject
->ParentKey
->KeyCell
->SecurityKeyOffset
;
475 KeyObject
->KeyCell
->ParentKeyOffset
= -1;
476 KeyObject
->KeyCell
->SecurityKeyOffset
= -1;
477 /* This key must remain in memory unless it is deleted
478 or file is unloaded */
479 ObReferenceObjectByPointer(KeyObject
,
480 STANDARD_RIGHTS_REQUIRED
,
485 CmiAddKeyToList(KeyObject
->ParentKey
, KeyObject
);
487 VERIFY_KEY_OBJECT(KeyObject
);
489 /* Release hive lock */
490 ExReleaseResourceLite(&CmiRegistryLock
);
491 KeLeaveCriticalRegion();
494 ObDereferenceObject(Object
);
497 *Disposition
= REG_CREATED_NEW_KEY
;
506 NtDeleteKey(IN HANDLE KeyHandle
)
508 KPROCESSOR_MODE PreviousMode
;
509 PKEY_OBJECT KeyObject
;
514 DPRINT("NtDeleteKey(KeyHandle %x) called\n", KeyHandle
);
516 PreviousMode
= ExGetPreviousMode();
518 /* Verify that the handle is valid and is a registry key */
519 Status
= ObReferenceObjectByHandle(KeyHandle
,
525 if (!NT_SUCCESS(Status
))
527 DPRINT1("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
531 /* Acquire hive lock */
532 KeEnterCriticalRegion();
533 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
535 VERIFY_KEY_OBJECT(KeyObject
);
537 /* Check for subkeys */
538 if (KeyObject
->NumberOfSubKeys
!= 0)
540 Status
= STATUS_CANNOT_DELETE
;
544 /* Set the marked for delete bit in the key object */
545 KeyObject
->Flags
|= KO_MARKED_FOR_DELETE
;
546 Status
= STATUS_SUCCESS
;
549 /* Release hive lock */
550 ExReleaseResourceLite(&CmiRegistryLock
);
551 KeLeaveCriticalRegion();
553 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
555 /* Dereference the object */
556 ObDereferenceObject(KeyObject
);
557 /* Remove the keep-alive reference */
558 ObDereferenceObject(KeyObject
);
560 if (KeyObject
->RegistryHive
!= KeyObject
->ParentKey
->RegistryHive
)
561 ObDereferenceObject(KeyObject
);
563 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID
)KeyObject
));
564 DPRINT("HandleCount %lu\n", ObGetObjectHandleCount((PVOID
)KeyObject
));
568 * Hive-Synchronization will not be triggered here. This is done in
569 * CmiObjectDelete() (in regobj.c) after all key-related structures
570 * have been released.
578 NtEnumerateKey(IN HANDLE KeyHandle
,
580 IN KEY_INFORMATION_CLASS KeyInformationClass
,
581 OUT PVOID KeyInformation
,
583 OUT PULONG ResultLength
)
585 PKEY_OBJECT KeyObject
;
586 PKEY_OBJECT SubKeyObject
;
587 PREGISTRY_HIVE RegistryHive
;
588 PKEY_CELL KeyCell
, SubKeyCell
;
589 PHASH_TABLE_CELL HashTableBlock
;
590 PKEY_BASIC_INFORMATION BasicInformation
;
591 PKEY_NODE_INFORMATION NodeInformation
;
592 PKEY_FULL_INFORMATION FullInformation
;
593 PDATA_CELL ClassCell
;
594 ULONG NameSize
, ClassSize
;
595 KPROCESSOR_MODE PreviousMode
;
600 PreviousMode
= ExGetPreviousMode();
602 DPRINT("KH %x I %d KIC %x KI %x L %d RL %x\n",
610 /* Verify that the handle is valid and is a registry key */
611 Status
= ObReferenceObjectByHandle(KeyHandle
,
612 KEY_ENUMERATE_SUB_KEYS
,
615 (PVOID
*) &KeyObject
,
617 if (!NT_SUCCESS(Status
))
619 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
623 /* Acquire hive lock */
624 KeEnterCriticalRegion();
625 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
627 VERIFY_KEY_OBJECT(KeyObject
);
629 /* Get pointer to KeyCell */
630 KeyCell
= KeyObject
->KeyCell
;
631 RegistryHive
= KeyObject
->RegistryHive
;
635 /* Check for hightest possible sub key index */
636 if (Index
>= KeyCell
->NumberOfSubKeys
+ KeyObject
->NumberOfSubKeys
)
638 ExReleaseResourceLite(&CmiRegistryLock
);
639 KeLeaveCriticalRegion();
640 ObDereferenceObject(KeyObject
);
641 DPRINT("No more volatile entries\n");
642 return STATUS_NO_MORE_ENTRIES
;
645 /* Get pointer to SubKey */
646 if (Index
>= KeyCell
->NumberOfSubKeys
)
648 PKEY_OBJECT CurKey
= NULL
;
652 /* Search for volatile or 'foreign' keys */
653 j
= KeyCell
->NumberOfSubKeys
;
654 for (i
= 0; i
< KeyObject
->NumberOfSubKeys
; i
++)
656 CurKey
= KeyObject
->SubKeys
[i
];
657 if (CurKey
->RegistryHive
!= RegistryHive
)
665 if (i
>= KeyObject
->NumberOfSubKeys
)
667 ExReleaseResourceLite(&CmiRegistryLock
);
668 KeLeaveCriticalRegion();
669 ObDereferenceObject(KeyObject
);
670 DPRINT("No more non-volatile entries\n");
671 return STATUS_NO_MORE_ENTRIES
;
674 SubKeyObject
= CurKey
;
675 SubKeyCell
= CurKey
->KeyCell
;
679 if (KeyCell
->HashTableOffset
== (BLOCK_OFFSET
)-1)
681 ExReleaseResourceLite(&CmiRegistryLock
);
682 KeLeaveCriticalRegion();
683 ObDereferenceObject(KeyObject
);
684 return STATUS_NO_MORE_ENTRIES
;
687 HashTableBlock
= CmiGetCell (RegistryHive
, KeyCell
->HashTableOffset
, NULL
);
688 if (HashTableBlock
== NULL
)
690 DPRINT("CmiGetBlock() failed\n");
691 ExReleaseResourceLite(&CmiRegistryLock
);
692 KeLeaveCriticalRegion();
693 ObDereferenceObject(KeyObject
);
694 return STATUS_UNSUCCESSFUL
;
697 SubKeyCell
= CmiGetKeyFromHashByIndex(RegistryHive
,
702 if (SubKeyCell
== NULL
)
704 ExReleaseResourceLite(&CmiRegistryLock
);
705 KeLeaveCriticalRegion();
706 ObDereferenceObject(KeyObject
);
707 DPRINT("No more entries\n");
708 return STATUS_NO_MORE_ENTRIES
;
711 Status
= STATUS_SUCCESS
;
712 switch (KeyInformationClass
)
714 case KeyBasicInformation
:
715 /* Check size of buffer */
716 if (SubKeyObject
!= NULL
)
718 NameSize
= SubKeyObject
->Name
.Length
;
722 NameSize
= SubKeyCell
->NameSize
;
723 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
725 NameSize
*= sizeof(WCHAR
);
729 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) + NameSize
;
732 * NOTE: It's perfetly valid to call NtEnumerateKey to get
733 * all the information but name. Actually the NT4 sound
734 * framework does that while querying parameters from registry.
735 * -- Filip Navara, 19/07/2004
737 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
739 Status
= STATUS_BUFFER_TOO_SMALL
;
743 /* Fill buffer with requested info */
744 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
745 BasicInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
746 BasicInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
747 BasicInformation
->TitleIndex
= Index
;
748 BasicInformation
->NameLength
= NameSize
;
750 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) < NameSize
)
752 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
753 Status
= STATUS_BUFFER_OVERFLOW
;
757 if (SubKeyObject
!= NULL
)
759 RtlCopyMemory(BasicInformation
->Name
,
760 SubKeyObject
->Name
.Buffer
,
765 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
767 CmiCopyPackedName(BasicInformation
->Name
,
769 NameSize
/ sizeof(WCHAR
));
773 RtlCopyMemory(BasicInformation
->Name
,
781 case KeyNodeInformation
:
782 /* Check size of buffer */
783 if (SubKeyObject
!= NULL
)
785 NameSize
= SubKeyObject
->Name
.Length
;
789 NameSize
= SubKeyCell
->NameSize
;
790 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
792 NameSize
*= sizeof(WCHAR
);
795 ClassSize
= SubKeyCell
->ClassSize
;
797 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
798 NameSize
+ ClassSize
;
800 if (Length
< FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]))
802 Status
= STATUS_BUFFER_TOO_SMALL
;
806 /* Fill buffer with requested info */
807 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
808 NodeInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
809 NodeInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
810 NodeInformation
->TitleIndex
= Index
;
811 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) + NameSize
;
812 NodeInformation
->ClassLength
= SubKeyCell
->ClassSize
;
813 NodeInformation
->NameLength
= NameSize
;
815 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
817 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
819 Status
= STATUS_BUFFER_OVERFLOW
;
822 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
823 NameSize
< ClassSize
)
825 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
827 Status
= STATUS_BUFFER_OVERFLOW
;
831 if (SubKeyObject
!= NULL
)
833 RtlCopyMemory(NodeInformation
->Name
,
834 SubKeyObject
->Name
.Buffer
,
839 if (SubKeyCell
->Flags
& REG_KEY_NAME_PACKED
)
841 CmiCopyPackedName(NodeInformation
->Name
,
843 NameSize
/ sizeof(WCHAR
));
847 RtlCopyMemory(NodeInformation
->Name
,
855 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
856 SubKeyCell
->ClassNameOffset
,
858 RtlCopyMemory (NodeInformation
->Name
+ SubKeyCell
->NameSize
,
865 case KeyFullInformation
:
866 ClassSize
= SubKeyCell
->ClassSize
;
868 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) +
871 /* Check size of buffer */
872 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]))
874 Status
= STATUS_BUFFER_TOO_SMALL
;
878 /* Fill buffer with requested info */
879 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
880 FullInformation
->LastWriteTime
.u
.LowPart
= SubKeyCell
->LastWriteTime
.u
.LowPart
;
881 FullInformation
->LastWriteTime
.u
.HighPart
= SubKeyCell
->LastWriteTime
.u
.HighPart
;
882 FullInformation
->TitleIndex
= Index
;
883 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) -
885 FullInformation
->ClassLength
= SubKeyCell
->ClassSize
;
886 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //SubKeyCell->NumberOfSubKeys;
887 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
888 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
889 FullInformation
->Values
= SubKeyCell
->NumberOfValues
;
890 FullInformation
->MaxValueNameLen
=
891 CmiGetMaxValueNameLength(RegistryHive
, SubKeyCell
);
892 FullInformation
->MaxValueDataLen
=
893 CmiGetMaxValueDataLength(RegistryHive
, SubKeyCell
);
895 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
897 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
898 Status
= STATUS_BUFFER_OVERFLOW
;
904 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
905 SubKeyCell
->ClassNameOffset
,
907 RtlCopyMemory (FullInformation
->Class
,
915 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
919 ExReleaseResourceLite(&CmiRegistryLock
);
920 KeLeaveCriticalRegion();
921 ObDereferenceObject(KeyObject
);
923 DPRINT("Returning status %x\n", Status
);
930 NtEnumerateValueKey(IN HANDLE KeyHandle
,
932 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
933 OUT PVOID KeyValueInformation
,
935 OUT PULONG ResultLength
)
938 PKEY_OBJECT KeyObject
;
939 PREGISTRY_HIVE RegistryHive
;
941 PVALUE_CELL ValueCell
;
943 ULONG NameSize
, DataSize
;
944 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
945 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
946 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
950 DPRINT("KH %x I %d KVIC %x KVI %x L %d RL %x\n",
953 KeyValueInformationClass
,
958 /* Verify that the handle is valid and is a registry key */
959 Status
= ObReferenceObjectByHandle(KeyHandle
,
963 (PVOID
*) &KeyObject
,
966 if (!NT_SUCCESS(Status
))
971 /* Acquire hive lock */
972 KeEnterCriticalRegion();
973 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
975 VERIFY_KEY_OBJECT(KeyObject
);
977 /* Get pointer to KeyCell */
978 KeyCell
= KeyObject
->KeyCell
;
979 RegistryHive
= KeyObject
->RegistryHive
;
981 /* Get Value block of interest */
982 Status
= CmiGetValueFromKeyByIndex(RegistryHive
,
987 if (!NT_SUCCESS(Status
))
989 ExReleaseResourceLite(&CmiRegistryLock
);
990 KeLeaveCriticalRegion();
991 ObDereferenceObject(KeyObject
);
995 if (ValueCell
!= NULL
)
997 switch (KeyValueInformationClass
)
999 case KeyValueBasicInformation
:
1000 NameSize
= ValueCell
->NameSize
;
1001 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1003 NameSize
*= sizeof(WCHAR
);
1006 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) + NameSize
;
1008 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1010 Status
= STATUS_BUFFER_TOO_SMALL
;
1014 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1015 KeyValueInformation
;
1016 ValueBasicInformation
->TitleIndex
= 0;
1017 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1018 ValueBasicInformation
->NameLength
= NameSize
;
1020 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1023 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1024 Status
= STATUS_BUFFER_OVERFLOW
;
1028 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1030 CmiCopyPackedName(ValueBasicInformation
->Name
,
1032 NameSize
/ sizeof(WCHAR
));
1036 RtlCopyMemory(ValueBasicInformation
->Name
,
1043 case KeyValuePartialInformation
:
1044 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1046 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1049 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1051 Status
= STATUS_BUFFER_TOO_SMALL
;
1055 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1056 KeyValueInformation
;
1057 ValuePartialInformation
->TitleIndex
= 0;
1058 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1059 ValuePartialInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1061 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1064 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1065 Status
= STATUS_BUFFER_OVERFLOW
;
1069 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1071 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1072 RtlCopyMemory(ValuePartialInformation
->Data
,
1078 RtlCopyMemory(ValuePartialInformation
->Data
,
1079 &ValueCell
->DataOffset
,
1085 case KeyValueFullInformation
:
1086 NameSize
= ValueCell
->NameSize
;
1087 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1089 NameSize
*= sizeof(WCHAR
);
1091 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1093 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1094 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1096 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1098 Status
= STATUS_BUFFER_TOO_SMALL
;
1102 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1103 KeyValueInformation
;
1104 ValueFullInformation
->TitleIndex
= 0;
1105 ValueFullInformation
->Type
= ValueCell
->DataType
;
1106 ValueFullInformation
->NameLength
= NameSize
;
1107 ValueFullInformation
->DataOffset
=
1108 (ULONG_PTR
)ValueFullInformation
->Name
-
1109 (ULONG_PTR
)ValueFullInformation
+
1110 ValueFullInformation
->NameLength
;
1111 ValueFullInformation
->DataOffset
=
1112 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1113 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1115 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1118 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1120 Status
= STATUS_BUFFER_OVERFLOW
;
1123 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1124 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1126 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) - NameSize
, sizeof(PVOID
));
1127 Status
= STATUS_BUFFER_OVERFLOW
;
1131 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1133 CmiCopyPackedName(ValueFullInformation
->Name
,
1135 NameSize
/ sizeof(WCHAR
));
1139 RtlCopyMemory(ValueFullInformation
->Name
,
1144 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1146 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1147 RtlCopyMemory((PCHAR
) ValueFullInformation
1148 + ValueFullInformation
->DataOffset
,
1149 DataCell
->Data
, DataSize
);
1153 RtlCopyMemory((PCHAR
) ValueFullInformation
1154 + ValueFullInformation
->DataOffset
,
1155 &ValueCell
->DataOffset
, DataSize
);
1161 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1167 Status
= STATUS_UNSUCCESSFUL
;
1170 ExReleaseResourceLite(&CmiRegistryLock
);
1171 KeLeaveCriticalRegion();
1172 ObDereferenceObject(KeyObject
);
1179 NtFlushKey(IN HANDLE KeyHandle
)
1182 PKEY_OBJECT KeyObject
;
1183 PREGISTRY_HIVE RegistryHive
;
1184 KPROCESSOR_MODE PreviousMode
;
1188 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle
);
1190 PreviousMode
= ExGetPreviousMode();
1192 /* Verify that the handle is valid and is a registry key */
1193 Status
= ObReferenceObjectByHandle(KeyHandle
,
1197 (PVOID
*)&KeyObject
,
1199 if (!NT_SUCCESS(Status
))
1204 VERIFY_KEY_OBJECT(KeyObject
);
1206 RegistryHive
= KeyObject
->RegistryHive
;
1208 /* Acquire hive lock */
1209 KeEnterCriticalRegion();
1210 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1212 if (IsNoFileHive(RegistryHive
))
1214 Status
= STATUS_SUCCESS
;
1218 /* Flush non-volatile hive */
1219 Status
= CmiFlushRegistryHive(RegistryHive
);
1222 ExReleaseResourceLite(&CmiRegistryLock
);
1223 KeLeaveCriticalRegion();
1225 ObDereferenceObject(KeyObject
);
1227 return STATUS_SUCCESS
;
1232 NtOpenKey(OUT PHANDLE KeyHandle
,
1233 IN ACCESS_MASK DesiredAccess
,
1234 IN POBJECT_ATTRIBUTES ObjectAttributes
)
1236 UNICODE_STRING RemainingPath
;
1237 KPROCESSOR_MODE PreviousMode
;
1240 NTSTATUS Status
= STATUS_SUCCESS
;
1244 DPRINT("NtOpenKey(KH %x DA %x OA %x OA->ON '%wZ'\n",
1248 ObjectAttributes
? ObjectAttributes
->ObjectName
: NULL
);
1250 /* Check place for result handle, if it's null - return immediately */
1251 if (KeyHandle
== NULL
)
1252 return(STATUS_INVALID_PARAMETER
);
1254 PreviousMode
= ExGetPreviousMode();
1256 if(PreviousMode
!= KernelMode
)
1260 ProbeForWrite(KeyHandle
,
1266 Status
= _SEH_GetExceptionCode();
1270 if(!NT_SUCCESS(Status
))
1276 /* WINE checks for the length also */
1277 /*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
1278 return(STATUS_BUFFER_OVERFLOW);*/
1280 RemainingPath
.Buffer
= NULL
;
1281 Status
= CmpFindObject(ObjectAttributes
,
1285 if (!NT_SUCCESS(Status
))
1287 DPRINT("CmpFindObject() returned 0x%08lx\n", Status
);
1288 Status
= STATUS_INVALID_HANDLE
; /* Because CmpFindObject returns STATUS_UNSUCCESSFUL */
1289 hKey
= *KeyHandle
; /* Preserve hkResult value */
1290 goto openkey_cleanup
;
1293 VERIFY_KEY_OBJECT((PKEY_OBJECT
) Object
);
1295 DPRINT("RemainingPath '%wZ'\n", &RemainingPath
);
1297 if ((RemainingPath
.Buffer
!= NULL
) && (RemainingPath
.Buffer
[0] != 0))
1299 ObDereferenceObject(Object
);
1300 RtlFreeUnicodeString(&RemainingPath
);
1301 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1303 goto openkey_cleanup
;
1306 RtlFreeUnicodeString(&RemainingPath
);
1308 /* Fail if the key has been deleted */
1309 if (((PKEY_OBJECT
)Object
)->Flags
& KO_MARKED_FOR_DELETE
)
1311 ObDereferenceObject(Object
);
1312 Status
= STATUS_UNSUCCESSFUL
;
1314 goto openkey_cleanup
;
1317 Status
= ObpCreateHandle(PsGetCurrentProcess(),
1322 ObDereferenceObject(Object
);
1324 if (!NT_SUCCESS(Status
))
1334 Status
= _SEH_GetExceptionCode();
1343 NtQueryKey(IN HANDLE KeyHandle
,
1344 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1345 OUT PVOID KeyInformation
,
1347 OUT PULONG ResultLength
)
1349 PKEY_BASIC_INFORMATION BasicInformation
;
1350 PKEY_NODE_INFORMATION NodeInformation
;
1351 PKEY_FULL_INFORMATION FullInformation
;
1352 PREGISTRY_HIVE RegistryHive
;
1353 PDATA_CELL ClassCell
;
1354 PKEY_OBJECT KeyObject
;
1356 ULONG NameSize
, ClassSize
;
1361 DPRINT("NtQueryKey(KH %x KIC %x KI %x L %d RL %x)\n",
1363 KeyInformationClass
,
1368 /* Verify that the handle is valid and is a registry key */
1369 Status
= ObReferenceObjectByHandle(KeyHandle
,
1370 (KeyInformationClass
!= KeyNameInformation
? KEY_QUERY_VALUE
: 0),
1373 (PVOID
*) &KeyObject
,
1375 if (!NT_SUCCESS(Status
))
1380 /* Acquire hive lock */
1381 KeEnterCriticalRegion();
1382 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1384 VERIFY_KEY_OBJECT(KeyObject
);
1386 /* Get pointer to KeyCell */
1387 KeyCell
= KeyObject
->KeyCell
;
1388 RegistryHive
= KeyObject
->RegistryHive
;
1390 Status
= STATUS_SUCCESS
;
1391 switch (KeyInformationClass
)
1393 case KeyBasicInformation
:
1394 NameSize
= KeyObject
->Name
.Length
;
1396 *ResultLength
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1398 /* Check size of buffer */
1399 if (Length
< FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]))
1401 Status
= STATUS_BUFFER_TOO_SMALL
;
1405 /* Fill buffer with requested info */
1406 BasicInformation
= (PKEY_BASIC_INFORMATION
) KeyInformation
;
1407 BasicInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1408 BasicInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1409 BasicInformation
->TitleIndex
= 0;
1410 BasicInformation
->NameLength
= KeyObject
->Name
.Length
;
1412 if (Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]) <
1415 NameSize
= Length
- FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
[0]);
1416 Status
= STATUS_BUFFER_OVERFLOW
;
1420 RtlCopyMemory(BasicInformation
->Name
,
1421 KeyObject
->Name
.Buffer
,
1426 case KeyNodeInformation
:
1427 NameSize
= KeyObject
->Name
.Length
;
1428 ClassSize
= KeyCell
->ClassSize
;
1430 *ResultLength
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) +
1431 NameSize
+ ClassSize
;
1433 /* Check size of buffer */
1434 if (Length
< *ResultLength
)
1436 Status
= STATUS_BUFFER_TOO_SMALL
;
1440 /* Fill buffer with requested info */
1441 NodeInformation
= (PKEY_NODE_INFORMATION
) KeyInformation
;
1442 NodeInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1443 NodeInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1444 NodeInformation
->TitleIndex
= 0;
1445 NodeInformation
->ClassOffset
= sizeof(KEY_NODE_INFORMATION
) +
1446 KeyObject
->Name
.Length
;
1447 NodeInformation
->ClassLength
= KeyCell
->ClassSize
;
1448 NodeInformation
->NameLength
= KeyObject
->Name
.Length
;
1450 if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) < NameSize
)
1452 NameSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]);
1454 Status
= STATUS_BUFFER_OVERFLOW
;
1457 else if (Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1458 NameSize
< ClassSize
)
1460 ClassSize
= Length
- FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
[0]) -
1462 Status
= STATUS_BUFFER_OVERFLOW
;
1466 RtlCopyMemory(NodeInformation
->Name
,
1467 KeyObject
->Name
.Buffer
,
1472 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1473 KeyCell
->ClassNameOffset
,
1475 RtlCopyMemory (NodeInformation
->Name
+ KeyObject
->Name
.Length
,
1482 case KeyFullInformation
:
1483 ClassSize
= KeyCell
->ClassSize
;
1485 *ResultLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
1488 /* Check size of buffer */
1489 if (Length
< FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
))
1491 Status
= STATUS_BUFFER_TOO_SMALL
;
1495 /* Fill buffer with requested info */
1496 FullInformation
= (PKEY_FULL_INFORMATION
) KeyInformation
;
1497 FullInformation
->LastWriteTime
.u
.LowPart
= KeyCell
->LastWriteTime
.u
.LowPart
;
1498 FullInformation
->LastWriteTime
.u
.HighPart
= KeyCell
->LastWriteTime
.u
.HighPart
;
1499 FullInformation
->TitleIndex
= 0;
1500 FullInformation
->ClassOffset
= sizeof(KEY_FULL_INFORMATION
) - sizeof(WCHAR
);
1501 FullInformation
->ClassLength
= KeyCell
->ClassSize
;
1502 FullInformation
->SubKeys
= CmiGetNumberOfSubKeys(KeyObject
); //KeyCell->NumberOfSubKeys;
1503 FullInformation
->MaxNameLen
= CmiGetMaxNameLength(KeyObject
);
1504 FullInformation
->MaxClassLen
= CmiGetMaxClassLength(KeyObject
);
1505 FullInformation
->Values
= KeyCell
->NumberOfValues
;
1506 FullInformation
->MaxValueNameLen
=
1507 CmiGetMaxValueNameLength(RegistryHive
, KeyCell
);
1508 FullInformation
->MaxValueDataLen
=
1509 CmiGetMaxValueDataLength(RegistryHive
, KeyCell
);
1511 if (Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]) < ClassSize
)
1513 ClassSize
= Length
- FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[0]);
1514 Status
= STATUS_BUFFER_OVERFLOW
;
1520 ClassCell
= CmiGetCell (KeyObject
->RegistryHive
,
1521 KeyCell
->ClassNameOffset
,
1523 RtlCopyMemory (FullInformation
->Class
,
1524 ClassCell
->Data
, ClassSize
);
1529 case KeyNameInformation
:
1530 case KeyCachedInformation
:
1531 case KeyFlagsInformation
:
1532 DPRINT1("Key information class 0x%x not yet implemented!\n", KeyInformationClass
);
1533 Status
= STATUS_NOT_IMPLEMENTED
;
1537 DPRINT1("Not handling 0x%x\n", KeyInformationClass
);
1538 Status
= STATUS_INVALID_INFO_CLASS
;
1542 ExReleaseResourceLite(&CmiRegistryLock
);
1543 KeLeaveCriticalRegion();
1544 ObDereferenceObject(KeyObject
);
1551 NtQueryValueKey(IN HANDLE KeyHandle
,
1552 IN PUNICODE_STRING ValueName
,
1553 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1554 OUT PVOID KeyValueInformation
,
1556 OUT PULONG ResultLength
)
1559 ULONG NameSize
, DataSize
;
1560 PKEY_OBJECT KeyObject
;
1561 PREGISTRY_HIVE RegistryHive
;
1563 PVALUE_CELL ValueCell
;
1564 PDATA_CELL DataCell
;
1565 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation
;
1566 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation
;
1567 PKEY_VALUE_FULL_INFORMATION ValueFullInformation
;
1571 DPRINT("NtQueryValueKey(KeyHandle %x ValueName %S Length %x)\n",
1572 KeyHandle
, ValueName
->Buffer
, Length
);
1574 /* Verify that the handle is valid and is a registry key */
1575 Status
= ObReferenceObjectByHandle(KeyHandle
,
1579 (PVOID
*)&KeyObject
,
1582 if (!NT_SUCCESS(Status
))
1584 DPRINT1("ObReferenceObjectByHandle() failed with status %x\n", Status
);
1588 /* Acquire hive lock */
1589 KeEnterCriticalRegion();
1590 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
1592 VERIFY_KEY_OBJECT(KeyObject
);
1594 /* Get pointer to KeyCell */
1595 KeyCell
= KeyObject
->KeyCell
;
1596 RegistryHive
= KeyObject
->RegistryHive
;
1598 /* Get value cell by name */
1599 Status
= CmiScanKeyForValue(RegistryHive
,
1604 if (!NT_SUCCESS(Status
))
1606 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
1610 Status
= STATUS_SUCCESS
;
1611 switch (KeyValueInformationClass
)
1613 case KeyValueBasicInformation
:
1614 NameSize
= ValueCell
->NameSize
;
1615 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1617 NameSize
*= sizeof(WCHAR
);
1620 *ResultLength
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) +
1623 if (Length
< FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]))
1625 Status
= STATUS_BUFFER_TOO_SMALL
;
1629 ValueBasicInformation
= (PKEY_VALUE_BASIC_INFORMATION
)
1630 KeyValueInformation
;
1631 ValueBasicInformation
->TitleIndex
= 0;
1632 ValueBasicInformation
->Type
= ValueCell
->DataType
;
1633 ValueBasicInformation
->NameLength
= NameSize
;
1635 if (Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]) <
1638 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
1639 Status
= STATUS_BUFFER_OVERFLOW
;
1643 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1645 CmiCopyPackedName(ValueBasicInformation
->Name
,
1647 NameSize
/ sizeof(WCHAR
));
1651 RtlCopyMemory(ValueBasicInformation
->Name
,
1658 case KeyValuePartialInformation
:
1659 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1661 *ResultLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) +
1664 if (Length
< FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]))
1666 Status
= STATUS_BUFFER_TOO_SMALL
;
1670 ValuePartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)
1671 KeyValueInformation
;
1672 ValuePartialInformation
->TitleIndex
= 0;
1673 ValuePartialInformation
->Type
= ValueCell
->DataType
;
1674 ValuePartialInformation
->DataLength
= DataSize
;
1676 if (Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) <
1679 DataSize
= Length
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
1680 Status
= STATUS_BUFFER_OVERFLOW
;
1684 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1686 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1687 RtlCopyMemory(ValuePartialInformation
->Data
,
1693 RtlCopyMemory(ValuePartialInformation
->Data
,
1694 &ValueCell
->DataOffset
,
1700 case KeyValueFullInformation
:
1701 NameSize
= ValueCell
->NameSize
;
1702 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1704 NameSize
*= sizeof(WCHAR
);
1706 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1708 *ResultLength
= ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1709 Name
[0]) + NameSize
, sizeof(PVOID
)) + DataSize
;
1711 if (Length
< FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]))
1713 Status
= STATUS_BUFFER_TOO_SMALL
;
1717 ValueFullInformation
= (PKEY_VALUE_FULL_INFORMATION
)
1718 KeyValueInformation
;
1719 ValueFullInformation
->TitleIndex
= 0;
1720 ValueFullInformation
->Type
= ValueCell
->DataType
;
1721 ValueFullInformation
->NameLength
= NameSize
;
1722 ValueFullInformation
->DataOffset
=
1723 (ULONG_PTR
)ValueFullInformation
->Name
-
1724 (ULONG_PTR
)ValueFullInformation
+
1725 ValueFullInformation
->NameLength
;
1726 ValueFullInformation
->DataOffset
=
1727 ROUND_UP(ValueFullInformation
->DataOffset
, sizeof(PVOID
));
1728 ValueFullInformation
->DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1730 if (Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) <
1733 NameSize
= Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
1735 Status
= STATUS_BUFFER_OVERFLOW
;
1738 else if (ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1739 Name
[0]) - NameSize
, sizeof(PVOID
)) < DataSize
)
1741 DataSize
= ROUND_UP(Length
- FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
,
1742 Name
[0]) - NameSize
, sizeof(PVOID
));
1743 Status
= STATUS_BUFFER_OVERFLOW
;
1747 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1749 CmiCopyPackedName(ValueFullInformation
->Name
,
1751 NameSize
/ sizeof(WCHAR
));
1755 RtlCopyMemory(ValueFullInformation
->Name
,
1759 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1761 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1762 RtlCopyMemory((PCHAR
) ValueFullInformation
1763 + ValueFullInformation
->DataOffset
,
1769 RtlCopyMemory((PCHAR
) ValueFullInformation
1770 + ValueFullInformation
->DataOffset
,
1771 &ValueCell
->DataOffset
,
1778 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass
);
1779 Status
= STATUS_INVALID_INFO_CLASS
;
1784 ExReleaseResourceLite(&CmiRegistryLock
);
1785 KeLeaveCriticalRegion();
1786 ObDereferenceObject(KeyObject
);
1793 NtSetValueKey(IN HANDLE KeyHandle
,
1794 IN PUNICODE_STRING ValueName
,
1795 IN ULONG TitleIndex
,
1801 PKEY_OBJECT KeyObject
;
1802 PREGISTRY_HIVE RegistryHive
;
1804 PVALUE_CELL ValueCell
;
1805 BLOCK_OFFSET ValueCellOffset
;
1806 PDATA_CELL DataCell
;
1807 PDATA_CELL NewDataCell
;
1809 ULONG DesiredAccess
;
1813 DPRINT("NtSetValueKey(KeyHandle %x ValueName '%wZ' Type %d)\n",
1814 KeyHandle
, ValueName
, Type
);
1816 DesiredAccess
= KEY_SET_VALUE
;
1818 /* Verify that the handle is valid and is a registry key */
1819 Status
= ObReferenceObjectByHandle(KeyHandle
,
1822 ExGetPreviousMode(),
1823 (PVOID
*)&KeyObject
,
1825 if (!NT_SUCCESS(Status
))
1828 /* Acquire hive lock exclucively */
1829 KeEnterCriticalRegion();
1830 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1832 VERIFY_KEY_OBJECT(KeyObject
);
1834 /* Get pointer to key cell */
1835 KeyCell
= KeyObject
->KeyCell
;
1836 RegistryHive
= KeyObject
->RegistryHive
;
1837 Status
= CmiScanKeyForValue(RegistryHive
,
1842 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1844 DPRINT("Allocate new value cell\n");
1845 Status
= CmiAddValueToKey(RegistryHive
,
1847 KeyObject
->KeyCellOffset
,
1853 if (!NT_SUCCESS(Status
))
1855 DPRINT("Cannot add value. Status 0x%X\n", Status
);
1857 ExReleaseResourceLite(&CmiRegistryLock
);
1858 KeLeaveCriticalRegion();
1859 ObDereferenceObject(KeyObject
);
1863 DPRINT("DataSize %lu\n", DataSize
);
1864 DPRINT("ValueCell %p\n", ValueCell
);
1865 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1867 if (DataSize
<= sizeof(BLOCK_OFFSET
))
1869 /* If data size <= sizeof(BLOCK_OFFSET) then store data in the data offset */
1870 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1871 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1872 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1874 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1875 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
1878 RtlCopyMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
1879 ValueCell
->DataSize
= DataSize
| REG_DATA_IN_OFFSET
;
1880 ValueCell
->DataType
= Type
;
1881 RtlMoveMemory(&ValueCell
->DataOffset
, Data
, DataSize
);
1882 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
1884 else if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1885 (DataSize
<= (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
)))
1887 /* If new data size is <= current then overwrite current data */
1888 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
,&pBin
);
1889 RtlZeroMemory(DataCell
->Data
, ValueCell
->DataSize
);
1890 RtlCopyMemory(DataCell
->Data
, Data
, DataSize
);
1891 ValueCell
->DataSize
= DataSize
;
1892 ValueCell
->DataType
= Type
;
1897 * New data size is larger than the current, destroy current
1898 * data block and allocate a new one.
1900 BLOCK_OFFSET NewOffset
;
1902 DPRINT("ValueCell->DataSize %lu\n", ValueCell
->DataSize
);
1904 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
) &&
1905 (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) != 0)
1907 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
1908 CmiDestroyCell(RegistryHive
, DataCell
, ValueCell
->DataOffset
);
1909 ValueCell
->DataSize
= 0;
1910 ValueCell
->DataType
= 0;
1911 ValueCell
->DataOffset
= (BLOCK_OFFSET
)-1;
1914 Status
= CmiAllocateCell (RegistryHive
,
1915 sizeof(CELL_HEADER
) + DataSize
,
1916 (PVOID
*)&NewDataCell
,
1918 if (!NT_SUCCESS(Status
))
1920 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status
);
1922 ExReleaseResourceLite(&CmiRegistryLock
);
1923 KeLeaveCriticalRegion();
1924 ObDereferenceObject(KeyObject
);
1929 RtlCopyMemory(&NewDataCell
->Data
[0], Data
, DataSize
);
1930 ValueCell
->DataSize
= DataSize
& REG_DATA_SIZE_MASK
;
1931 ValueCell
->DataType
= Type
;
1932 ValueCell
->DataOffset
= NewOffset
;
1933 CmiMarkBlockDirty(RegistryHive
, ValueCell
->DataOffset
);
1934 CmiMarkBlockDirty(RegistryHive
, ValueCellOffset
);
1938 if ((Type
== REG_LINK
) &&
1939 (_wcsicmp(ValueName
->Buffer
, L
"SymbolicLinkValue") == 0))
1941 KeyCell
->Flags
|= REG_KEY_LINK_CELL
;
1944 KeQuerySystemTime (&KeyCell
->LastWriteTime
);
1945 CmiMarkBlockDirty (RegistryHive
, KeyObject
->KeyCellOffset
);
1947 ExReleaseResourceLite(&CmiRegistryLock
);
1948 KeLeaveCriticalRegion();
1949 ObDereferenceObject(KeyObject
);
1953 DPRINT("Return Status 0x%X\n", Status
);
1960 NtDeleteValueKey (IN HANDLE KeyHandle
,
1961 IN PUNICODE_STRING ValueName
)
1963 PKEY_OBJECT KeyObject
;
1968 /* Verify that the handle is valid and is a registry key */
1969 Status
= ObReferenceObjectByHandle(KeyHandle
,
1973 (PVOID
*)&KeyObject
,
1975 if (!NT_SUCCESS(Status
))
1980 /* Acquire hive lock */
1981 KeEnterCriticalRegion();
1982 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1984 VERIFY_KEY_OBJECT(KeyObject
);
1986 Status
= CmiDeleteValueFromKey(KeyObject
->RegistryHive
,
1988 KeyObject
->KeyCellOffset
,
1991 KeQuerySystemTime (&KeyObject
->KeyCell
->LastWriteTime
);
1992 CmiMarkBlockDirty (KeyObject
->RegistryHive
, KeyObject
->KeyCellOffset
);
1994 /* Release hive lock */
1995 ExReleaseResourceLite(&CmiRegistryLock
);
1996 KeLeaveCriticalRegion();
1998 ObDereferenceObject (KeyObject
);
2008 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2009 * KeyObjectAttributes->Name specifies the name of the key to load.
2012 NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
2013 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
2015 return NtLoadKey2 (KeyObjectAttributes
,
2016 FileObjectAttributes
,
2023 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2024 * KeyObjectAttributes->Name specifies the name of the key to load.
2025 * Flags can be 0 or REG_NO_LAZY_FLUSH.
2028 NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
2029 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
2032 POBJECT_NAME_INFORMATION NameInfo
;
2033 PUNICODE_STRING NamePointer
;
2041 DPRINT ("NtLoadKey2() called\n");
2044 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, KeGetPreviousMode ()))
2045 return STATUS_PRIVILEGE_NOT_HELD
;
2048 if (FileObjectAttributes
->RootDirectory
!= NULL
)
2051 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2052 Buffer
= ExAllocatePool (NonPagedPool
,
2055 return STATUS_INSUFFICIENT_RESOURCES
;
2057 Status
= ZwQueryObject (FileObjectAttributes
->RootDirectory
,
2058 ObjectNameInformation
,
2062 if (!NT_SUCCESS(Status
))
2064 DPRINT1 ("NtQueryObject() failed (Status %lx)\n", Status
);
2065 ExFreePool (Buffer
);
2069 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2070 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2071 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2073 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2074 if (FileObjectAttributes
->ObjectName
->Buffer
[0] != L
'\\')
2076 RtlAppendUnicodeToString (&NameInfo
->Name
,
2078 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2079 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2081 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2082 FileObjectAttributes
->ObjectName
);
2084 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2085 &NameInfo
->Name
, NameInfo
->Name
.Length
);
2086 NamePointer
= &NameInfo
->Name
;
2090 if (FileObjectAttributes
->ObjectName
->Buffer
[0] == L
'\\')
2093 NamePointer
= FileObjectAttributes
->ObjectName
;
2098 sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2099 Buffer
= ExAllocatePool (NonPagedPool
,
2102 return STATUS_INSUFFICIENT_RESOURCES
;
2104 NameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
2105 NameInfo
->Name
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2106 NameInfo
->Name
.Length
= 0;
2107 NameInfo
->Name
.Buffer
= (PWSTR
)((ULONG_PTR
)Buffer
+ sizeof(OBJECT_NAME_INFORMATION
));
2108 NameInfo
->Name
.Buffer
[0] = 0;
2110 RtlAppendUnicodeToString (&NameInfo
->Name
,
2112 RtlAppendUnicodeStringToString (&NameInfo
->Name
,
2113 FileObjectAttributes
->ObjectName
);
2115 NamePointer
= &NameInfo
->Name
;
2119 DPRINT ("Full name: '%wZ'\n", NamePointer
);
2121 /* Acquire hive lock */
2122 KeEnterCriticalRegion();
2123 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2125 Status
= CmiLoadHive (KeyObjectAttributes
,
2128 if (!NT_SUCCESS (Status
))
2130 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
2133 /* Release hive lock */
2134 ExReleaseResourceLite(&CmiRegistryLock
);
2135 KeLeaveCriticalRegion();
2138 ExFreePool (Buffer
);
2145 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2147 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2148 IN PVOID ApcContext OPTIONAL
,
2149 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2150 IN ULONG CompletionFilter
,
2151 IN BOOLEAN WatchSubtree
,
2154 IN BOOLEAN Asynchronous
)
2157 return(STATUS_NOT_IMPLEMENTED
);
2162 NtNotifyChangeKey (IN HANDLE KeyHandle
,
2164 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
2165 IN PVOID ApcContext OPTIONAL
,
2166 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2167 IN ULONG CompletionFilter
,
2168 IN BOOLEAN WatchSubtree
,
2171 IN BOOLEAN Asynchronous
)
2173 return NtNotifyChangeMultipleKeys(KeyHandle
,
2190 NtQueryMultipleValueKey (IN HANDLE KeyHandle
,
2191 IN OUT PKEY_VALUE_ENTRY ValueList
,
2192 IN ULONG NumberOfValues
,
2194 IN OUT PULONG Length
,
2195 OUT PULONG ReturnLength
)
2197 PREGISTRY_HIVE RegistryHive
;
2198 PVALUE_CELL ValueCell
;
2199 PKEY_OBJECT KeyObject
;
2200 PDATA_CELL DataCell
;
2201 ULONG BufferLength
= 0;
2209 /* Verify that the handle is valid and is a registry key */
2210 Status
= ObReferenceObjectByHandle(KeyHandle
,
2214 (PVOID
*) &KeyObject
,
2216 if (!NT_SUCCESS(Status
))
2218 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2222 /* Acquire hive lock */
2223 KeEnterCriticalRegion();
2224 ExAcquireResourceSharedLite(&CmiRegistryLock
, TRUE
);
2226 VERIFY_KEY_OBJECT(KeyObject
);
2228 /* Get pointer to KeyCell */
2229 KeyCell
= KeyObject
->KeyCell
;
2230 RegistryHive
= KeyObject
->RegistryHive
;
2232 DataPtr
= (PUCHAR
) Buffer
;
2234 for (i
= 0; i
< NumberOfValues
; i
++)
2236 DPRINT("ValueName: '%wZ'\n", ValueList
[i
].ValueName
);
2238 /* Get Value block of interest */
2239 Status
= CmiScanKeyForValue(RegistryHive
,
2241 ValueList
[i
].ValueName
,
2245 if (!NT_SUCCESS(Status
))
2247 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status
);
2250 else if (ValueCell
== NULL
)
2252 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
2256 BufferLength
= ROUND_UP(BufferLength
, sizeof(PVOID
));
2258 if (BufferLength
+ (ValueCell
->DataSize
& REG_DATA_SIZE_MASK
) <= *Length
)
2260 DataPtr
= (PUCHAR
)ROUND_UP((ULONG_PTR
)DataPtr
, sizeof(PVOID
));
2262 ValueList
[i
].Type
= ValueCell
->DataType
;
2263 ValueList
[i
].DataLength
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2264 ValueList
[i
].DataOffset
= (ULONG_PTR
)DataPtr
- (ULONG_PTR
)Buffer
;
2266 if (!(ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
2268 DataCell
= CmiGetCell (RegistryHive
,
2269 ValueCell
->DataOffset
,
2271 RtlCopyMemory(DataPtr
,
2273 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2277 RtlCopyMemory(DataPtr
,
2278 &ValueCell
->DataOffset
,
2279 ValueCell
->DataSize
& REG_DATA_SIZE_MASK
);
2282 DataPtr
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2286 Status
= STATUS_BUFFER_TOO_SMALL
;
2289 BufferLength
+= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
2292 if (NT_SUCCESS(Status
))
2293 *Length
= BufferLength
;
2295 *ReturnLength
= BufferLength
;
2297 /* Release hive lock */
2298 ExReleaseResourceLite(&CmiRegistryLock
);
2299 KeLeaveCriticalRegion();
2301 ObDereferenceObject(KeyObject
);
2303 DPRINT("Return Status 0x%X\n", Status
);
2310 NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes
,
2312 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
2315 return(STATUS_NOT_IMPLEMENTED
);
2320 NtRestoreKey (IN HANDLE KeyHandle
,
2321 IN HANDLE FileHandle
,
2322 IN ULONG RestoreFlags
)
2325 return(STATUS_NOT_IMPLEMENTED
);
2330 NtSaveKey (IN HANDLE KeyHandle
,
2331 IN HANDLE FileHandle
)
2333 PREGISTRY_HIVE TempHive
;
2334 PKEY_OBJECT KeyObject
;
2339 DPRINT ("NtSaveKey() called\n");
2342 if (!SeSinglePrivilegeCheck (SeBackupPrivilege
, KeGetPreviousMode ()))
2343 return STATUS_PRIVILEGE_NOT_HELD
;
2346 Status
= ObReferenceObjectByHandle (KeyHandle
,
2349 KeGetPreviousMode(),
2350 (PVOID
*)&KeyObject
,
2352 if (!NT_SUCCESS(Status
))
2354 DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status
);
2358 /* Acquire hive lock exclucively */
2359 KeEnterCriticalRegion();
2360 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2362 /* Refuse to save a volatile key */
2363 if (KeyObject
->RegistryHive
== CmiVolatileHive
)
2365 DPRINT1 ("Cannot save a volatile key\n");
2366 ExReleaseResourceLite(&CmiRegistryLock
);
2367 KeLeaveCriticalRegion();
2368 ObDereferenceObject (KeyObject
);
2369 return STATUS_ACCESS_DENIED
;
2372 Status
= CmiCreateTempHive(&TempHive
);
2373 if (!NT_SUCCESS(Status
))
2375 DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status
);
2376 ExReleaseResourceLite(&CmiRegistryLock
);
2377 KeLeaveCriticalRegion();
2378 ObDereferenceObject (KeyObject
);
2382 Status
= CmiCopyKey (TempHive
,
2384 KeyObject
->RegistryHive
,
2385 KeyObject
->KeyCell
);
2386 if (!NT_SUCCESS(Status
))
2388 DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status
);
2389 CmiRemoveRegistryHive (TempHive
);
2390 ExReleaseResourceLite(&CmiRegistryLock
);
2391 KeLeaveCriticalRegion();
2392 ObDereferenceObject (KeyObject
);
2396 Status
= CmiSaveTempHive (TempHive
,
2398 if (!NT_SUCCESS(Status
))
2400 DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status
);
2403 CmiRemoveRegistryHive (TempHive
);
2405 /* Release hive lock */
2406 ExReleaseResourceLite(&CmiRegistryLock
);
2407 KeLeaveCriticalRegion();
2409 ObDereferenceObject (KeyObject
);
2411 DPRINT ("NtSaveKey() done\n");
2413 return STATUS_SUCCESS
;
2422 IN HANDLE KeyHandle
,
2423 IN HANDLE FileHandle
,
2424 IN ULONG Flags
// REG_STANDARD_FORMAT, etc..
2428 return STATUS_NOT_IMPLEMENTED
;
2433 NtSetInformationKey (IN HANDLE KeyHandle
,
2434 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
2435 IN PVOID KeyInformation
,
2436 IN ULONG KeyInformationLength
)
2438 PKEY_OBJECT KeyObject
;
2443 if (KeyInformationClass
!= KeyWriteTimeInformation
)
2444 return STATUS_INVALID_INFO_CLASS
;
2446 if (KeyInformationLength
!= sizeof (KEY_WRITE_TIME_INFORMATION
))
2447 return STATUS_INFO_LENGTH_MISMATCH
;
2449 /* Verify that the handle is valid and is a registry key */
2450 Status
= ObReferenceObjectByHandle (KeyHandle
,
2454 (PVOID
*)&KeyObject
,
2456 if (!NT_SUCCESS (Status
))
2458 DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status
);
2462 /* Acquire hive lock */
2463 KeEnterCriticalRegion();
2464 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2466 VERIFY_KEY_OBJECT(KeyObject
);
2468 KeyObject
->KeyCell
->LastWriteTime
.QuadPart
=
2469 ((PKEY_WRITE_TIME_INFORMATION
)KeyInformation
)->LastWriteTime
.QuadPart
;
2471 CmiMarkBlockDirty (KeyObject
->RegistryHive
,
2472 KeyObject
->KeyCellOffset
);
2474 /* Release hive lock */
2475 ExReleaseResourceLite(&CmiRegistryLock
);
2476 KeLeaveCriticalRegion();
2478 ObDereferenceObject (KeyObject
);
2482 DPRINT ("NtSaveKey() done\n");
2484 return STATUS_SUCCESS
;
2490 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2491 * KeyObjectAttributes->Name specifies the name of the key to unload.
2494 NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
2496 PREGISTRY_HIVE RegistryHive
;
2501 DPRINT ("NtUnloadKey() called\n");
2504 if (!SeSinglePrivilegeCheck (SeRestorePrivilege
, KeGetPreviousMode ()))
2505 return STATUS_PRIVILEGE_NOT_HELD
;
2508 /* Acquire registry lock exclusively */
2509 KeEnterCriticalRegion();
2510 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
2512 Status
= CmiDisconnectHive (KeyObjectAttributes
,
2514 if (!NT_SUCCESS (Status
))
2516 DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status
);
2517 ExReleaseResourceLite (&CmiRegistryLock
);
2518 KeLeaveCriticalRegion();
2522 DPRINT ("RegistryHive %p\n", RegistryHive
);
2526 if (!IsNoFileHive (RegistryHive
))
2527 CmiFlushRegistryHive (RegistryHive
);
2530 CmiRemoveRegistryHive (RegistryHive
);
2532 /* Release registry lock */
2533 ExReleaseResourceLite (&CmiRegistryLock
);
2534 KeLeaveCriticalRegion();
2536 DPRINT ("NtUnloadKey() done\n");
2538 return STATUS_SUCCESS
;
2543 NtInitializeRegistry (IN BOOLEAN SetUpBoot
)
2549 if (CmiRegistryInitialized
== TRUE
)
2550 return STATUS_ACCESS_DENIED
;
2552 /* Save boot log file */
2553 IopSaveBootLogToFile();
2555 Status
= CmiInitHives (SetUpBoot
);
2557 CmiRegistryInitialized
= TRUE
;