- Implement NtEnumerateValueKey as a simpler wrapper.

- Implement CmEnumerateValueKey. Simply calls already-existing Value Cache routines (CmpGetValueListFromCache, CmpGetValueKeyFromCache and CmpQueryKeyValueData) to do all the work.

svn path=/trunk/; revision=26778
This commit is contained in:
Alex Ionescu 2007-05-14 06:40:40 +00:00
parent 3ecce0a306
commit 934cae8069
4 changed files with 189 additions and 269 deletions

View file

@ -284,6 +284,23 @@ CmQueryValueKey(IN PKEY_OBJECT KeyObject,
IN ULONG Length,
IN PULONG ResultLength);
NTSTATUS
NTAPI
CmEnumerateValueKey(IN PKEY_OBJECT KeyObject,
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
IN PVOID KeyValueInformation,
IN ULONG Length,
IN PULONG ResultLength);
NTSTATUS
NTAPI
CmSetValueKey(IN PKEY_OBJECT KeyObject,
IN PUNICODE_STRING ValueName,
IN ULONG Type,
IN PVOID Data,
IN ULONG DataSize);
NTSTATUS
CmiAllocateHashTableCell(IN PEREGISTRY_HIVE RegistryHive,
OUT PHASH_TABLE_CELL *HashBlock,
@ -304,14 +321,6 @@ CmiAddKeyToHashTable(PEREGISTRY_HIVE RegistryHive,
PCM_KEY_NODE NewKeyCell,
HCELL_INDEX NKBOffset);
NTSTATUS
NTAPI
CmSetValueKey(IN PKEY_OBJECT KeyObject,
IN PUNICODE_STRING ValueName,
IN ULONG Type,
IN PVOID Data,
IN ULONG DataSize);
NTSTATUS
CmiRemoveKeyFromHashTable(PEREGISTRY_HIVE RegistryHive,
PHASH_TABLE_CELL HashBlock,

View file

@ -830,277 +830,61 @@ NtEnumerateKey(IN HANDLE KeyHandle,
return(Status);
}
NTSTATUS STDCALL
NTSTATUS
NTAPI
NtEnumerateValueKey(IN HANDLE KeyHandle,
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength)
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength)
{
NTSTATUS Status;
PKEY_OBJECT KeyObject;
PEREGISTRY_HIVE RegistryHive;
PCM_KEY_NODE KeyCell;
PCM_KEY_VALUE ValueCell;
PVOID DataCell;
ULONG NameSize, DataSize;
REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo;
REG_POST_OPERATION_INFORMATION PostOperationInfo;
PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
NTSTATUS Status;
PKEY_OBJECT KeyObject;
REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo;
REG_POST_OPERATION_INFORMATION PostOperationInfo;
PAGED_CODE();
PAGED_CODE();
/* Verify that the handle is valid and is a registry key */
Status = ObReferenceObjectByHandle(KeyHandle,
KEY_QUERY_VALUE,
CmpKeyObjectType,
ExGetPreviousMode(),
(PVOID *)&KeyObject,
NULL);
if (!NT_SUCCESS(Status)) return Status;
DPRINT("KH 0x%p I %d KVIC %x KVI 0x%p L %d RL 0x%p\n",
KeyHandle,
Index,
KeyValueInformationClass,
KeyValueInformation,
Length,
ResultLength);
/* Setup the callback */
PostOperationInfo.Object = (PVOID)KeyObject;
EnumerateValueKeyInfo.Object = (PVOID)KeyObject;
EnumerateValueKeyInfo.Index = Index;
EnumerateValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
EnumerateValueKeyInfo.KeyValueInformation = KeyValueInformation;
EnumerateValueKeyInfo.Length = Length;
EnumerateValueKeyInfo.ResultLength = ResultLength;
/* Verify that the handle is valid and is a registry key */
Status = ObReferenceObjectByHandle(KeyHandle,
KEY_QUERY_VALUE,
CmpKeyObjectType,
ExGetPreviousMode(),
(PVOID *) &KeyObject,
NULL);
if (!NT_SUCCESS(Status))
/* Do the callback */
Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey,
&EnumerateValueKeyInfo);
if (NT_SUCCESS(Status))
{
return Status;
/* Call the internal API */
Status = CmEnumerateValueKey(KeyObject,
Index,
KeyValueInformationClass,
KeyValueInformation,
Length,
ResultLength);
/* Do the post callback */
PostOperationInfo.Status = Status;
CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &PostOperationInfo);
}
PostOperationInfo.Object = (PVOID)KeyObject;
EnumerateValueKeyInfo.Object = (PVOID)KeyObject;
EnumerateValueKeyInfo.Index = Index;
EnumerateValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
EnumerateValueKeyInfo.KeyValueInformation = KeyValueInformation;
EnumerateValueKeyInfo.Length = Length;
EnumerateValueKeyInfo.ResultLength = ResultLength;
Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey, &EnumerateValueKeyInfo);
if (!NT_SUCCESS(Status))
{
PostOperationInfo.Status = Status;
CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &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;
/* Get Value block of interest */
Status = CmiGetValueFromKeyByIndex(RegistryHive,
KeyCell,
Index,
&ValueCell);
if (!NT_SUCCESS(Status))
{
ExReleaseResourceLite(&CmpRegistryLock);
KeLeaveCriticalRegion();
ObDereferenceObject(KeyObject);
PostOperationInfo.Status = Status;
CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &PostOperationInfo);
return Status;
}
if (ValueCell != NULL)
{
switch (KeyValueInformationClass)
{
case KeyValueBasicInformation:
NameSize = ValueCell->NameSize;
if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
{
NameSize *= sizeof(WCHAR);
}
*ResultLength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) + NameSize;
if (Length < FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]))
{
Status = STATUS_BUFFER_TOO_SMALL;
}
else
{
ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
KeyValueInformation;
ValueBasicInformation->TitleIndex = 0;
ValueBasicInformation->Type = ValueCell->DataType;
ValueBasicInformation->NameLength = NameSize;
if (Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) <
NameSize)
{
NameSize = Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
{
CmiCopyPackedName(ValueBasicInformation->Name,
ValueCell->Name,
NameSize / sizeof(WCHAR));
}
else
{
RtlCopyMemory(ValueBasicInformation->Name,
ValueCell->Name,
NameSize);
}
}
break;
case KeyValuePartialInformation:
DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
*ResultLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) +
DataSize;
if (Length < FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]))
{
Status = STATUS_BUFFER_TOO_SMALL;
}
else
{
ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
KeyValueInformation;
ValuePartialInformation->TitleIndex = 0;
ValuePartialInformation->Type = ValueCell->DataType;
ValuePartialInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
if (Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) <
DataSize)
{
DataSize = Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
{
DataCell = HvGetCell (&RegistryHive->Hive, ValueCell->DataOffset);
RtlCopyMemory(ValuePartialInformation->Data,
DataCell,
DataSize);
}
else
{
RtlCopyMemory(ValuePartialInformation->Data,
&ValueCell->DataOffset,
DataSize);
}
}
break;
case KeyValueFullInformation:
NameSize = ValueCell->NameSize;
if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
{
NameSize *= sizeof(WCHAR);
}
DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
*ResultLength = ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
Name[0]) + NameSize, sizeof(PVOID)) + DataSize;
if (Length < FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]))
{
Status = STATUS_BUFFER_TOO_SMALL;
}
else
{
ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
KeyValueInformation;
ValueFullInformation->TitleIndex = 0;
ValueFullInformation->Type = ValueCell->DataType;
ValueFullInformation->NameLength = NameSize;
ValueFullInformation->DataOffset =
(ULONG_PTR)ValueFullInformation->Name -
(ULONG_PTR)ValueFullInformation +
ValueFullInformation->NameLength;
ValueFullInformation->DataOffset =
ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID));
ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
if (Length < ValueFullInformation->DataOffset)
{
NameSize = Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
DataSize = 0;
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
else if (Length - ValueFullInformation->DataOffset < DataSize)
{
DataSize = Length - ValueFullInformation->DataOffset;
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
{
CmiCopyPackedName(ValueFullInformation->Name,
ValueCell->Name,
NameSize / sizeof(WCHAR));
}
else
{
RtlCopyMemory(ValueFullInformation->Name,
ValueCell->Name,
NameSize);
}
if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
{
DataCell = HvGetCell (&RegistryHive->Hive, ValueCell->DataOffset);
RtlCopyMemory((PCHAR) ValueFullInformation
+ ValueFullInformation->DataOffset,
DataCell, DataSize);
}
else
{
RtlCopyMemory((PCHAR) ValueFullInformation
+ ValueFullInformation->DataOffset,
&ValueCell->DataOffset, DataSize);
}
}
break;
default:
DPRINT1("Not handling 0x%x\n", KeyValueInformationClass);
break;
}
}
else
{
Status = STATUS_UNSUCCESSFUL;
}
ExReleaseResourceLite(&CmpRegistryLock);
KeLeaveCriticalRegion();
ObDereferenceObject(KeyObject);
PostOperationInfo.Status = Status;
CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &PostOperationInfo);
return Status;
ObDereferenceObject(KeyObject);
return Status;
}
NTSTATUS STDCALL
NtFlushKey(IN HANDLE KeyHandle)
{

View file

@ -769,6 +769,28 @@ CmpQueryKeyValueData(
OUT PNTSTATUS Status
);
VALUE_SEARCH_RETURN_TYPE
NTAPI
CmpGetValueListFromCache(
IN PKEY_OBJECT KeyObject,
OUT PCELL_DATA *CellData,
OUT BOOLEAN *IndexIsCached,
OUT PHCELL_INDEX ValueListToRelease
);
VALUE_SEARCH_RETURN_TYPE
NTAPI
CmpGetValueKeyFromCache(
IN PKEY_OBJECT KeyObject,
IN PCELL_DATA CellData,
IN ULONG Index,
OUT PCM_CACHED_VALUE **CachedValue,
OUT PCM_KEY_VALUE *Value,
IN BOOLEAN IndexIsCached,
OUT BOOLEAN *ValueIsCached,
OUT PHCELL_INDEX CellToRelease
);
//
// Registry Validation Functions
//

View file

@ -519,3 +519,108 @@ CmQueryValueKey(IN PKEY_OBJECT KeyObject,
KeLeaveCriticalRegion();
return Status;
}
NTSTATUS
NTAPI
CmEnumerateValueKey(IN PKEY_OBJECT KeyObject,
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
IN PVOID KeyValueInformation,
IN ULONG Length,
IN PULONG ResultLength)
{
NTSTATUS Status;
PHHIVE Hive;
PCM_KEY_NODE Parent;
HCELL_INDEX CellToRelease = HCELL_NIL, CellToRelease2 = HCELL_NIL;
VALUE_SEARCH_RETURN_TYPE Result;
BOOLEAN IndexIsCached, ValueIsCached = FALSE;
PCELL_DATA CellData;
PCM_CACHED_VALUE *CachedValue;
PCM_KEY_VALUE ValueData;
PAGED_CODE();
/* 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;
}
/* Make sure the index is valid */
//if (Index >= KeyObject->ValueCache.Count)
if (Index >= KeyObject->KeyCell->ValueList.Count)
{
/* Release the cell and fail */
HvReleaseCell(Hive, KeyObject->KeyCellOffset);
Status = STATUS_NO_MORE_ENTRIES;
goto Quickie;
}
/* Find the value list */
Result = CmpGetValueListFromCache(KeyObject,
&CellData,
&IndexIsCached,
&CellToRelease);
if (Result != SearchSuccess)
{
/* Sanity check */
ASSERT(CellData == NULL);
/* Release the cell and fail */
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Quickie;
}
/* Now get the key value */
Result = CmpGetValueKeyFromCache(KeyObject,
CellData,
Index,
&CachedValue,
&ValueData,
IndexIsCached,
&ValueIsCached,
&CellToRelease2);
if (Result != SearchSuccess)
{
/* Sanity check */
ASSERT(CellToRelease2 == HCELL_NIL);
/* Release the cells and fail */
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Quickie;
}
/* Query the information requested */
Result = CmpQueryKeyValueData(KeyObject,
CachedValue,
ValueData,
ValueIsCached,
KeyValueInformationClass,
KeyValueInformation,
Length,
ResultLength,
&Status);
Quickie:
/* If we have a cell to release, do so */
if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease);
/* Release the parent cell */
HvReleaseCell(Hive, KeyObject->KeyCellOffset);
/* If we have a cell to release, do so */
if (CellToRelease2 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease2);
/* Release hive lock */
ExReleaseResourceLite(&CmpRegistryLock);
KeLeaveCriticalRegion();
return Status;
}