From 64f4f03b9517f667937522fda65b16a2a53a762d Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Mon, 14 May 2007 18:12:57 +0000 Subject: [PATCH] - Make CmiGetMaxClassLength, CmiGetMaxNameLength, CmiGetMaxValueDataLength, CmiGetMaxValueNameLength use PHHIVE and PCM_KEY_NODE instead of PKEY_OBJECT or PERGSITRY_HIVE/PCM_KEY_NDOE so they're consistent. - Implement NtQueryKey as a simple wrapper around CmQueryKey. - Implement CmQueryKey based on previous code, and handle only the classes that the previous code handled, through CmpQueryKeyData. - The CmiGetMax* routines will be depreated soon since they're a perf hit and we should be reading the key node's values instead. svn path=/trunk/; revision=26780 --- reactos/ntoskrnl/cm/cm.h | 16 +- reactos/ntoskrnl/cm/ntfunc.c | 271 ++++++----------------------- reactos/ntoskrnl/cm/regfile.c | 38 ++--- reactos/ntoskrnl/config/cm.h | 14 ++ reactos/ntoskrnl/config/cmapi.c | 293 ++++++++++++++++++++++++++++++++ 5 files changed, 382 insertions(+), 250 deletions(-) diff --git a/reactos/ntoskrnl/cm/cm.h b/reactos/ntoskrnl/cm/cm.h index 088e6db7ac3..dacff7421bd 100644 --- a/reactos/ntoskrnl/cm/cm.h +++ b/reactos/ntoskrnl/cm/cm.h @@ -221,17 +221,17 @@ ULONG CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject); ULONG -CmiGetMaxNameLength(IN PKEY_OBJECT KeyObject); +CmiGetMaxNameLength(IN PHHIVE RegistryHive, IN PCM_KEY_NODE KeyCell); ULONG -CmiGetMaxClassLength(IN PKEY_OBJECT KeyObject); +CmiGetMaxClassLength(IN PHHIVE RegistryHive, IN PCM_KEY_NODE KeyCell); ULONG -CmiGetMaxValueNameLength(IN PEREGISTRY_HIVE RegistryHive, +CmiGetMaxValueNameLength(IN PHHIVE RegistryHive, IN PCM_KEY_NODE KeyCell); ULONG -CmiGetMaxValueDataLength(IN PEREGISTRY_HIVE RegistryHive, +CmiGetMaxValueDataLength(IN PHHIVE RegistryHive, IN PCM_KEY_NODE KeyCell); NTSTATUS @@ -301,6 +301,14 @@ CmSetValueKey(IN PKEY_OBJECT KeyObject, IN PVOID Data, IN ULONG DataSize); +NTSTATUS +NTAPI +CmQueryKey(IN PKEY_OBJECT KeyObject, + IN KEY_INFORMATION_CLASS KeyInformationClass, + IN PVOID KeyInformation, + IN ULONG Length, + IN PULONG ResultLength); + NTSTATUS CmiAllocateHashTableCell(IN PEREGISTRY_HIVE RegistryHive, OUT PHASH_TABLE_CELL *HashBlock, diff --git a/reactos/ntoskrnl/cm/ntfunc.c b/reactos/ntoskrnl/cm/ntfunc.c index 231c32e1c13..efe06117f04 100644 --- a/reactos/ntoskrnl/cm/ntfunc.c +++ b/reactos/ntoskrnl/cm/ntfunc.c @@ -786,13 +786,13 @@ NtEnumerateKey(IN HANDLE KeyHandle, sizeof(WCHAR); FullInformation->ClassLength = SubKeyCell->ClassSize; FullInformation->SubKeys = CmiGetNumberOfSubKeys(KeyObject); //SubKeyCell->SubKeyCounts; - FullInformation->MaxNameLen = CmiGetMaxNameLength(KeyObject); - FullInformation->MaxClassLen = CmiGetMaxClassLength(KeyObject); + FullInformation->MaxNameLen = CmiGetMaxNameLength(&RegistryHive->Hive, SubKeyCell); + FullInformation->MaxClassLen = CmiGetMaxClassLength(&RegistryHive->Hive, SubKeyCell); FullInformation->Values = SubKeyCell->ValueList.Count; FullInformation->MaxValueNameLen = - CmiGetMaxValueNameLength(RegistryHive, SubKeyCell); + CmiGetMaxValueNameLength(&RegistryHive->Hive, SubKeyCell); FullInformation->MaxValueDataLen = - CmiGetMaxValueDataLength(RegistryHive, SubKeyCell); + CmiGetMaxValueDataLength(&RegistryHive->Hive, SubKeyCell); if (Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]) < ClassSize) { @@ -1094,232 +1094,58 @@ openkey_cleanup: return Status; } - -NTSTATUS STDCALL +NTSTATUS +NTAPI NtQueryKey(IN HANDLE KeyHandle, - IN KEY_INFORMATION_CLASS KeyInformationClass, - OUT PVOID KeyInformation, - IN ULONG Length, - OUT PULONG ResultLength) + IN KEY_INFORMATION_CLASS KeyInformationClass, + OUT PVOID KeyInformation, + IN ULONG Length, + OUT PULONG ResultLength) { - PKEY_BASIC_INFORMATION BasicInformation; - PKEY_NODE_INFORMATION NodeInformation; - PKEY_FULL_INFORMATION FullInformation; - PEREGISTRY_HIVE RegistryHive; - PVOID ClassCell; - PKEY_OBJECT KeyObject; - PCM_KEY_NODE KeyCell; - ULONG NameSize, ClassSize; - NTSTATUS Status; - REG_QUERY_KEY_INFORMATION QueryKeyInfo; - REG_POST_OPERATION_INFORMATION PostOperationInfo; + NTSTATUS Status; + PKEY_OBJECT KeyObject; + REG_QUERY_KEY_INFORMATION QueryKeyInfo; + REG_POST_OPERATION_INFORMATION PostOperationInfo; + PAGED_CODE(); - PAGED_CODE(); + /* Verify that the handle is valid and is a registry key */ + Status = ObReferenceObjectByHandle(KeyHandle, + (KeyInformationClass != + KeyNameInformation) ? + KEY_QUERY_VALUE : 0, + CmpKeyObjectType, + ExGetPreviousMode(), + (PVOID *)&KeyObject, + NULL); + if (!NT_SUCCESS(Status)) return Status; - DPRINT("NtQueryKey(KH 0x%p KIC %x KI 0x%p L %d RL 0x%p)\n", - KeyHandle, - KeyInformationClass, - KeyInformation, - Length, - ResultLength); + /* Setup the callback */ + PostOperationInfo.Object = (PVOID)KeyObject; + QueryKeyInfo.Object = (PVOID)KeyObject; + QueryKeyInfo.KeyInformationClass = KeyInformationClass; + QueryKeyInfo.KeyInformation = KeyInformation; + QueryKeyInfo.Length = Length; + QueryKeyInfo.ResultLength = ResultLength; - /* Verify that the handle is valid and is a registry key */ - Status = ObReferenceObjectByHandle(KeyHandle, - (KeyInformationClass != KeyNameInformation ? KEY_QUERY_VALUE : 0), - CmpKeyObjectType, - ExGetPreviousMode(), - (PVOID *) &KeyObject, - NULL); - if (!NT_SUCCESS(Status)) + /* Do the callback */ + Status = CmiCallRegisteredCallbacks(RegNtPreQueryKey, &QueryKeyInfo); + if (NT_SUCCESS(Status)) { - return Status; + /* Call the internal API */ + Status = CmQueryKey(KeyObject, + KeyInformationClass, + KeyInformation, + Length, + ResultLength); + + /* Do the post callback */ + PostOperationInfo.Status = Status; + CmiCallRegisteredCallbacks(RegNtPostQueryKey, &PostOperationInfo); } - PostOperationInfo.Object = (PVOID)KeyObject; - QueryKeyInfo.Object = (PVOID)KeyObject; - QueryKeyInfo.KeyInformationClass = KeyInformationClass; - QueryKeyInfo.KeyInformation = KeyInformation; - QueryKeyInfo.Length = Length; - QueryKeyInfo.ResultLength = ResultLength; - - Status = CmiCallRegisteredCallbacks(RegNtPreQueryKey, &QueryKeyInfo); - if (!NT_SUCCESS(Status)) - { - PostOperationInfo.Status = Status; - CmiCallRegisteredCallbacks(RegNtPostQueryKey, &PostOperationInfo); - ObDereferenceObject(KeyObject); - return Status; - } - - /* Acquire hive lock */ - KeEnterCriticalRegion(); - ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE); - - VERIFY_KEY_OBJECT(KeyObject); - - /* Get pointer to KeyCell */ - KeyCell = KeyObject->KeyCell; - RegistryHive = KeyObject->RegistryHive; - - Status = STATUS_SUCCESS; - switch (KeyInformationClass) - { - case KeyBasicInformation: - NameSize = KeyObject->Name.Length; - - *ResultLength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]); - - /* Check size of buffer */ - if (Length < FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0])) - { - Status = STATUS_BUFFER_TOO_SMALL; - } - else - { - /* Fill buffer with requested info */ - BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation; - BasicInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart; - BasicInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart; - BasicInformation->TitleIndex = 0; - BasicInformation->NameLength = KeyObject->Name.Length; - - if (Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]) < - NameSize) - { - NameSize = Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]); - Status = STATUS_BUFFER_OVERFLOW; - CHECKPOINT; - } - - RtlCopyMemory(BasicInformation->Name, - KeyObject->Name.Buffer, - NameSize); - } - break; - - case KeyNodeInformation: - NameSize = KeyObject->Name.Length; - ClassSize = KeyCell->ClassSize; - - *ResultLength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) + - NameSize + ClassSize; - - /* Check size of buffer */ - if (Length < *ResultLength) - { - Status = STATUS_BUFFER_TOO_SMALL; - } - else - { - /* Fill buffer with requested info */ - NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation; - NodeInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart; - NodeInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart; - NodeInformation->TitleIndex = 0; - NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) + - KeyObject->Name.Length; - NodeInformation->ClassLength = KeyCell->ClassSize; - NodeInformation->NameLength = KeyObject->Name.Length; - - if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) < NameSize) - { - NameSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]); - ClassSize = 0; - Status = STATUS_BUFFER_OVERFLOW; - CHECKPOINT; - } - else if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) - - NameSize < ClassSize) - { - ClassSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) - - NameSize; - Status = STATUS_BUFFER_OVERFLOW; - CHECKPOINT; - } - - RtlCopyMemory(NodeInformation->Name, - KeyObject->Name.Buffer, - NameSize); - - if (ClassSize != 0) - { - ClassCell = HvGetCell (&KeyObject->RegistryHive->Hive, - KeyCell->ClassNameOffset); - RtlCopyMemory (NodeInformation->Name + KeyObject->Name.Length, - ClassCell, - ClassSize); - } - } - break; - - case KeyFullInformation: - ClassSize = KeyCell->ClassSize; - - *ResultLength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + - ClassSize; - - /* Check size of buffer */ - if (Length < FIELD_OFFSET(KEY_FULL_INFORMATION, Class)) - { - Status = STATUS_BUFFER_TOO_SMALL; - } - else - { - /* Fill buffer with requested info */ - FullInformation = (PKEY_FULL_INFORMATION) KeyInformation; - FullInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart; - FullInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart; - FullInformation->TitleIndex = 0; - FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR); - FullInformation->ClassLength = KeyCell->ClassSize; - FullInformation->SubKeys = CmiGetNumberOfSubKeys(KeyObject); //KeyCell->SubKeyCounts; - FullInformation->MaxNameLen = CmiGetMaxNameLength(KeyObject); - FullInformation->MaxClassLen = CmiGetMaxClassLength(KeyObject); - FullInformation->Values = KeyCell->ValueList.Count; - FullInformation->MaxValueNameLen = - CmiGetMaxValueNameLength(RegistryHive, KeyCell); - FullInformation->MaxValueDataLen = - CmiGetMaxValueDataLength(RegistryHive, KeyCell); - - if (Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]) < ClassSize) - { - ClassSize = Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]); - Status = STATUS_BUFFER_OVERFLOW; - CHECKPOINT; - } - - if (ClassSize) - { - ClassCell = HvGetCell (&KeyObject->RegistryHive->Hive, - KeyCell->ClassNameOffset); - RtlCopyMemory (FullInformation->Class, - ClassCell, ClassSize); - } - } - break; - - case KeyNameInformation: - case KeyCachedInformation: - case KeyFlagsInformation: - DPRINT1("Key information class 0x%x not yet implemented!\n", KeyInformationClass); - Status = STATUS_NOT_IMPLEMENTED; - break; - - default: - DPRINT1("Not handling 0x%x\n", KeyInformationClass); - Status = STATUS_INVALID_INFO_CLASS; - break; - } - - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - - PostOperationInfo.Status = Status; - CmiCallRegisteredCallbacks(RegNtPostQueryKey, &PostOperationInfo); - - ObDereferenceObject(KeyObject); - - return(Status); + /* Dereference and return status */ + ObDereferenceObject(KeyObject); + return Status; } NTSTATUS @@ -1371,6 +1197,7 @@ NtQueryValueKey(IN HANDLE KeyHandle, CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo); } + /* Dereference and return status */ ObDereferenceObject(KeyObject); return Status; } diff --git a/reactos/ntoskrnl/cm/regfile.c b/reactos/ntoskrnl/cm/regfile.c index b3350bac3a4..cd137245199 100644 --- a/reactos/ntoskrnl/cm/regfile.c +++ b/reactos/ntoskrnl/cm/regfile.c @@ -124,32 +124,27 @@ CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject) ULONG -CmiGetMaxNameLength(PKEY_OBJECT KeyObject) +CmiGetMaxNameLength(PHHIVE Hive, + PCM_KEY_NODE KeyCell) { PHASH_TABLE_CELL HashBlock; PCM_KEY_NODE CurSubKeyCell; - PCM_KEY_NODE KeyCell; ULONG MaxName; ULONG NameSize; ULONG i; ULONG Storage; - VERIFY_KEY_OBJECT(KeyObject); - - KeyCell = KeyObject->KeyCell; - VERIFY_KEY_CELL(KeyCell); - MaxName = 0; for (Storage = HvStable; Storage < HvMaxStorageType; Storage++) { if (KeyCell->SubKeyLists[Storage] != HCELL_NULL) { - HashBlock = HvGetCell (&KeyObject->RegistryHive->Hive, KeyCell->SubKeyLists[Storage]); + HashBlock = HvGetCell (Hive, KeyCell->SubKeyLists[Storage]); ASSERT(HashBlock->Id == REG_HASH_TABLE_CELL_ID); for (i = 0; i < KeyCell->SubKeyCounts[Storage]; i++) { - CurSubKeyCell = HvGetCell (&KeyObject->RegistryHive->Hive, + CurSubKeyCell = HvGetCell (Hive, HashBlock->Table[i].KeyOffset); NameSize = CurSubKeyCell->NameSize; if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED) @@ -167,32 +162,27 @@ CmiGetMaxNameLength(PKEY_OBJECT KeyObject) ULONG -CmiGetMaxClassLength(PKEY_OBJECT KeyObject) +CmiGetMaxClassLength(PHHIVE Hive, + PCM_KEY_NODE KeyCell) { PHASH_TABLE_CELL HashBlock; PCM_KEY_NODE CurSubKeyCell; - PCM_KEY_NODE KeyCell; ULONG MaxClass; ULONG i; ULONG Storage; - VERIFY_KEY_OBJECT(KeyObject); - - KeyCell = KeyObject->KeyCell; - VERIFY_KEY_CELL(KeyCell); - MaxClass = 0; for (Storage = HvStable; Storage < HvMaxStorageType; Storage++) { if (KeyCell->SubKeyLists[Storage] != HCELL_NULL) { - HashBlock = HvGetCell (&KeyObject->RegistryHive->Hive, + HashBlock = HvGetCell (Hive, KeyCell->SubKeyLists[Storage]); ASSERT(HashBlock->Id == REG_HASH_TABLE_CELL_ID); for (i = 0; i < KeyCell->SubKeyCounts[Storage]; i++) { - CurSubKeyCell = HvGetCell (&KeyObject->RegistryHive->Hive, + CurSubKeyCell = HvGetCell (Hive, HashBlock->Table[i].KeyOffset); if (MaxClass < CurSubKeyCell->ClassSize) @@ -208,7 +198,7 @@ CmiGetMaxClassLength(PKEY_OBJECT KeyObject) ULONG -CmiGetMaxValueNameLength(PEREGISTRY_HIVE RegistryHive, +CmiGetMaxValueNameLength(PHHIVE Hive, PCM_KEY_NODE KeyCell) { PVALUE_LIST_CELL ValueListCell; @@ -225,12 +215,12 @@ CmiGetMaxValueNameLength(PEREGISTRY_HIVE RegistryHive, } MaxValueName = 0; - ValueListCell = HvGetCell (&RegistryHive->Hive, + ValueListCell = HvGetCell (Hive, KeyCell->ValueList.List); for (i = 0; i < KeyCell->ValueList.Count; i++) { - CurValueCell = HvGetCell (&RegistryHive->Hive, + CurValueCell = HvGetCell (Hive, ValueListCell->ValueOffset[i]); if (CurValueCell == NULL) { @@ -256,7 +246,7 @@ CmiGetMaxValueNameLength(PEREGISTRY_HIVE RegistryHive, ULONG -CmiGetMaxValueDataLength(PEREGISTRY_HIVE RegistryHive, +CmiGetMaxValueDataLength(PHHIVE Hive, PCM_KEY_NODE KeyCell) { PVALUE_LIST_CELL ValueListCell; @@ -272,11 +262,11 @@ CmiGetMaxValueDataLength(PEREGISTRY_HIVE RegistryHive, } MaxValueData = 0; - ValueListCell = HvGetCell (&RegistryHive->Hive, KeyCell->ValueList.List); + ValueListCell = HvGetCell (Hive, KeyCell->ValueList.List); for (i = 0; i < KeyCell->ValueList.Count; i++) { - CurValueCell = HvGetCell (&RegistryHive->Hive, + CurValueCell = HvGetCell (Hive, ValueListCell->ValueOffset[i]); if ((MaxValueData < (LONG)(CurValueCell->DataSize & REG_DATA_SIZE_MASK))) { diff --git a/reactos/ntoskrnl/config/cm.h b/reactos/ntoskrnl/config/cm.h index 71df11623e9..672969e0738 100644 --- a/reactos/ntoskrnl/config/cm.h +++ b/reactos/ntoskrnl/config/cm.h @@ -675,6 +675,16 @@ typedef struct _KEY_VALUE_INFORMATION }; } KEY_VALUE_INFORMATION, *PKEY_VALUE_INFORMATION; +typedef struct _KEY_INFORMATION +{ + union + { + KEY_BASIC_INFORMATION KeyBasicInformation; + KEY_FULL_INFORMATION KeyFullInformation; + KEY_NODE_INFORMATION KeyNodeInformation; + }; +} KEY_INFORMATION, *PKEY_INFORMATION; + /////////////////////////////////////////////////////////////////////////////// // // BUGBUG Old Hive Stuff for Temporary Support @@ -718,6 +728,10 @@ extern KTIMER CmiWorkerTimer; VOID NTAPI CmiWorkerThread(IN PVOID Param); PVOID NTAPI CmpRosGetHardwareHive(OUT PULONG Length); NTSTATUS CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1, IN PVOID Argument2); +ULONG CmiGetMaxNameLength(IN PHHIVE RegistryHive, IN PCM_KEY_NODE KeyCell); +ULONG CmiGetMaxClassLength(IN PHHIVE RegistryHive, IN PCM_KEY_NODE KeyCell); +ULONG CmiGetMaxValueNameLength(IN PHHIVE RegistryHive, IN PCM_KEY_NODE KeyCell); +ULONG CmiGetMaxValueDataLength(IN PHHIVE RegistryHive, IN PCM_KEY_NODE KeyCell); VOID CmiSyncHives(VOID); #define HIVE_NO_FILE 0x00000002 /////////////////////////////////////////////////////////////////////////////// diff --git a/reactos/ntoskrnl/config/cmapi.c b/reactos/ntoskrnl/config/cmapi.c index da5e1e5aa76..77afbedd861 100644 --- a/reactos/ntoskrnl/config/cmapi.c +++ b/reactos/ntoskrnl/config/cmapi.c @@ -624,3 +624,296 @@ Quickie: KeLeaveCriticalRegion(); return Status; } + +NTSTATUS +NTAPI +CmpQueryKeyData(IN PHHIVE Hive, + IN PCM_KEY_NODE Node, + IN KEY_INFORMATION_CLASS KeyInformationClass, + IN OUT PVOID KeyInformation, + IN ULONG Length, + IN OUT PULONG ResultLength) +{ + NTSTATUS Status; + ULONG Size, SizeLeft, MinimumSize; + PKEY_INFORMATION Info = (PKEY_INFORMATION)KeyInformation; + USHORT NameLength; + + /* Check if the value is compressed */ + if (Node->Flags & VALUE_COMP_NAME) + { + /* Get the compressed name size */ + NameLength = CmpCompressedNameSize(Node->Name, Node->NameLength); + } + else + { + /* Get the real size */ + NameLength = Node->NameLength; + } + + /* Check what kind of information is being requested */ + switch (KeyInformationClass) + { + /* Basic information */ + case KeyBasicInformation: + + /* This is the size we need */ + Size = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) + NameLength; + + /* And this is the minimum we can work with */ + MinimumSize = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name); + + /* Let the caller know and assume success */ + *ResultLength = Size; + Status = STATUS_SUCCESS; + + /* Check if the bufer we got is too small */ + if (Length < MinimumSize) + { + /* Let the caller know and fail */ + Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + /* Copy the basic information */ + Info->KeyBasicInformation.LastWriteTime = Node->LastWriteTime; + Info->KeyBasicInformation.TitleIndex = 0; + Info->KeyBasicInformation.NameLength = NameLength; + + /* Only the name is left */ + SizeLeft = Length - MinimumSize; + Size = NameLength; + + /* Check if we don't have enough space for the name */ + if (SizeLeft < Size) + { + /* Truncate the name we'll return, and tell the caller */ + Size = SizeLeft; + Status = STATUS_BUFFER_OVERFLOW; + } + + /* Check if this is a compressed key */ + if (Node->Flags & KEY_COMP_NAME) + { + /* Copy the compressed name */ + CmpCopyCompressedName(Info->KeyBasicInformation.Name, + SizeLeft, + Node->Name, + Node->NameLength); + } + else + { + /* Otherwise, copy the raw name */ + RtlCopyMemory(Info->KeyBasicInformation.Name, + Node->Name, + Size); + } + break; + + /* Node information */ + case KeyNodeInformation: + + /* Calculate the size we need */ + Size = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) + + NameLength + + Node->ClassLength; + + /* And the minimum size we can support */ + MinimumSize = FIELD_OFFSET(KEY_NODE_INFORMATION, Name); + + /* Return the size to the caller and assume succes */ + *ResultLength = Size; + Status = STATUS_SUCCESS; + + /* Check if the caller's buffer is too small */ + if (Length < MinimumSize) + { + /* Let them know, and fail */ + Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + /* Copy the basic information */ + Info->KeyNodeInformation.LastWriteTime = Node->LastWriteTime; + Info->KeyNodeInformation.TitleIndex = 0; + Info->KeyNodeInformation.ClassLength = Node->ClassLength; + Info->KeyNodeInformation.NameLength = NameLength; + + /* Now the name is left */ + SizeLeft = Length - MinimumSize; + Size = NameLength; + + /* Check if the name can fit entirely */ + if (SizeLeft < Size) + { + /* It can't, we'll have to truncate. Tell the caller */ + Size = SizeLeft; + Status = STATUS_BUFFER_OVERFLOW; + } + + /* Check if the key node name is compressed */ + if (Node->Flags & KEY_COMP_NAME) + { + /* Copy the compressed name */ + CmpCopyCompressedName(Info->KeyNodeInformation.Name, + SizeLeft, + Node->Name, + Node->NameLength); + } + else + { + /* It isn't, so copy the raw name */ + RtlCopyMemory(Info->KeyNodeInformation.Name, + Node->Name, + Size); + } + + /* Check if the node has a class */ + if (Node->ClassLength > 0) + { + /* It does. We don't support these yet */ + ASSERTMSG("Classes not supported\n", FALSE); + } + else + { + /* It doesn't, so set offset to -1, not 0! */ + Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF; + } + break; + + /* Full information requsted */ + case KeyFullInformation: + + /* This is the size we need */ + Size = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + + Node->ClassLength; + + /* This is what we can work with */ + MinimumSize = FIELD_OFFSET(KEY_FULL_INFORMATION, Class); + + /* Return it to caller and assume success */ + *ResultLength = Size; + Status = STATUS_SUCCESS; + + /* Check if the caller's buffer is to small */ + if (Length < MinimumSize) + { + /* Let them know and fail */ + Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + /* Now copy all the basic information */ + Info->KeyFullInformation.LastWriteTime = Node->LastWriteTime; + Info->KeyFullInformation.TitleIndex = 0; + Info->KeyFullInformation.ClassLength = Node->ClassLength; + Info->KeyFullInformation.SubKeys = Node->SubKeyCounts[HvStable] + + Node->SubKeyCounts[HvVolatile]; + Info->KeyFullInformation.Values = Node->ValueList.Count; + Info->KeyFullInformation.MaxNameLen = CmiGetMaxNameLength(Hive, Node); + Info->KeyFullInformation.MaxClassLen = CmiGetMaxClassLength(Hive, Node); + Info->KeyFullInformation.MaxValueNameLen = CmiGetMaxValueNameLength(Hive, Node); + Info->KeyFullInformation.MaxValueDataLen = CmiGetMaxValueDataLength(Hive, Node); + DPRINT("%d %d %d %d\n", + CmiGetMaxNameLength(Hive, Node), + CmiGetMaxValueDataLength(Hive, Node), + CmiGetMaxValueNameLength(Hive, Node), + CmiGetMaxClassLength(Hive, Node)); + //Info->KeyFullInformation.MaxNameLen = Node->MaxNameLen; + //Info->KeyFullInformation.MaxClassLen = Node->MaxClassLen; + //Info->KeyFullInformation.MaxValueNameLen = Node->MaxValueNameLen; + //Info->KeyFullInformation.MaxValueDataLen = Node->MaxValueDataLen; + + /* Check if we have a class */ + if (Node->ClassLength > 0) + { + /* We do, but we currently don't support this */ + ASSERTMSG("Classes not supported\n", FALSE); + } + else + { + /* We don't have a class, so set offset to -1, not 0! */ + Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF; + } + break; + + /* Any other class that got sent here is invalid! */ + default: + + /* Set failure code */ + Status = STATUS_INVALID_PARAMETER; + break; + } + + /* Return status */ + return Status; +} + +NTSTATUS +NTAPI +CmQueryKey(IN PKEY_OBJECT KeyObject, + IN KEY_INFORMATION_CLASS KeyInformationClass, + IN PVOID KeyInformation, + IN ULONG Length, + IN PULONG ResultLength) +{ + NTSTATUS Status; + PHHIVE Hive; + PCM_KEY_NODE Parent; + + /* Acquire hive lock */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + + /* Get the hive and parent */ + Hive = &KeyObject->RegistryHive->Hive; + Parent = (PCM_KEY_NODE)HvGetCell(Hive, KeyObject->KeyCellOffset); + if (!Parent) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Check what class we got */ + switch (KeyInformationClass) + { + /* Typical information */ + case KeyFullInformation: + case KeyBasicInformation: + case KeyNodeInformation: + + /* Call the internal API */ + Status = CmpQueryKeyData(Hive, + Parent, + KeyInformationClass, + KeyInformation, + Length, + ResultLength); + break; + + /* Unsupported classes for now */ + case KeyNameInformation: + case KeyCachedInformation: + case KeyFlagsInformation: + + /* Print message and fail */ + DPRINT1("Unsupported class: %d!\n", KeyInformationClass); + Status = STATUS_NOT_IMPLEMENTED; + break; + + /* Illegal classes */ + default: + + /* Print message and fail */ + DPRINT1("Unsupported class: %d!\n", KeyInformationClass); + Status = STATUS_INVALID_INFO_CLASS; + break; + } + +Quickie: + /* Release hive lock */ + ExReleaseResourceLite(&CmpRegistryLock); + KeLeaveCriticalRegion(); + return Status; +}