2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/ntfunc.c
5 * PURPOSE: Ntxxx function for registry access
9 /* INCLUDES *****************************************************************/
11 #include <ddk/ntddk.h>
13 #include <internal/ob.h>
16 #include <internal/pool.h>
17 #include <internal/registry.h>
20 #include <internal/debug.h>
25 /* GLOBALS ******************************************************************/
27 extern POBJECT_TYPE CmiKeyType;
28 extern PREGISTRY_HIVE CmiVolatileHive;
30 static BOOLEAN CmiRegistryInitialized = FALSE;
33 /* FUNCTIONS ****************************************************************/
36 NtCreateKey(OUT PHANDLE KeyHandle,
37 IN ACCESS_MASK DesiredAccess,
38 IN POBJECT_ATTRIBUTES ObjectAttributes,
40 IN PUNICODE_STRING Class,
41 IN ULONG CreateOptions,
42 OUT PULONG Disposition)
44 UNICODE_STRING RemainingPath;
45 PKEY_OBJECT KeyObject;
50 DPRINT("NtCreateKey (Name %wZ KeyHandle %x Root %x)\n",
51 ObjectAttributes->ObjectName,
53 ObjectAttributes->RootDirectory);
55 /* FIXME: check for standard handle prefix and adjust objectAttributes accordingly */
57 Status = ObFindObject(ObjectAttributes,
61 if (!NT_SUCCESS(Status))
66 DPRINT("RemainingPath %wZ\n", &RemainingPath);
68 if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
70 /* Fail if the key has been deleted */
71 if (((PKEY_OBJECT) Object)->Flags & KO_MARKED_FOR_DELETE)
73 ObDereferenceObject(Object);
74 return(STATUS_UNSUCCESSFUL);
78 *Disposition = REG_OPENED_EXISTING_KEY;
80 Status = ObCreateHandle(PsGetCurrentProcess(),
86 DPRINT("Status %x\n", Status);
87 ObDereferenceObject(Object);
91 /* If RemainingPath contains \ we must return error
92 because NtCreateKey don't create trees */
93 if (RemainingPath.Buffer[0] == '\\')
94 End = wcschr(RemainingPath.Buffer + 1, '\\');
96 End = wcschr(RemainingPath.Buffer, '\\');
100 ObDereferenceObject(Object);
101 return STATUS_OBJECT_NAME_NOT_FOUND;
104 DPRINT("RemainingPath %S ParentObject %x\n", RemainingPath.Buffer, Object);
106 Status = ObCreateObject(KeyHandle,
111 if (!NT_SUCCESS(Status))
116 KeyObject->ParentKey = Object;
118 if (CreateOptions & REG_OPTION_VOLATILE)
119 KeyObject->RegistryHive = CmiVolatileHive;
121 KeyObject->RegistryHive = KeyObject->ParentKey->RegistryHive;
123 KeyObject->Flags = 0;
124 KeyObject->NumberOfSubKeys = 0;
125 KeyObject->SizeOfSubKeys = 0;
126 KeyObject->SubKeys = NULL;
128 /* Acquire hive lock */
129 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
131 /* add key to subkeys of parent if needed */
132 Status = CmiAddSubKey(KeyObject->RegistryHive,
133 KeyObject->ParentKey,
135 RemainingPath.Buffer,
136 RemainingPath.Length,
140 if (!NT_SUCCESS(Status))
142 DPRINT("CmiAddSubKey() failed (Status %lx)\n", Status);
143 /* Release hive lock */
144 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
145 ObDereferenceObject(KeyObject);
146 ObDereferenceObject(Object);
147 return STATUS_UNSUCCESSFUL;
150 KeyObject->Name = KeyObject->KeyCell->Name;
151 KeyObject->NameSize = KeyObject->KeyCell->NameSize;
153 if (KeyObject->RegistryHive == KeyObject->ParentKey->RegistryHive)
155 KeyObject->KeyCell->ParentKeyOffset = KeyObject->ParentKey->BlockOffset;
156 KeyObject->KeyCell->SecurityKeyOffset = KeyObject->ParentKey->KeyCell->SecurityKeyOffset;
160 KeyObject->KeyCell->ParentKeyOffset = -1;
161 KeyObject->KeyCell->SecurityKeyOffset = -1;
162 /* This key must remain in memory unless it is deleted
163 or file is unloaded */
164 ObReferenceObjectByPointer(KeyObject,
165 STANDARD_RIGHTS_REQUIRED,
170 CmiAddKeyToList(KeyObject->ParentKey, KeyObject);
172 VERIFY_KEY_OBJECT(KeyObject);
174 /* Release hive lock */
175 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
177 ObDereferenceObject(KeyObject);
178 ObDereferenceObject(Object);
181 *Disposition = REG_CREATED_NEW_KEY;
190 NtDeleteKey(IN HANDLE KeyHandle)
192 PKEY_OBJECT KeyObject;
195 DPRINT("KeyHandle %x\n", KeyHandle);
197 /* Verify that the handle is valid and is a registry key */
198 Status = ObReferenceObjectByHandle(KeyHandle,
204 if (!NT_SUCCESS(Status))
209 /* Acquire hive lock */
210 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
212 VERIFY_KEY_OBJECT(KeyObject);
214 /* Check for subkeys */
215 if (KeyObject->NumberOfSubKeys != 0)
217 Status = STATUS_CANNOT_DELETE;
221 /* Set the marked for delete bit in the key object */
222 KeyObject->Flags |= KO_MARKED_FOR_DELETE;
223 Status = STATUS_SUCCESS;
226 /* Release hive lock */
227 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
229 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
231 /* Dereference the object */
232 ObDereferenceObject(KeyObject);
233 if(KeyObject->RegistryHive != KeyObject->ParentKey->RegistryHive)
234 ObDereferenceObject(KeyObject);
236 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
240 * Hive-Synchronization will not be triggered here. This is done in
241 * CmiObjectDelete() (in regobj.c) after all key-related structures
242 * have been released.
253 IN KEY_INFORMATION_CLASS KeyInformationClass,
254 OUT PVOID KeyInformation,
256 OUT PULONG ResultLength
260 PKEY_OBJECT KeyObject;
261 PREGISTRY_HIVE RegistryHive;
262 PKEY_CELL KeyCell, SubKeyCell;
263 PHASH_TABLE_CELL HashTableBlock;
264 PKEY_BASIC_INFORMATION BasicInformation;
265 PKEY_NODE_INFORMATION NodeInformation;
266 PKEY_FULL_INFORMATION FullInformation;
267 PDATA_CELL pClassData;
269 DPRINT("KH %x I %d KIC %x KI %x L %d RL %x\n",
277 /* Verify that the handle is valid and is a registry key */
278 Status = ObReferenceObjectByHandle(KeyHandle,
279 KEY_ENUMERATE_SUB_KEYS,
282 (PVOID *) &KeyObject,
284 if (!NT_SUCCESS(Status))
286 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
290 /* Acquire hive lock */
291 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
293 VERIFY_KEY_OBJECT(KeyObject);
295 /* Get pointer to KeyCell */
296 KeyCell = KeyObject->KeyCell;
297 RegistryHive = KeyObject->RegistryHive;
299 /* Get pointer to SubKey */
300 if (Index >= KeyCell->NumberOfSubKeys)
302 if (RegistryHive == CmiVolatileHive)
304 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
305 ObDereferenceObject(KeyObject);
306 DPRINT("No more volatile entries\n");
307 return(STATUS_NO_MORE_ENTRIES);
312 PKEY_OBJECT CurKey = NULL;
314 /* Search volatile keys */
315 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
317 CurKey = KeyObject->SubKeys[i];
318 if (CurKey->RegistryHive == CmiVolatileHive)
320 if (Index-- == KeyObject->NumberOfSubKeys)
324 if (Index >= KeyCell->NumberOfSubKeys)
326 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
327 ObDereferenceObject(KeyObject);
328 DPRINT("No more non-volatile entries\n");
329 return(STATUS_NO_MORE_ENTRIES);
331 SubKeyCell = CurKey->KeyCell;
336 if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
338 return(STATUS_NO_MORE_ENTRIES);
339 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
340 ObDereferenceObject(KeyObject);
343 HashTableBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
344 if (HashTableBlock == NULL)
346 DPRINT("CmiGetBlock() failed\n");
347 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
348 ObDereferenceObject(KeyObject);
349 return STATUS_UNSUCCESSFUL;
351 SubKeyCell = CmiGetKeyFromHashByIndex(RegistryHive,
356 if (SubKeyCell == NULL)
358 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
359 ObDereferenceObject(KeyObject);
360 DPRINT("No more entries\n");
361 return(STATUS_NO_MORE_ENTRIES);
364 Status = STATUS_SUCCESS;
365 switch (KeyInformationClass)
367 case KeyBasicInformation:
368 /* Check size of buffer */
369 *ResultLength = sizeof(KEY_BASIC_INFORMATION) +
370 (SubKeyCell->NameSize ) * sizeof(WCHAR);
371 if (Length < *ResultLength)
373 Status = STATUS_BUFFER_OVERFLOW;
377 /* Fill buffer with requested info */
378 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
379 BasicInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
380 BasicInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
381 BasicInformation->TitleIndex = Index;
382 BasicInformation->NameLength = SubKeyCell->NameSize * sizeof(WCHAR);
383 mbstowcs(BasicInformation->Name,
385 SubKeyCell->NameSize * 2);
386 // BasicInformation->Name[SubKeyCell->NameSize] = 0;
390 case KeyNodeInformation:
391 /* Check size of buffer */
392 *ResultLength = sizeof(KEY_NODE_INFORMATION) +
393 SubKeyCell->NameSize * sizeof(WCHAR) +
394 SubKeyCell->ClassSize;
395 if (Length < *ResultLength)
397 Status = STATUS_BUFFER_OVERFLOW;
401 /* Fill buffer with requested info */
402 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
403 NodeInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
404 NodeInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
405 NodeInformation->TitleIndex = Index;
406 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
407 SubKeyCell->NameSize * sizeof(WCHAR);
408 NodeInformation->ClassLength = SubKeyCell->ClassSize;
409 NodeInformation->NameLength = SubKeyCell->NameSize * sizeof(WCHAR);
410 mbstowcs(NodeInformation->Name,
412 SubKeyCell->NameSize * 2);
413 // NodeInformation->Name[SubKeyCell->NameSize] = 0;
414 if (SubKeyCell->ClassSize != 0)
416 pClassData=CmiGetBlock(KeyObject->RegistryHive,
417 SubKeyCell->ClassNameOffset,
419 wcsncpy(NodeInformation->Name + SubKeyCell->NameSize ,
420 (PWCHAR) pClassData->Data,
421 SubKeyCell->ClassSize);
426 case KeyFullInformation:
427 /* check size of buffer */
428 *ResultLength = sizeof(KEY_FULL_INFORMATION) +
429 SubKeyCell->ClassSize;
430 if (Length < *ResultLength)
432 Status = STATUS_BUFFER_OVERFLOW;
436 /* fill buffer with requested info */
437 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
438 FullInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
439 FullInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
440 FullInformation->TitleIndex = Index;
441 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) -
443 FullInformation->ClassLength = SubKeyCell->ClassSize;
444 FullInformation->SubKeys = SubKeyCell->NumberOfSubKeys;
445 FullInformation->MaxNameLen =
446 CmiGetMaxNameLength(RegistryHive, SubKeyCell);
447 FullInformation->MaxClassLen =
448 CmiGetMaxClassLength(RegistryHive, SubKeyCell);
449 FullInformation->Values = SubKeyCell->NumberOfValues;
450 FullInformation->MaxValueNameLen =
451 CmiGetMaxValueNameLength(RegistryHive, SubKeyCell);
452 FullInformation->MaxValueDataLen =
453 CmiGetMaxValueDataLength(RegistryHive, SubKeyCell);
454 if (SubKeyCell->ClassSize != 0)
456 pClassData = CmiGetBlock(KeyObject->RegistryHive,
457 SubKeyCell->ClassNameOffset,
459 wcsncpy(FullInformation->Class,
460 (PWCHAR) pClassData->Data,
461 SubKeyCell->ClassSize);
467 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
468 ObDereferenceObject(KeyObject);
470 DPRINT("Returning status %x\n", Status);
477 NtEnumerateValueKey(IN HANDLE KeyHandle,
479 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
480 OUT PVOID KeyValueInformation,
482 OUT PULONG ResultLength)
485 PKEY_OBJECT KeyObject;
486 PREGISTRY_HIVE RegistryHive;
488 PVALUE_CELL ValueCell;
490 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
491 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
492 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
494 DPRINT("KH %x I %d KVIC %x KVI %x L %d RL %x\n",
497 KeyValueInformationClass,
502 /* Verify that the handle is valid and is a registry key */
503 Status = ObReferenceObjectByHandle(KeyHandle,
507 (PVOID *) &KeyObject,
510 if (!NT_SUCCESS(Status))
515 /* Acquire hive lock */
516 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
518 VERIFY_KEY_OBJECT(KeyObject);
520 /* Get pointer to KeyCell */
521 KeyCell = KeyObject->KeyCell;
522 RegistryHive = KeyObject->RegistryHive;
524 /* Get Value block of interest */
525 Status = CmiGetValueFromKeyByIndex(RegistryHive,
530 if (!NT_SUCCESS(Status))
532 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
533 ObDereferenceObject(KeyObject);
537 if (ValueCell != NULL)
539 switch (KeyValueInformationClass)
541 case KeyValueBasicInformation:
542 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
544 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) +
545 (ValueCell->NameSize + 1) * sizeof(WCHAR);
549 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) +
550 ValueCell->NameSize + sizeof(WCHAR);
552 if (Length < *ResultLength)
554 Status = STATUS_BUFFER_OVERFLOW;
558 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
560 ValueBasicInformation->TitleIndex = 0;
561 ValueBasicInformation->Type = ValueCell->DataType;
562 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
564 ValueBasicInformation->NameLength =
565 (ValueCell->NameSize + 1) * sizeof(WCHAR);
566 CmiCopyPackedName(ValueBasicInformation->Name,
568 ValueCell->NameSize);
569 ValueBasicInformation->Name[ValueCell->NameSize] = 0;
573 ValueBasicInformation->NameLength =
574 ValueCell->NameSize + sizeof(WCHAR);
575 RtlCopyMemory(ValueBasicInformation->Name,
577 ValueCell->NameSize * sizeof(WCHAR));
578 ValueBasicInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
583 case KeyValuePartialInformation:
584 *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
585 (ValueCell->DataSize & LONG_MAX);
586 if (Length < *ResultLength)
588 Status = STATUS_BUFFER_OVERFLOW;
592 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
594 ValuePartialInformation->TitleIndex = 0;
595 ValuePartialInformation->Type = ValueCell->DataType;
596 ValuePartialInformation->DataLength = ValueCell->DataSize & LONG_MAX;
597 if(ValueCell->DataSize >0)
599 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
600 RtlCopyMemory(ValuePartialInformation->Data,
602 ValueCell->DataSize & LONG_MAX);
606 RtlCopyMemory(ValuePartialInformation->Data,
607 &ValueCell->DataOffset,
608 ValueCell->DataSize & LONG_MAX);
610 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
614 case KeyValueFullInformation:
615 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
617 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
618 (ValueCell->NameSize + 1) * sizeof(WCHAR) +
619 (ValueCell->DataSize & LONG_MAX);
623 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
624 ValueCell->NameSize + sizeof(WCHAR) +
625 (ValueCell->DataSize & LONG_MAX);
627 if (Length < *ResultLength)
629 Status = STATUS_BUFFER_OVERFLOW;
633 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
635 ValueFullInformation->TitleIndex = 0;
636 ValueFullInformation->Type = ValueCell->DataType;
637 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
639 ValueFullInformation->NameLength =
640 (ValueCell->NameSize + 1) * sizeof(WCHAR);
642 CmiCopyPackedName(ValueFullInformation->Name,
644 ValueCell->NameSize);
645 ValueFullInformation->Name[ValueCell->NameSize] = 0;
649 ValueFullInformation->NameLength =
650 ValueCell->NameSize + sizeof(WCHAR);
651 RtlCopyMemory(ValueFullInformation->Name,
653 ValueCell->NameSize);
654 ValueFullInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
656 ValueFullInformation->DataOffset =
657 (ULONG)ValueFullInformation->Name - (ULONG)ValueFullInformation +
658 ValueFullInformation->NameLength;
659 ValueFullInformation->DataOffset =
660 (ValueFullInformation->DataOffset + 3) & 0xfffffffc;
661 ValueFullInformation->DataLength = ValueCell->DataSize & LONG_MAX;
662 if (ValueCell->DataSize > 0)
664 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
665 RtlCopyMemory((PCHAR) ValueFullInformation
666 + ValueFullInformation->DataOffset,
668 ValueCell->DataSize & LONG_MAX);
672 RtlCopyMemory((PCHAR) ValueFullInformation
673 + ValueFullInformation->DataOffset,
674 &ValueCell->DataOffset,
675 ValueCell->DataSize & LONG_MAX);
683 Status = STATUS_UNSUCCESSFUL;
686 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
687 ObDereferenceObject(KeyObject);
694 NtFlushKey(IN HANDLE KeyHandle)
697 PKEY_OBJECT KeyObject;
698 PREGISTRY_HIVE RegistryHive;
700 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle);
702 /* Verify that the handle is valid and is a registry key */
703 Status = ObReferenceObjectByHandle(KeyHandle,
709 if (!NT_SUCCESS(Status))
714 VERIFY_KEY_OBJECT(KeyObject);
716 RegistryHive = KeyObject->RegistryHive;
718 /* Acquire hive lock */
719 ExAcquireResourceExclusiveLite(&RegistryHive->HiveResource,
722 if (IsVolatileHive(RegistryHive))
724 Status = STATUS_SUCCESS;
728 /* Flush non-volatile hive */
729 Status = CmiFlushRegistryHive(RegistryHive);
732 ExReleaseResourceLite(&RegistryHive->HiveResource);
734 ObDereferenceObject(KeyObject);
736 return STATUS_SUCCESS;
741 NtOpenKey(OUT PHANDLE KeyHandle,
742 IN ACCESS_MASK DesiredAccess,
743 IN POBJECT_ATTRIBUTES ObjectAttributes)
745 UNICODE_STRING RemainingPath;
749 DPRINT("NtOpenFile(KH %x DA %x OA %x OA->ON '%wZ'\n",
753 ObjectAttributes ? ObjectAttributes->ObjectName : NULL);
755 RemainingPath.Buffer = NULL;
756 Status = ObFindObject(ObjectAttributes,
760 if (!NT_SUCCESS(Status))
765 VERIFY_KEY_OBJECT((PKEY_OBJECT) Object);
767 DPRINT("RemainingPath '%wZ'\n", &RemainingPath);
769 if ((RemainingPath.Buffer != NULL) && (RemainingPath.Buffer[0] != 0))
771 ObDereferenceObject(Object);
772 return(STATUS_UNSUCCESSFUL);
775 /* Fail if the key has been deleted */
776 if (((PKEY_OBJECT)Object)->Flags & KO_MARKED_FOR_DELETE)
778 ObDereferenceObject(Object);
779 return(STATUS_UNSUCCESSFUL);
782 Status = ObCreateHandle(PsGetCurrentProcess(),
787 ObDereferenceObject(Object);
789 if (!NT_SUCCESS(Status))
794 return(STATUS_SUCCESS);
799 NtQueryKey(IN HANDLE KeyHandle,
800 IN KEY_INFORMATION_CLASS KeyInformationClass,
801 OUT PVOID KeyInformation,
803 OUT PULONG ResultLength)
805 PKEY_BASIC_INFORMATION BasicInformation;
806 PKEY_NODE_INFORMATION NodeInformation;
807 PKEY_FULL_INFORMATION FullInformation;
808 PREGISTRY_HIVE RegistryHive;
809 PDATA_CELL pClassData;
810 PKEY_OBJECT KeyObject;
814 DPRINT("KH %x KIC %x KI %x L %d RL %x\n",
821 /* Verify that the handle is valid and is a registry key */
822 Status = ObReferenceObjectByHandle(KeyHandle,
826 (PVOID *) &KeyObject,
828 if (!NT_SUCCESS(Status))
833 /* Acquire hive lock */
834 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
836 VERIFY_KEY_OBJECT(KeyObject);
838 /* Get pointer to KeyCell */
839 KeyCell = KeyObject->KeyCell;
840 RegistryHive = KeyObject->RegistryHive;
842 Status = STATUS_SUCCESS;
843 switch (KeyInformationClass)
845 case KeyBasicInformation:
846 /* Check size of buffer */
847 if (Length < sizeof(KEY_BASIC_INFORMATION) +
848 KeyObject->NameSize * sizeof(WCHAR))
850 Status = STATUS_BUFFER_OVERFLOW;
854 /* Fill buffer with requested info */
855 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
856 BasicInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
857 BasicInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
858 BasicInformation->TitleIndex = 0;
859 BasicInformation->NameLength = (KeyObject->NameSize) * sizeof(WCHAR);
860 mbstowcs(BasicInformation->Name,
862 KeyObject->NameSize*sizeof(WCHAR));
863 *ResultLength = sizeof(KEY_BASIC_INFORMATION) +
864 KeyObject->NameSize * sizeof(WCHAR);
868 case KeyNodeInformation:
869 /* Check size of buffer */
870 if (Length < sizeof(KEY_NODE_INFORMATION)
871 + KeyObject->NameSize * sizeof(WCHAR)
872 + KeyCell->ClassSize)
874 Status = STATUS_BUFFER_OVERFLOW;
878 /* Fill buffer with requested info */
879 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
880 NodeInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
881 NodeInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
882 NodeInformation->TitleIndex = 0;
883 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
884 KeyObject->NameSize * sizeof(WCHAR);
885 NodeInformation->ClassLength = KeyCell->ClassSize;
886 NodeInformation->NameLength = KeyObject->NameSize * sizeof(WCHAR);
887 mbstowcs(NodeInformation->Name,
889 KeyObject->NameSize * sizeof(WCHAR));
891 if (KeyCell->ClassSize != 0)
893 pClassData = CmiGetBlock(KeyObject->RegistryHive,
894 KeyCell->ClassNameOffset,
896 wcsncpy(NodeInformation->Name + KeyObject->NameSize * sizeof(WCHAR),
897 (PWCHAR)pClassData->Data,
900 *ResultLength = sizeof(KEY_NODE_INFORMATION)
901 + KeyObject->NameSize * sizeof(WCHAR)
902 + KeyCell->ClassSize;
906 case KeyFullInformation:
907 /* Check size of buffer */
908 if (Length < sizeof(KEY_FULL_INFORMATION) + KeyCell->ClassSize)
910 Status = STATUS_BUFFER_OVERFLOW;
914 /* Fill buffer with requested info */
915 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
916 FullInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
917 FullInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
918 FullInformation->TitleIndex = 0;
919 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR);
920 FullInformation->ClassLength = KeyCell->ClassSize;
921 FullInformation->SubKeys = KeyCell->NumberOfSubKeys;
922 FullInformation->MaxNameLen =
923 CmiGetMaxNameLength(RegistryHive, KeyCell);
924 FullInformation->MaxClassLen =
925 CmiGetMaxClassLength(RegistryHive, KeyCell);
926 FullInformation->Values = KeyCell->NumberOfValues;
927 FullInformation->MaxValueNameLen =
928 CmiGetMaxValueNameLength(RegistryHive, KeyCell);
929 FullInformation->MaxValueDataLen =
930 CmiGetMaxValueDataLength(RegistryHive, KeyCell);
931 if (KeyCell->ClassSize != 0)
933 pClassData=CmiGetBlock(KeyObject->RegistryHive,
934 KeyCell->ClassNameOffset,
936 wcsncpy(FullInformation->Class,
937 (PWCHAR)pClassData->Data,
940 *ResultLength = sizeof(KEY_FULL_INFORMATION) + KeyCell->ClassSize;
945 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
946 ObDereferenceObject(KeyObject);
953 NtQueryValueKey(IN HANDLE KeyHandle,
954 IN PUNICODE_STRING ValueName,
955 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
956 OUT PVOID KeyValueInformation,
958 OUT PULONG ResultLength)
961 PKEY_OBJECT KeyObject;
962 PREGISTRY_HIVE RegistryHive;
964 PVALUE_CELL ValueCell;
966 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
967 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
968 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
970 DPRINT("NtQueryValueKey(KeyHandle %x ValueName %S Length %x)\n",
971 KeyHandle, ValueName->Buffer, Length);
973 /* Verify that the handle is valid and is a registry key */
974 Status = ObReferenceObjectByHandle(KeyHandle,
981 if (!NT_SUCCESS(Status))
983 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
987 /* Acquire hive lock */
988 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
990 VERIFY_KEY_OBJECT(KeyObject);
992 /* Get pointer to KeyCell */
993 KeyCell = KeyObject->KeyCell;
994 RegistryHive = KeyObject->RegistryHive;
996 /* Get Value block of interest */
997 Status = CmiScanKeyForValue(RegistryHive,
1002 if (!NT_SUCCESS(Status))
1004 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1005 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1006 ObDereferenceObject(KeyObject);
1009 else if (ValueCell != NULL)
1011 switch (KeyValueInformationClass)
1013 case KeyValueBasicInformation:
1014 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1016 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) +
1017 (ValueCell->NameSize + 1) * sizeof(WCHAR);
1021 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) +
1022 ValueCell->NameSize + sizeof(WCHAR);
1024 if (Length < *ResultLength)
1026 Status = STATUS_BUFFER_TOO_SMALL;
1030 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
1031 KeyValueInformation;
1032 ValueBasicInformation->TitleIndex = 0;
1033 ValueBasicInformation->Type = ValueCell->DataType;
1034 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1036 ValueBasicInformation->NameLength =
1037 (ValueCell->NameSize + 1) * sizeof(WCHAR);
1038 CmiCopyPackedName(ValueBasicInformation->Name,
1040 ValueCell->NameSize);
1041 ValueBasicInformation->Name[ValueCell->NameSize] = 0;
1045 ValueBasicInformation->NameLength =
1046 ValueCell->NameSize + sizeof(WCHAR);
1047 RtlCopyMemory(ValueBasicInformation->Name,
1049 ValueCell->NameSize * sizeof(WCHAR));
1050 ValueBasicInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
1055 case KeyValuePartialInformation:
1056 *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION)
1057 + (ValueCell->DataSize & LONG_MAX);
1058 if (Length < *ResultLength)
1060 Status = STATUS_BUFFER_TOO_SMALL;
1064 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
1065 KeyValueInformation;
1066 ValuePartialInformation->TitleIndex = 0;
1067 ValuePartialInformation->Type = ValueCell->DataType;
1068 ValuePartialInformation->DataLength = ValueCell->DataSize & LONG_MAX;
1069 if (ValueCell->DataSize > 0)
1071 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1072 RtlCopyMemory(ValuePartialInformation->Data,
1074 ValueCell->DataSize & LONG_MAX);
1078 RtlCopyMemory(ValuePartialInformation->Data,
1079 &ValueCell->DataOffset,
1080 ValueCell->DataSize & LONG_MAX);
1085 case KeyValueFullInformation:
1086 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1088 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
1089 (ValueCell->NameSize + 1) * sizeof(WCHAR) +
1090 (ValueCell->DataSize & LONG_MAX);
1094 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
1095 ValueCell->NameSize + sizeof(WCHAR) +
1096 (ValueCell->DataSize & LONG_MAX);
1098 if (Length < *ResultLength)
1100 Status = STATUS_BUFFER_TOO_SMALL;
1104 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
1105 KeyValueInformation;
1106 ValueFullInformation->TitleIndex = 0;
1107 ValueFullInformation->Type = ValueCell->DataType;
1108 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1110 ValueFullInformation->NameLength =
1111 (ValueCell->NameSize + 1) * sizeof(WCHAR);
1112 CmiCopyPackedName(ValueFullInformation->Name,
1114 ValueCell->NameSize);
1115 ValueFullInformation->Name[ValueCell->NameSize] = 0;
1119 ValueFullInformation->NameLength =
1120 ValueCell->NameSize + sizeof(WCHAR);
1121 RtlCopyMemory(ValueFullInformation->Name,
1123 ValueCell->NameSize);
1124 ValueFullInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
1126 ValueFullInformation->DataOffset =
1127 (ULONG)ValueFullInformation->Name - (ULONG)ValueFullInformation +
1128 ValueFullInformation->NameLength;
1129 ValueFullInformation->DataOffset =
1130 (ValueFullInformation->DataOffset + 3) & 0xfffffffc;
1131 ValueFullInformation->DataLength = ValueCell->DataSize & LONG_MAX;
1132 if (ValueCell->DataSize > 0)
1134 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1135 RtlCopyMemory((PCHAR) ValueFullInformation
1136 + ValueFullInformation->DataOffset,
1138 ValueCell->DataSize & LONG_MAX);
1142 RtlCopyMemory((PCHAR) ValueFullInformation
1143 + ValueFullInformation->DataOffset,
1144 &ValueCell->DataOffset,
1145 ValueCell->DataSize & LONG_MAX);
1153 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1156 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1157 ObDereferenceObject(KeyObject);
1164 NtSetValueKey(IN HANDLE KeyHandle,
1165 IN PUNICODE_STRING ValueName,
1166 IN ULONG TitleIndex,
1172 PKEY_OBJECT KeyObject;
1173 PREGISTRY_HIVE RegistryHive;
1175 PVALUE_CELL ValueCell;
1176 BLOCK_OFFSET VBOffset;
1177 PDATA_CELL DataCell;
1178 PDATA_CELL NewDataCell;
1180 ULONG DesiredAccess;
1182 DPRINT("NtSetValueKey(KeyHandle %x ValueName '%wZ' Type %d)\n",
1183 KeyHandle, ValueName, Type);
1185 DesiredAccess = KEY_SET_VALUE;
1186 if (Type == REG_LINK)
1187 DesiredAccess |= KEY_CREATE_LINK;
1189 /* Verify that the handle is valid and is a registry key */
1190 Status = ObReferenceObjectByHandle(KeyHandle,
1194 (PVOID *)&KeyObject,
1196 if (!NT_SUCCESS(Status))
1199 /* Acquire hive lock exclucively */
1200 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1202 VERIFY_KEY_OBJECT(KeyObject);
1204 /* Get pointer to key cell */
1205 KeyCell = KeyObject->KeyCell;
1206 RegistryHive = KeyObject->RegistryHive;
1207 Status = CmiScanKeyForValue(RegistryHive,
1212 if (!NT_SUCCESS(Status))
1214 DPRINT("Value not found. Status 0x%X\n", Status);
1216 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1217 ObDereferenceObject(KeyObject);
1221 if (ValueCell == NULL)
1223 DPRINT("Allocate new value cell\n");
1224 Status = CmiAddValueToKey(RegistryHive,
1229 if (NT_SUCCESS(Status))
1231 CmiMarkBlockDirty(RegistryHive, VBOffset);
1235 if (!NT_SUCCESS(Status))
1237 DPRINT("Cannot add value. Status 0x%X\n", Status);
1239 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1240 ObDereferenceObject(KeyObject);
1244 DPRINT("DataSize %lu\n", DataSize);
1245 DPRINT("ValueCell %p\n", ValueCell);
1246 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1250 /* If datasize <= 4 then write in valueblock directly */
1251 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1252 if ((ValueCell->DataSize >= 0) &&
1253 (DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL)))
1255 CmiDestroyBlock(RegistryHive, DataCell, ValueCell->DataOffset);
1258 RtlCopyMemory(&ValueCell->DataOffset, Data, DataSize);
1259 ValueCell->DataSize = DataSize | 0x80000000;
1260 ValueCell->DataType = Type;
1261 RtlMoveMemory(&ValueCell->DataOffset, Data, DataSize);
1262 CmiMarkBlockDirty(RegistryHive, VBOffset);
1264 else if (DataSize <= (ULONG) (ValueCell->DataSize & 0x7fffffff))
1266 /* If new data size is <= current then overwrite current data */
1267 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset,&pBin);
1268 RtlZeroMemory(DataCell->Data, ValueCell->DataSize);
1269 RtlCopyMemory(DataCell->Data, Data, DataSize);
1270 ValueCell->DataSize = DataSize;
1271 ValueCell->DataType = Type;
1273 /* Update time of heap */
1274 if (!IsVolatileHive(RegistryHive))
1276 NtQuerySystemTime((PTIME) &pBin->DateModified);
1278 CmiMarkBlockDirty(RegistryHive, ValueCell->DataOffset);
1283 * New data size is larger than the current, destroy current
1284 * data block and allocate a new one.
1286 BLOCK_OFFSET NewOffset;
1288 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1290 if ((ValueCell->DataSize >= 0) &&
1291 (DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL)))
1293 CmiDestroyBlock(RegistryHive, DataCell, ValueCell->DataOffset);
1294 ValueCell->DataSize = 0;
1295 ValueCell->DataType = 0;
1296 ValueCell->DataOffset = 0xffffffff;
1299 Status = CmiAllocateBlock(RegistryHive,
1300 (PVOID *)&NewDataCell,
1303 if (!NT_SUCCESS(Status))
1305 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status);
1307 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1308 ObDereferenceObject(KeyObject);
1313 RtlCopyMemory(&NewDataCell->Data[0], Data, DataSize);
1314 ValueCell->DataSize = DataSize;
1315 ValueCell->DataType = Type;
1316 ValueCell->DataOffset = NewOffset;
1317 CmiMarkBlockDirty(RegistryHive, ValueCell->DataOffset);
1321 if ((_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0) &&
1324 KeyCell->Type = REG_LINK_KEY_CELL_TYPE;
1325 CmiMarkBlockDirty(RegistryHive, KeyObject->BlockOffset);
1328 /* Update time of heap */
1329 if (!IsVolatileHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
1331 NtQuerySystemTime((PTIME) &pBin->DateModified);
1334 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1335 ObDereferenceObject(KeyObject);
1339 DPRINT("Return Status 0x%X\n", Status);
1346 NtDeleteValueKey(IN HANDLE KeyHandle,
1347 IN PUNICODE_STRING ValueName)
1349 PKEY_OBJECT KeyObject;
1352 /* Verify that the handle is valid and is a registry key */
1353 Status = ObReferenceObjectByHandle(KeyHandle,
1357 (PVOID *)&KeyObject,
1359 if (!NT_SUCCESS(Status))
1364 /* Acquire hive lock */
1365 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1367 VERIFY_KEY_OBJECT(KeyObject);
1369 Status = CmiDeleteValueFromKey(KeyObject->RegistryHive,
1371 KeyObject->BlockOffset,
1374 /* Release hive lock */
1375 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1377 ObDereferenceObject(KeyObject);
1386 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1387 * KeyObjectAttributes->Name specifies the name of the key to load.
1390 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1391 IN POBJECT_ATTRIBUTES FileObjectAttributes)
1393 return NtLoadKey2(KeyObjectAttributes, FileObjectAttributes, 0);
1399 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1400 * KeyObjectAttributes->Name specifies the name of the key to load.
1403 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1404 IN POBJECT_ATTRIBUTES FileObjectAttributes,
1408 return STATUS_NOT_IMPLEMENTED;
1414 IN HANDLE KeyHandle,
1416 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1417 IN PVOID ApcContext OPTIONAL,
1418 OUT PIO_STATUS_BLOCK IoStatusBlock,
1419 IN ULONG CompletionFilter,
1420 IN BOOLEAN Asynchroneous,
1421 OUT PVOID ChangeBuffer,
1423 IN BOOLEAN WatchSubtree)
1430 NtQueryMultipleValueKey(IN HANDLE KeyHandle,
1431 IN OUT PKEY_VALUE_ENTRY ValueList,
1432 IN ULONG NumberOfValues,
1434 IN OUT PULONG Length,
1435 OUT PULONG ReturnLength)
1437 PREGISTRY_HIVE RegistryHive;
1438 PVALUE_CELL ValueCell;
1439 PKEY_OBJECT KeyObject;
1440 PDATA_CELL DataCell;
1441 ULONG BufferLength = 0;
1447 /* Verify that the handle is valid and is a registry key */
1448 Status = ObReferenceObjectByHandle(KeyHandle,
1452 (PVOID *) &KeyObject,
1454 if (!NT_SUCCESS(Status))
1456 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
1460 /* Acquire hive lock */
1461 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1463 VERIFY_KEY_OBJECT(KeyObject);
1465 /* Get pointer to KeyCell */
1466 KeyCell = KeyObject->KeyCell;
1467 RegistryHive = KeyObject->RegistryHive;
1469 DataPtr = (PUCHAR) Buffer;
1471 for (i = 0; i < NumberOfValues; i++)
1473 DPRINT("ValueName: '%wZ'\n", ValueList[i].ValueName);
1475 /* Get Value block of interest */
1476 Status = CmiScanKeyForValue(RegistryHive,
1478 ValueList[i].ValueName,
1482 if (!NT_SUCCESS(Status))
1484 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1487 else if (ValueCell == NULL)
1489 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1493 BufferLength = (BufferLength + 3) & 0xfffffffc;
1495 if (BufferLength + (ValueCell->DataSize & LONG_MAX) <= *Length)
1497 DataPtr = (PUCHAR)(((ULONG)DataPtr + 3) & 0xfffffffc);
1499 ValueList[i].Type = ValueCell->DataType;
1500 ValueList[i].DataLength = ValueCell->DataSize & LONG_MAX;
1501 ValueList[i].DataOffset = (ULONG) DataPtr - (ULONG) Buffer;
1503 if (ValueCell->DataSize > 0)
1505 DataCell = CmiGetBlock(RegistryHive,
1506 ValueCell->DataOffset,
1508 RtlCopyMemory(DataPtr,
1510 ValueCell->DataSize & LONG_MAX);
1514 RtlCopyMemory(DataPtr,
1515 &ValueCell->DataOffset,
1516 ValueCell->DataSize & LONG_MAX);
1519 DataPtr += ValueCell->DataSize & LONG_MAX;
1523 Status = STATUS_BUFFER_TOO_SMALL;
1526 BufferLength += ValueCell->DataSize & LONG_MAX;
1529 if (NT_SUCCESS(Status))
1530 *Length = BufferLength;
1532 *ReturnLength = BufferLength;
1534 /* Release hive lock */
1535 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1537 ObDereferenceObject(KeyObject);
1539 DPRINT("Return Status 0x%X\n", Status);
1547 IN POBJECT_ATTRIBUTES ObjectAttributes,
1549 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
1558 IN HANDLE KeyHandle,
1559 IN HANDLE FileHandle,
1560 IN ULONG RestoreFlags
1569 IN HANDLE KeyHandle,
1570 IN HANDLE FileHandle)
1577 NtSetInformationKey(
1578 IN HANDLE KeyHandle,
1579 IN CINT KeyInformationClass,
1580 IN PVOID KeyInformation,
1581 IN ULONG KeyInformationLength)
1589 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1590 * KeyObjectAttributes->Name specifies the name of the key to unload.
1593 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)
1600 NtInitializeRegistry(IN BOOLEAN SetUpBoot)
1602 NTSTATUS Status = STATUS_ACCESS_DENIED;
1604 if (CmiRegistryInitialized == FALSE)
1606 /* FIXME: save boot log file */
1608 Status = CmiInitHives(SetUpBoot);
1610 CmiRegistryInitialized = TRUE;