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, &Object, &RemainingPath, CmiKeyType);
59 if (!NT_SUCCESS(Status))
64 DPRINT("RemainingPath %wZ\n", &RemainingPath);
66 if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
68 /* Fail if the key has been deleted */
69 if (((PKEY_OBJECT) Object)->Flags & KO_MARKED_FOR_DELETE)
71 ObDereferenceObject(Object);
72 return STATUS_UNSUCCESSFUL;
76 *Disposition = REG_OPENED_EXISTING_KEY;
78 Status = ObCreateHandle(PsGetCurrentProcess(),
84 DPRINT("Status %x\n", Status);
85 ObDereferenceObject(Object);
89 /* If RemainingPath contains \ we must return error
90 because NtCreateKey don't create trees */
91 if (RemainingPath.Buffer[0] == '\\')
92 End = wcschr(RemainingPath.Buffer + 1, '\\');
94 End = wcschr(RemainingPath.Buffer, '\\');
98 ObDereferenceObject(Object);
99 return STATUS_UNSUCCESSFUL;
102 DPRINT("RemainingPath %S ParentObject %x\n", RemainingPath.Buffer, Object);
104 Status = ObCreateObject(KeyHandle,
110 if (!NT_SUCCESS(Status))
113 KeyObject->ParentKey = Object;
115 if (CreateOptions & REG_OPTION_VOLATILE)
116 KeyObject->RegistryHive = CmiVolatileHive;
118 KeyObject->RegistryHive = KeyObject->ParentKey->RegistryHive;
120 KeyObject->Flags = 0;
121 KeyObject->NumberOfSubKeys = 0;
122 KeyObject->SizeOfSubKeys = 0;
123 KeyObject->SubKeys = NULL;
124 // KeAcquireSpinLock(&Key->RegistryHive->RegLock, &OldIrql);
125 /* add key to subkeys of parent if needed */
126 Status = CmiAddSubKey(KeyObject->RegistryHive,
127 KeyObject->ParentKey,
129 RemainingPath.Buffer,
130 RemainingPath.Length,
135 if (!NT_SUCCESS(Status))
137 ObDereferenceObject(KeyObject);
138 ObDereferenceObject(Object);
139 return STATUS_UNSUCCESSFUL;
142 KeyObject->Name = KeyObject->KeyCell->Name;
143 KeyObject->NameSize = KeyObject->KeyCell->NameSize;
145 if (KeyObject->RegistryHive == KeyObject->ParentKey->RegistryHive)
147 KeyObject->KeyCell->ParentKeyOffset = KeyObject->ParentKey->BlockOffset;
148 KeyObject->KeyCell->SecurityKeyOffset = KeyObject->ParentKey->KeyCell->SecurityKeyOffset;
152 KeyObject->KeyCell->ParentKeyOffset = -1;
153 KeyObject->KeyCell->SecurityKeyOffset = -1;
154 /* This key must rest in memory unless it is deleted
155 or file is unloaded */
156 ObReferenceObjectByPointer(KeyObject,
157 STANDARD_RIGHTS_REQUIRED,
162 CmiAddKeyToList(KeyObject->ParentKey, KeyObject);
163 // KeReleaseSpinLock(&KeyObject->RegistryHive->RegLock, OldIrql);
165 ObDereferenceObject(KeyObject);
166 ObDereferenceObject(Object);
169 *Disposition = REG_CREATED_NEW_KEY;
171 VERIFY_KEY_OBJECT(KeyObject);
178 NtDeleteKey(IN HANDLE KeyHandle)
180 PKEY_OBJECT KeyObject;
183 DPRINT("KeyHandle %x\n", KeyHandle);
185 /* Verify that the handle is valid and is a registry key */
186 Status = ObReferenceObjectByHandle(KeyHandle,
190 (PVOID *) &KeyObject,
193 if (!NT_SUCCESS(Status))
198 VERIFY_KEY_OBJECT(KeyObject);
200 /* Set the marked for delete bit in the key object */
201 KeyObject->Flags |= KO_MARKED_FOR_DELETE;
203 /* Dereference the object */
204 ObDereferenceObject(KeyObject);
205 if(KeyObject->RegistryHive != KeyObject->ParentKey->RegistryHive)
206 ObDereferenceObject(KeyObject);
207 /* Close the handle */
208 ObDeleteHandle(PsGetCurrentProcess(), KeyHandle);
209 /* FIXME: I think that ObDeleteHandle should dereference the object */
210 ObDereferenceObject(KeyObject);
212 return STATUS_SUCCESS;
220 IN KEY_INFORMATION_CLASS KeyInformationClass,
221 OUT PVOID KeyInformation,
223 OUT PULONG ResultLength
227 PKEY_OBJECT KeyObject;
228 PREGISTRY_HIVE RegistryHive;
229 PKEY_CELL KeyCell, SubKeyCell;
230 PHASH_TABLE_CELL HashTableBlock;
231 PKEY_BASIC_INFORMATION BasicInformation;
232 PKEY_NODE_INFORMATION NodeInformation;
233 PKEY_FULL_INFORMATION FullInformation;
234 PDATA_CELL pClassData;
236 DPRINT("KH %x I %d KIC %x KI %x L %d RL %x\n",
244 /* Verify that the handle is valid and is a registry key */
245 Status = ObReferenceObjectByHandle(KeyHandle,
246 KEY_ENUMERATE_SUB_KEYS,
249 (PVOID *) &KeyObject,
251 if (!NT_SUCCESS(Status))
253 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
257 VERIFY_KEY_OBJECT(KeyObject);
259 /* Get pointer to KeyCell */
260 KeyCell = KeyObject->KeyCell;
261 RegistryHive = KeyObject->RegistryHive;
263 /* Get pointer to SubKey */
264 if (Index >= KeyCell->NumberOfSubKeys)
266 if (RegistryHive == CmiVolatileHive)
268 ObDereferenceObject (KeyObject);
269 DPRINT("No more volatile entries\n");
270 return STATUS_NO_MORE_ENTRIES;
275 PKEY_OBJECT CurKey = NULL;
277 /* Search volatile keys */
278 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
280 CurKey = KeyObject->SubKeys[i];
281 if (CurKey->RegistryHive == CmiVolatileHive)
283 if (Index-- == KeyObject->NumberOfSubKeys)
287 if(Index >= KeyCell->NumberOfSubKeys)
289 ObDereferenceObject (KeyObject);
290 DPRINT("No more non-volatile entries\n");
291 return STATUS_NO_MORE_ENTRIES;
293 SubKeyCell = CurKey->KeyCell;
298 HashTableBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
299 SubKeyCell = CmiGetKeyFromHashByIndex(RegistryHive,
304 if (SubKeyCell == NULL)
306 ObDereferenceObject (KeyObject);
307 DPRINT("No more entries\n");
308 return STATUS_NO_MORE_ENTRIES;
311 Status = STATUS_SUCCESS;
312 switch (KeyInformationClass)
314 case KeyBasicInformation:
315 /* Check size of buffer */
316 *ResultLength = sizeof(KEY_BASIC_INFORMATION) +
317 (SubKeyCell->NameSize ) * sizeof(WCHAR);
318 if (Length < *ResultLength)
320 Status = STATUS_BUFFER_OVERFLOW;
324 /* Fill buffer with requested info */
325 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
326 BasicInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
327 BasicInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
328 BasicInformation->TitleIndex = Index;
329 BasicInformation->NameLength = SubKeyCell->NameSize * sizeof(WCHAR);
330 mbstowcs(BasicInformation->Name,
332 SubKeyCell->NameSize * 2);
333 // BasicInformation->Name[SubKeyCell->NameSize] = 0;
337 case KeyNodeInformation:
338 /* Check size of buffer */
339 *ResultLength = sizeof(KEY_NODE_INFORMATION) +
340 SubKeyCell->NameSize * sizeof(WCHAR) +
341 SubKeyCell->ClassSize;
342 if (Length < *ResultLength)
344 Status = STATUS_BUFFER_OVERFLOW;
348 /* Fill buffer with requested info */
349 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
350 NodeInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
351 NodeInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
352 NodeInformation->TitleIndex = Index;
353 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
354 SubKeyCell->NameSize * sizeof(WCHAR);
355 NodeInformation->ClassLength = SubKeyCell->ClassSize;
356 NodeInformation->NameLength = SubKeyCell->NameSize * sizeof(WCHAR);
357 mbstowcs(NodeInformation->Name,
359 SubKeyCell->NameSize * 2);
360 // NodeInformation->Name[SubKeyCell->NameSize] = 0;
361 if (SubKeyCell->ClassSize != 0)
363 pClassData=CmiGetBlock(KeyObject->RegistryHive,
364 SubKeyCell->ClassNameOffset,
366 wcsncpy(NodeInformation->Name + SubKeyCell->NameSize ,
367 (PWCHAR) pClassData->Data,
368 SubKeyCell->ClassSize);
369 CmiReleaseBlock(RegistryHive, pClassData);
374 case KeyFullInformation:
375 /* check size of buffer */
376 *ResultLength = sizeof(KEY_FULL_INFORMATION) +
377 SubKeyCell->ClassSize;
378 if (Length < *ResultLength)
380 Status = STATUS_BUFFER_OVERFLOW;
384 /* fill buffer with requested info */
385 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
386 FullInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
387 FullInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
388 FullInformation->TitleIndex = Index;
389 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) -
391 FullInformation->ClassLength = SubKeyCell->ClassSize;
392 FullInformation->SubKeys = SubKeyCell->NumberOfSubKeys;
393 FullInformation->MaxNameLen =
394 CmiGetMaxNameLength(RegistryHive, SubKeyCell);
395 FullInformation->MaxClassLen =
396 CmiGetMaxClassLength(RegistryHive, SubKeyCell);
397 FullInformation->Values = SubKeyCell->NumberOfValues;
398 FullInformation->MaxValueNameLen =
399 CmiGetMaxValueNameLength(RegistryHive, SubKeyCell);
400 FullInformation->MaxValueDataLen =
401 CmiGetMaxValueDataLength(RegistryHive, SubKeyCell);
402 if (SubKeyCell->ClassSize != 0)
404 pClassData = CmiGetBlock(KeyObject->RegistryHive,
405 SubKeyCell->ClassNameOffset,
407 wcsncpy(FullInformation->Class,
408 (PWCHAR) pClassData->Data,
409 SubKeyCell->ClassSize);
410 CmiReleaseBlock(RegistryHive, pClassData);
415 CmiReleaseBlock(RegistryHive, SubKeyCell);
416 ObDereferenceObject (KeyObject);
418 DPRINT("Returning status %x\n", Status);
425 NtEnumerateValueKey(IN HANDLE KeyHandle,
427 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
428 OUT PVOID KeyValueInformation,
430 OUT PULONG ResultLength)
433 PKEY_OBJECT KeyObject;
434 PREGISTRY_HIVE RegistryHive;
436 PVALUE_CELL ValueCell;
438 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
439 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
440 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
442 DPRINT("KH %x I %d KVIC %x KVI %x L %d RL %x\n",
445 KeyValueInformationClass,
450 /* Verify that the handle is valid and is a registry key */
451 Status = ObReferenceObjectByHandle(KeyHandle,
455 (PVOID *) &KeyObject,
458 if (!NT_SUCCESS(Status))
463 VERIFY_KEY_OBJECT(KeyObject);
465 /* Get pointer to KeyCell */
466 KeyCell = KeyObject->KeyCell;
467 RegistryHive = KeyObject->RegistryHive;
469 /* Get Value block of interest */
470 Status = CmiGetValueFromKeyByIndex(RegistryHive,
475 if (!NT_SUCCESS(Status))
477 ObDereferenceObject(KeyObject);
480 else if (ValueCell != NULL)
482 switch (KeyValueInformationClass)
484 case KeyValueBasicInformation:
485 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) +
486 (ValueCell->NameSize + 1) * sizeof(WCHAR);
487 if (Length < *ResultLength)
489 Status = STATUS_BUFFER_OVERFLOW;
493 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
495 ValueBasicInformation->TitleIndex = 0;
496 ValueBasicInformation->Type = ValueCell->DataType;
497 ValueBasicInformation->NameLength =
498 (ValueCell->NameSize + 1) * sizeof(WCHAR);
499 mbstowcs(ValueBasicInformation->Name,
501 ValueCell->NameSize * 2);
502 ValueBasicInformation->Name[ValueCell->NameSize] = 0;
506 case KeyValuePartialInformation:
507 *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
508 (ValueCell->DataSize & LONG_MAX);
509 if (Length < *ResultLength)
511 Status = STATUS_BUFFER_OVERFLOW;
515 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
517 ValuePartialInformation->TitleIndex = 0;
518 ValuePartialInformation->Type = ValueCell->DataType;
519 ValuePartialInformation->DataLength = ValueCell->DataSize & LONG_MAX;
520 if(ValueCell->DataSize >0)
522 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
523 RtlCopyMemory(ValuePartialInformation->Data,
525 ValueCell->DataSize & LONG_MAX);
526 CmiReleaseBlock(RegistryHive, DataCell);
530 RtlCopyMemory(ValuePartialInformation->Data,
531 &ValueCell->DataOffset,
532 ValueCell->DataSize & LONG_MAX);
534 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
538 case KeyValueFullInformation:
539 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
540 ValueCell->NameSize * sizeof(WCHAR) + (ValueCell->DataSize & LONG_MAX);
541 if (Length < *ResultLength)
543 Status = STATUS_BUFFER_OVERFLOW;
547 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
549 ValueFullInformation->TitleIndex = 0;
550 ValueFullInformation->Type = ValueCell->DataType;
551 ValueFullInformation->DataOffset =
552 (DWORD)ValueFullInformation->Name - (DWORD) ValueFullInformation
553 + (ValueCell->NameSize + 1) * sizeof(WCHAR);
554 ValueFullInformation->DataOffset =
555 (ValueFullInformation->DataOffset + 3) & 0xfffffffc;
556 ValueFullInformation->DataLength = ValueCell->DataSize & LONG_MAX;
557 ValueFullInformation->NameLength =
558 (ValueCell->NameSize + 1) * sizeof(WCHAR);
559 mbstowcs(ValueFullInformation->Name,
561 ValueCell->NameSize * 2);
562 ValueFullInformation->Name[ValueCell->NameSize] = 0;
563 if (ValueCell->DataSize > 0)
565 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
566 RtlCopyMemory((PCHAR) ValueFullInformation
567 + ValueFullInformation->DataOffset,
569 ValueCell->DataSize & LONG_MAX);
570 CmiReleaseBlock(RegistryHive, DataCell);
574 RtlCopyMemory((PCHAR) ValueFullInformation
575 + ValueFullInformation->DataOffset,
576 &ValueCell->DataOffset,
577 ValueCell->DataSize & LONG_MAX);
585 Status = STATUS_UNSUCCESSFUL;
587 ObDereferenceObject(KeyObject);
594 NtFlushKey(IN HANDLE KeyHandle)
597 PKEY_OBJECT KeyObject;
598 PREGISTRY_HIVE RegistryHive;
599 WCHAR LogName[MAX_PATH];
600 UNICODE_STRING TmpFileName;
602 // HANDLE FileHandleLog;
603 OBJECT_ATTRIBUTES ObjectAttributes;
605 LARGE_INTEGER fileOffset;
609 DPRINT("KeyHandle %x\n", KeyHandle);
611 /* Verify that the handle is valid and is a registry key */
612 Status = ObReferenceObjectByHandle(KeyHandle,
616 (PVOID *) &KeyObject,
619 if (!NT_SUCCESS(Status))
624 VERIFY_KEY_OBJECT(KeyObject);
626 RegistryHive = KeyObject->RegistryHive;
627 // KeAcquireSpinLock(&RegistryHive->RegLock, &OldIrql);
628 /* Then write changed blocks in .log */
629 wcscpy(LogName,RegistryHive->Filename.Buffer);
630 wcscat(LogName,L".log");
631 RtlInitUnicodeString (&TmpFileName, LogName);
632 InitializeObjectAttributes(&ObjectAttributes,
638 /* BEGIN FIXME : actually (26 November 200) vfatfs.sys can't create new files
639 so we can't create log file
640 Status = ZwCreateFile(&FileHandleLog,
645 FILE_ATTRIBUTE_NORMAL,
652 if (!NT_SUCCESS(Status))
654 ObDereferenceObject(KeyObject);
658 Status = ZwWriteFile(FileHandleLog,
663 RegistryHive->HiveHeader,
668 if (!NT_SUCCESS(Status))
670 ZwClose(FileHandleLog);
671 ObDereferenceObject(KeyObject);
675 for (i = 0; i < RegistryHive->BlockListSize ; i++)
677 if ( RegistryHive->BlockList[i]->DateModified.dwHighDateTime
678 > RegistryHive->HiveHeader->DateModified.dwHighDateTime
679 || (RegistryHive->BlockList[i]->DateModified.dwHighDateTime
680 == RegistryHive->HiveHeader->DateModified.dwHighDateTime
681 && RegistryHive->BlockList[i]->DateModified.dwLowDateTime
682 > RegistryHive->HiveHeader->DateModified.dwLowDateTime
686 Status = ZwWriteFile(FileHandleLog,
691 RegistryHive->BlockList[i],
692 RegistryHive->BlockList[i]->BlockSize ,
696 if (!NT_SUCCESS(Status))
698 ZwClose(FileHandleLog);
699 ObDereferenceObject(KeyObject);
703 ZwClose(FileHandleLog);
706 /* Update header of RegistryHive with Version >VersionOld */
707 /* this allow recover if system crash while updating hove file */
708 InitializeObjectAttributes(&ObjectAttributes,
709 &RegistryHive->Filename,
714 Status = NtOpenFile(&FileHandle,
719 FILE_SYNCHRONOUS_IO_NONALERT);
721 if (!NT_SUCCESS(Status))
723 ObDereferenceObject(KeyObject);
727 RegistryHive->HiveHeader->Version++;
729 Status = ZwWriteFile(FileHandle,
734 RegistryHive->HiveHeader,
739 if (!NT_SUCCESS(Status))
742 ObDereferenceObject(KeyObject);
746 /* Update changed blocks in file */
747 fileOffset.u.HighPart = 0;
748 for (i = 0; i < RegistryHive->BlockListSize ; i++)
750 if (RegistryHive->BlockList[i]->DateModified.dwHighDateTime
751 > RegistryHive->HiveHeader->DateModified.dwHighDateTime
752 || (RegistryHive->BlockList[i]->DateModified.dwHighDateTime
753 == RegistryHive->HiveHeader->DateModified.dwHighDateTime
754 && RegistryHive->BlockList[i]->DateModified.dwLowDateTime
755 > RegistryHive->HiveHeader->DateModified.dwLowDateTime
759 fileOffset.u.LowPart = RegistryHive->BlockList[i]->BlockOffset+4096;
760 Status = NtWriteFile(FileHandle,
765 RegistryHive->BlockList[i],
766 RegistryHive->BlockList[i]->BlockSize ,
770 if (!NT_SUCCESS(Status))
773 ObDereferenceObject(KeyObject);
779 /* Change version in header */
780 RegistryHive->HiveHeader->VersionOld = RegistryHive->HiveHeader->Version;
781 ZwQuerySystemTime((PTIME) &RegistryHive->HiveHeader->DateModified);
783 /* Calculate checksum */
784 RegistryHive->HiveHeader->Checksum = 0;
785 pEntDword = (DWORD *) RegistryHive->HiveHeader;
786 for (i = 0; i < 127 ; i++)
788 RegistryHive->HiveHeader->Checksum ^= pEntDword[i];
791 /* Write new header */
792 fileOffset.u.LowPart = 0;
793 Status = ZwWriteFile(FileHandle,
798 RegistryHive->HiveHeader,
803 if (!NT_SUCCESS(Status))
806 ObDereferenceObject(KeyObject);
811 // KeReleaseSpinLock(&RegistryHive->RegLock, OldIrql);
812 ObDereferenceObject(KeyObject);
813 return STATUS_SUCCESS;
818 NtOpenKey(OUT PHANDLE KeyHandle,
819 IN ACCESS_MASK DesiredAccess,
820 IN POBJECT_ATTRIBUTES ObjectAttributes)
822 UNICODE_STRING RemainingPath;
826 DPRINT("KH %x DA %x OA %x OA->ON %x\n",
830 ObjectAttributes ? ObjectAttributes->ObjectName : NULL);
832 RemainingPath.Buffer = NULL;
833 Status = ObFindObject(ObjectAttributes,
837 if (!NT_SUCCESS(Status))
842 VERIFY_KEY_OBJECT((PKEY_OBJECT) Object);
844 DPRINT("RemainingPath.Buffer %x\n", RemainingPath.Buffer);
846 if ((RemainingPath.Buffer != NULL) && (RemainingPath.Buffer[0] != 0))
848 ObDereferenceObject(Object);
849 return(STATUS_UNSUCCESSFUL);
852 /* Fail if the key has been deleted */
853 if (((PKEY_OBJECT)Object)->Flags & KO_MARKED_FOR_DELETE)
855 ObDereferenceObject(Object);
856 return(STATUS_UNSUCCESSFUL);
859 Status = ObCreateHandle(PsGetCurrentProcess(),
864 ObDereferenceObject(Object);
866 if (!NT_SUCCESS(Status))
871 return(STATUS_SUCCESS);
876 NtQueryKey(IN HANDLE KeyHandle,
877 IN KEY_INFORMATION_CLASS KeyInformationClass,
878 OUT PVOID KeyInformation,
880 OUT PULONG ResultLength)
882 PKEY_BASIC_INFORMATION BasicInformation;
883 PKEY_NODE_INFORMATION NodeInformation;
884 PKEY_FULL_INFORMATION FullInformation;
885 PREGISTRY_HIVE RegistryHive;
886 PDATA_CELL pClassData;
887 PKEY_OBJECT KeyObject;
891 DPRINT("KH %x KIC %x KI %x L %d RL %x\n",
898 /* Verify that the handle is valid and is a registry key */
899 Status = ObReferenceObjectByHandle(KeyHandle,
903 (PVOID *) &KeyObject,
906 if (!NT_SUCCESS(Status))
911 VERIFY_KEY_OBJECT(KeyObject);
913 /* Get pointer to KeyCell */
914 KeyCell = KeyObject->KeyCell;
915 RegistryHive = KeyObject->RegistryHive;
917 Status = STATUS_SUCCESS;
918 switch (KeyInformationClass)
920 case KeyBasicInformation:
921 /* Check size of buffer */
922 if (Length < sizeof(KEY_BASIC_INFORMATION) +
923 KeyObject->NameSize * sizeof(WCHAR))
925 Status = STATUS_BUFFER_OVERFLOW;
929 /* Fill buffer with requested info */
930 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
931 BasicInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
932 BasicInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
933 BasicInformation->TitleIndex = 0;
934 BasicInformation->NameLength = (KeyObject->NameSize) * sizeof(WCHAR);
935 mbstowcs(BasicInformation->Name,
937 KeyObject->NameSize*sizeof(WCHAR));
938 *ResultLength = sizeof(KEY_BASIC_INFORMATION) +
939 KeyObject->NameSize * sizeof(WCHAR);
943 case KeyNodeInformation:
944 /* Check size of buffer */
945 if (Length < sizeof(KEY_NODE_INFORMATION)
946 + KeyObject->NameSize * sizeof(WCHAR)
947 + KeyCell->ClassSize)
949 Status = STATUS_BUFFER_OVERFLOW;
953 /* Fill buffer with requested info */
954 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
955 NodeInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
956 NodeInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
957 NodeInformation->TitleIndex = 0;
958 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
959 KeyObject->NameSize * sizeof(WCHAR);
960 NodeInformation->ClassLength = KeyCell->ClassSize;
961 NodeInformation->NameLength = KeyObject->NameSize * sizeof(WCHAR);
962 mbstowcs(NodeInformation->Name,
964 KeyObject->NameSize * sizeof(WCHAR));
966 if (KeyCell->ClassSize != 0)
968 pClassData = CmiGetBlock(KeyObject->RegistryHive,
969 KeyCell->ClassNameOffset,
971 wcsncpy(NodeInformation->Name + KeyObject->NameSize * sizeof(WCHAR),
972 (PWCHAR)pClassData->Data,
974 CmiReleaseBlock(RegistryHive, pClassData);
976 *ResultLength = sizeof(KEY_NODE_INFORMATION)
977 + KeyObject->NameSize * sizeof(WCHAR)
978 + KeyCell->ClassSize;
982 case KeyFullInformation:
983 /* Check size of buffer */
984 if (Length < sizeof(KEY_FULL_INFORMATION) + KeyCell->ClassSize)
986 Status = STATUS_BUFFER_OVERFLOW;
990 /* Fill buffer with requested info */
991 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
992 FullInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
993 FullInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
994 FullInformation->TitleIndex = 0;
995 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR);
996 FullInformation->ClassLength = KeyCell->ClassSize;
997 FullInformation->SubKeys = KeyCell->NumberOfSubKeys;
998 FullInformation->MaxNameLen =
999 CmiGetMaxNameLength(RegistryHive, KeyCell);
1000 FullInformation->MaxClassLen =
1001 CmiGetMaxClassLength(RegistryHive, KeyCell);
1002 FullInformation->Values = KeyCell->NumberOfValues;
1003 FullInformation->MaxValueNameLen =
1004 CmiGetMaxValueNameLength(RegistryHive, KeyCell);
1005 FullInformation->MaxValueDataLen =
1006 CmiGetMaxValueDataLength(RegistryHive, KeyCell);
1007 if (KeyCell->ClassSize != 0)
1009 pClassData=CmiGetBlock(KeyObject->RegistryHive,
1010 KeyCell->ClassNameOffset,
1012 wcsncpy(FullInformation->Class,
1013 (PWCHAR)pClassData->Data,
1014 KeyCell->ClassSize);
1015 CmiReleaseBlock(RegistryHive, pClassData);
1017 *ResultLength = sizeof(KEY_FULL_INFORMATION) + KeyCell->ClassSize;
1022 ObDereferenceObject(KeyObject);
1028 NtQueryValueKey(IN HANDLE KeyHandle,
1029 IN PUNICODE_STRING ValueName,
1030 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
1031 OUT PVOID KeyValueInformation,
1033 OUT PULONG ResultLength)
1036 PKEY_OBJECT KeyObject;
1037 PREGISTRY_HIVE RegistryHive;
1039 PVALUE_CELL ValueCell;
1040 PDATA_CELL DataCell;
1041 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
1042 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
1043 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
1044 char ValueName2[MAX_PATH];
1046 DPRINT("NtQueryValueKey(KeyHandle %x ValueName %S Length %x)\n",
1047 KeyHandle, ValueName->Buffer, Length);
1049 wcstombs(ValueName2, ValueName->Buffer, ValueName->Length >> 1);
1050 ValueName2[ValueName->Length >> 1] = 0;
1052 /* Verify that the handle is valid and is a registry key */
1053 Status = ObReferenceObjectByHandle(KeyHandle,
1057 (PVOID *)&KeyObject,
1060 if (!NT_SUCCESS(Status))
1062 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
1066 VERIFY_KEY_OBJECT(KeyObject);
1068 /* Get pointer to KeyCell */
1069 KeyCell = KeyObject->KeyCell;
1070 RegistryHive = KeyObject->RegistryHive;
1071 /* Get Value block of interest */
1072 Status = CmiScanKeyForValue(RegistryHive,
1077 if (!NT_SUCCESS(Status))
1079 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1080 ObDereferenceObject(KeyObject);
1083 else if (ValueCell != NULL)
1085 switch (KeyValueInformationClass)
1087 case KeyValueBasicInformation:
1088 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION)
1089 + ValueCell->NameSize * sizeof(WCHAR);
1090 if (Length < *ResultLength)
1092 Status = STATUS_BUFFER_TOO_SMALL;
1096 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
1097 KeyValueInformation;
1098 ValueBasicInformation->TitleIndex = 0;
1099 ValueBasicInformation->Type = ValueCell->DataType;
1100 ValueBasicInformation->NameLength =
1101 (ValueCell->NameSize + 1) * sizeof(WCHAR);
1102 mbstowcs(ValueBasicInformation->Name,
1103 ValueCell->Name,ValueCell->NameSize * 2);
1104 ValueBasicInformation->Name[ValueCell->NameSize] = 0;
1108 case KeyValuePartialInformation:
1109 *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION)
1110 + (ValueCell->DataSize & LONG_MAX);
1111 if (Length < *ResultLength)
1113 Status = STATUS_BUFFER_TOO_SMALL;
1117 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
1118 KeyValueInformation;
1119 ValuePartialInformation->TitleIndex = 0;
1120 ValuePartialInformation->Type = ValueCell->DataType;
1121 ValuePartialInformation->DataLength = ValueCell->DataSize & LONG_MAX;
1122 if (ValueCell->DataSize > 0)
1124 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1125 RtlCopyMemory(ValuePartialInformation->Data,
1127 ValueCell->DataSize & LONG_MAX);
1128 CmiReleaseBlock(RegistryHive, DataCell);
1132 RtlCopyMemory(ValuePartialInformation->Data,
1133 &ValueCell->DataOffset,
1134 ValueCell->DataSize & LONG_MAX);
1139 case KeyValueFullInformation:
1140 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION)
1141 + (ValueCell->NameSize -1) * sizeof(WCHAR)
1142 + (ValueCell->DataSize & LONG_MAX);
1143 if (Length < *ResultLength)
1145 Status = STATUS_BUFFER_TOO_SMALL;
1149 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
1150 KeyValueInformation;
1151 ValueFullInformation->TitleIndex = 0;
1152 ValueFullInformation->Type = ValueCell->DataType;
1153 ValueFullInformation->DataOffset =
1154 (DWORD)ValueFullInformation->Name - (DWORD)ValueFullInformation
1155 + (ValueCell->NameSize + 1) * sizeof(WCHAR);
1156 ValueFullInformation->DataOffset =
1157 (ValueFullInformation->DataOffset + 3) &0xfffffffc;
1158 ValueFullInformation->DataLength = ValueCell->DataSize & LONG_MAX;
1159 ValueFullInformation->NameLength =
1160 (ValueCell->NameSize + 1) * sizeof(WCHAR);
1161 mbstowcs(ValueFullInformation->Name, ValueCell->Name,ValueCell->NameSize*2);
1162 ValueFullInformation->Name[ValueCell->NameSize] = 0;
1163 if (ValueCell->DataSize > 0)
1165 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1166 RtlCopyMemory((PCHAR) ValueFullInformation
1167 + ValueFullInformation->DataOffset,
1169 ValueCell->DataSize & LONG_MAX);
1170 CmiReleaseBlock(RegistryHive, DataCell);
1174 RtlCopyMemory((PCHAR) ValueFullInformation
1175 + ValueFullInformation->DataOffset,
1176 &ValueCell->DataOffset,
1177 ValueCell->DataSize & LONG_MAX);
1185 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1188 ObDereferenceObject(KeyObject);
1195 NtSetValueKey(IN HANDLE KeyHandle,
1196 IN PUNICODE_STRING ValueName,
1197 IN ULONG TitleIndex,
1203 PKEY_OBJECT KeyObject;
1204 PREGISTRY_HIVE RegistryHive;
1206 PVALUE_CELL ValueCell;
1207 BLOCK_OFFSET VBOffset;
1208 char ValueName2[MAX_PATH];
1209 PDATA_CELL DataCell;
1210 PDATA_CELL NewDataCell;
1212 ULONG DesiredAccess;
1215 DPRINT("KeyHandle %x ValueName %S Type %d\n",
1216 KeyHandle, ValueName? ValueName->Buffer : NULL, Type);
1218 wcstombs(ValueName2,ValueName->Buffer, ValueName->Length >> 1);
1219 ValueName2[ValueName->Length>>1] = 0;
1221 DesiredAccess = KEY_SET_VALUE;
1222 if (Type == REG_LINK)
1223 DesiredAccess |= KEY_CREATE_LINK;
1225 /* Verify that the handle is valid and is a registry key */
1226 Status = ObReferenceObjectByHandle(KeyHandle,
1230 (PVOID *)&KeyObject,
1232 if (!NT_SUCCESS(Status))
1235 VERIFY_KEY_OBJECT(KeyObject);
1237 /* Get pointer to key cell */
1238 KeyCell = KeyObject->KeyCell;
1239 RegistryHive = KeyObject->RegistryHive;
1240 Status = CmiScanKeyForValue(RegistryHive,
1245 if (!NT_SUCCESS(Status))
1247 DPRINT1("Value not found. Status 0x%X\n", Status);
1249 ObDereferenceObject(KeyObject);
1253 // KeAcquireSpinLock(&RegistryHive->RegLock, &OldIrql);
1255 if (ValueCell == NULL)
1257 Status = CmiAddValueToKey(RegistryHive,
1264 if (!NT_SUCCESS(Status))
1266 DPRINT1("Cannot add value. Status 0x%X\n", Status);
1268 ObDereferenceObject(KeyObject);
1273 DPRINT("DataSize (%d)\n", DataSize);
1275 /* If datasize <= 4 then write in valueblock directly */
1278 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1279 if ((ValueCell->DataSize >= 0) &&
1280 (DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL)))
1282 CmiDestroyBlock(RegistryHive, DataCell, ValueCell->DataOffset);
1285 RtlCopyMemory(&ValueCell->DataOffset, Data, DataSize);
1286 ValueCell->DataSize = DataSize | 0x80000000;
1287 ValueCell->DataType = Type;
1288 RtlMoveMemory(&ValueCell->DataOffset, Data, DataSize);
1290 /* If new data size is <= current then overwrite current data */
1291 else if (DataSize <= (ValueCell->DataSize & 0x7fffffff))
1293 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset,&pBin);
1294 RtlCopyMemory(DataCell->Data, Data, DataSize);
1295 ValueCell->DataSize = DataSize;
1296 ValueCell->DataType = Type;
1297 CmiReleaseBlock(RegistryHive, DataCell);
1298 /* Update time of heap */
1299 if (IsPermanentHive(RegistryHive))
1301 ZwQuerySystemTime((PTIME) &pBin->DateModified);
1306 BLOCK_OFFSET NewOffset;
1308 /* Destroy current data block and allocate a new one */
1309 if ((ValueCell->DataSize >= 0) &&
1310 (DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL)))
1312 CmiDestroyBlock(RegistryHive, DataCell, ValueCell->DataOffset);
1314 Status = CmiAllocateBlock(RegistryHive,
1315 (PVOID *)&NewDataCell,
1318 RtlCopyMemory(&NewDataCell->Data[0], Data, DataSize);
1319 ValueCell->DataSize = DataSize;
1320 ValueCell->DataType = Type;
1321 CmiReleaseBlock(RegistryHive, NewDataCell);
1322 ValueCell->DataOffset = NewOffset;
1325 if (strcmp(ValueName2, "SymbolicLinkValue") == 0)
1327 KeyCell->Type = REG_LINK_KEY_CELL_TYPE;
1330 /* Update time of heap */
1331 if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
1333 ZwQuerySystemTime((PTIME) &pBin->DateModified);
1337 // KeReleaseSpinLock(&RegistryHive->RegLock, OldIrql);
1339 ObDereferenceObject(KeyObject);
1341 DPRINT("Return Status 0x%X\n", Status);
1348 NtDeleteValueKey(IN HANDLE KeyHandle,
1349 IN PUNICODE_STRING ValueName)
1351 PREGISTRY_HIVE RegistryHive;
1352 CHAR ValueName2[MAX_PATH];
1353 PKEY_OBJECT KeyObject;
1358 wcstombs(ValueName2, ValueName->Buffer, ValueName->Length >> 1);
1359 ValueName2[ValueName->Length>>1] = 0;
1361 /* Verify that the handle is valid and is a registry key */
1362 Status = ObReferenceObjectByHandle(KeyHandle,
1366 (PVOID *)&KeyObject,
1369 if (!NT_SUCCESS(Status))
1374 VERIFY_KEY_OBJECT(KeyObject);
1376 /* Get pointer to KeyCell */
1377 KeyCell = KeyObject->KeyCell;
1378 RegistryHive = KeyObject->RegistryHive;
1379 // KeAcquireSpinLock(&RegistryHive->RegLock, &OldIrql);
1380 Status = CmiDeleteValueFromKey(RegistryHive, KeyCell, ValueName2);
1381 // KeReleaseSpinLock(&RegistryHive->RegLock, OldIrql);
1382 ObDereferenceObject(KeyObject);
1389 NtLoadKey(PHANDLE KeyHandle,
1390 POBJECT_ATTRIBUTES ObjectAttributes)
1392 return NtLoadKey2(KeyHandle, ObjectAttributes, 0);
1397 NtLoadKey2(IN PHANDLE KeyHandle,
1398 IN POBJECT_ATTRIBUTES ObjectAttributes,
1407 IN HANDLE KeyHandle,
1409 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1410 IN PVOID ApcContext OPTIONAL,
1411 OUT PIO_STATUS_BLOCK IoStatusBlock,
1412 IN ULONG CompletionFilter,
1413 IN BOOLEAN Asynchroneous,
1414 OUT PVOID ChangeBuffer,
1416 IN BOOLEAN WatchSubtree)
1423 NtQueryMultipleValueKey(IN HANDLE KeyHandle,
1424 IN OUT PKEY_VALUE_ENTRY ValueList,
1425 IN ULONG NumberOfValues,
1427 IN OUT PULONG Length,
1428 OUT PULONG ReturnLength)
1430 PREGISTRY_HIVE RegistryHive;
1431 UCHAR ValueName[MAX_PATH];
1432 PVALUE_CELL ValueCell;
1433 PKEY_OBJECT KeyObject;
1434 PDATA_CELL DataCell;
1435 ULONG BufferLength = 0;
1441 /* Verify that the handle is valid and is a registry key */
1442 Status = ObReferenceObjectByHandle(KeyHandle,
1446 (PVOID *) &KeyObject,
1448 if (!NT_SUCCESS(Status))
1450 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
1454 VERIFY_KEY_OBJECT(KeyObject);
1456 /* Get pointer to KeyCell */
1457 KeyCell = KeyObject->KeyCell;
1458 RegistryHive = KeyObject->RegistryHive;
1460 DataPtr = (PUCHAR) Buffer;
1462 for (i = 0; i < NumberOfValues; i++)
1465 ValueList[i].ValueName->Buffer,
1466 ValueList[i].ValueName->Length >> 1);
1467 ValueName[ValueList[i].ValueName->Length >> 1] = 0;
1469 DPRINT("ValueName: '%s'\n", ValueName);
1471 /* Get Value block of interest */
1472 Status = CmiScanKeyForValue(RegistryHive,
1478 if (!NT_SUCCESS(Status))
1480 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1483 else if (ValueCell == NULL)
1485 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1489 BufferLength = (BufferLength + 3) & 0xfffffffc;
1491 if (BufferLength + (ValueCell->DataSize & LONG_MAX) <= *Length)
1493 DataPtr = (PUCHAR)(((ULONG)DataPtr + 3) & 0xfffffffc);
1495 ValueList[i].Type = ValueCell->DataType;
1496 ValueList[i].DataLength = ValueCell->DataSize & LONG_MAX;
1497 ValueList[i].DataOffset = (ULONG) DataPtr - (ULONG) Buffer;
1499 if (ValueCell->DataSize > 0)
1501 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1502 RtlCopyMemory(DataPtr, DataCell->Data, ValueCell->DataSize & LONG_MAX);
1503 CmiReleaseBlock(RegistryHive, DataCell);
1507 RtlCopyMemory(DataPtr,
1508 &ValueCell->DataOffset,
1509 ValueCell->DataSize & LONG_MAX);
1512 DataPtr += ValueCell->DataSize & LONG_MAX;
1516 Status = STATUS_BUFFER_TOO_SMALL;
1519 BufferLength += ValueCell->DataSize & LONG_MAX;
1522 if (NT_SUCCESS(Status))
1523 *Length = BufferLength;
1525 *ReturnLength = BufferLength;
1527 ObDereferenceObject(KeyObject);
1529 DPRINT("Return Status 0x%X\n", Status);
1537 IN POBJECT_ATTRIBUTES ObjectAttributes,
1539 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
1548 IN HANDLE KeyHandle,
1549 IN HANDLE FileHandle,
1550 IN ULONG RestoreFlags
1559 IN HANDLE KeyHandle,
1560 IN HANDLE FileHandle)
1567 NtSetInformationKey(
1568 IN HANDLE KeyHandle,
1569 IN CINT KeyInformationClass,
1570 IN PVOID KeyInformation,
1571 IN ULONG KeyInformationLength)
1578 NtUnloadKey(IN HANDLE KeyHandle)
1585 NtInitializeRegistry(IN BOOLEAN SetUpBoot)
1587 NTSTATUS Status = STATUS_ACCESS_DENIED;
1589 if (CmiRegistryInitialized == FALSE)
1591 /* FIXME: save boot log file */
1593 Status = CmiInitHives(SetUpBoot);
1595 CmiRegistryInitialized = TRUE;