mirror of
https://github.com/reactos/reactos.git
synced 2025-05-31 23:18:39 +00:00
- Implement NtQueryValueKey as a simple wrapper around CmQueryValueKey (same idea as always).
- Add cmvalche.c to deal with Value Caches. Cm implements these to quickly look up either the value list and/or the value index and/or the value data itself. The routines fallback on non-cached access, which is what we currently do, since we don't have value caches yet. - Implement CmQueryValueKey and CmpQueryKeyValueData based on previous code, but update to use value caches and new routines. svn path=/trunk/; revision=26774
This commit is contained in:
parent
6f9af1cef6
commit
c045c30908
7 changed files with 908 additions and 254 deletions
|
@ -48,6 +48,20 @@
|
||||||
#define IsNoFileHive(Hive) ((Hive)->Flags & HIVE_NO_FILE)
|
#define IsNoFileHive(Hive) ((Hive)->Flags & HIVE_NO_FILE)
|
||||||
#define IsNoSynchHive(Hive) ((Hive)->Flags & HIVE_NO_SYNCH)
|
#define IsNoSynchHive(Hive) ((Hive)->Flags & HIVE_NO_SYNCH)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Cached Child List
|
||||||
|
//
|
||||||
|
typedef struct _CACHED_CHILD_LIST
|
||||||
|
{
|
||||||
|
ULONG Count;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
ULONG ValueList;
|
||||||
|
//struct _CM_KEY_CONTROL_BLOCK *RealKcb;
|
||||||
|
struct _KEY_OBJECT *RealKcb;
|
||||||
|
};
|
||||||
|
} CACHED_CHILD_LIST, *PCACHED_CHILD_LIST;
|
||||||
|
|
||||||
/* KEY_OBJECT.Flags */
|
/* KEY_OBJECT.Flags */
|
||||||
|
|
||||||
/* When set, the key is scheduled for deletion, and all
|
/* When set, the key is scheduled for deletion, and all
|
||||||
|
@ -96,6 +110,8 @@ typedef struct _KEY_OBJECT
|
||||||
|
|
||||||
/* List entry for connected hives */
|
/* List entry for connected hives */
|
||||||
LIST_ENTRY HiveList;
|
LIST_ENTRY HiveList;
|
||||||
|
|
||||||
|
CACHED_CHILD_LIST ValueCache;
|
||||||
} KEY_OBJECT, *PKEY_OBJECT;
|
} KEY_OBJECT, *PKEY_OBJECT;
|
||||||
|
|
||||||
/* Bits 31-22 (top 10 bits) of the cell index is the directory index */
|
/* Bits 31-22 (top 10 bits) of the cell index is the directory index */
|
||||||
|
@ -265,6 +281,15 @@ NTAPI
|
||||||
CmDeleteValueKey(IN PKEY_OBJECT KeyControlBlock,
|
CmDeleteValueKey(IN PKEY_OBJECT KeyControlBlock,
|
||||||
IN UNICODE_STRING ValueName);
|
IN UNICODE_STRING ValueName);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
CmQueryValueKey(IN PKEY_OBJECT KeyObject,
|
||||||
|
IN UNICODE_STRING ValueName,
|
||||||
|
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
||||||
|
IN PVOID KeyValueInformation,
|
||||||
|
IN ULONG Length,
|
||||||
|
IN PULONG ResultLength);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
CmiAllocateHashTableCell(IN PEREGISTRY_HIVE RegistryHive,
|
CmiAllocateHashTableCell(IN PEREGISTRY_HIVE RegistryHive,
|
||||||
OUT PHASH_TABLE_CELL *HashBlock,
|
OUT PHASH_TABLE_CELL *HashBlock,
|
||||||
|
|
|
@ -385,6 +385,8 @@ NtCreateKey(OUT PHANDLE KeyHandle,
|
||||||
|
|
||||||
KeyObject->KeyCell->Parent = KeyObject->ParentKey->KeyCellOffset;
|
KeyObject->KeyCell->Parent = KeyObject->ParentKey->KeyCellOffset;
|
||||||
KeyObject->KeyCell->SecurityKeyOffset = KeyObject->ParentKey->KeyCell->SecurityKeyOffset;
|
KeyObject->KeyCell->SecurityKeyOffset = KeyObject->ParentKey->KeyCell->SecurityKeyOffset;
|
||||||
|
KeyObject->ValueCache.ValueList = KeyObject->KeyCell->ValueList.List;
|
||||||
|
KeyObject->ValueCache.Count = KeyObject->KeyCell->ValueList.Count;
|
||||||
|
|
||||||
DPRINT("RemainingPath: %wZ\n", &RemainingPath);
|
DPRINT("RemainingPath: %wZ\n", &RemainingPath);
|
||||||
|
|
||||||
|
@ -1536,267 +1538,57 @@ NtQueryKey(IN HANDLE KeyHandle,
|
||||||
return(Status);
|
return(Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
NTSTATUS STDCALL
|
NTAPI
|
||||||
NtQueryValueKey(IN HANDLE KeyHandle,
|
NtQueryValueKey(IN HANDLE KeyHandle,
|
||||||
IN PUNICODE_STRING ValueName,
|
IN PUNICODE_STRING ValueName,
|
||||||
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
||||||
OUT PVOID KeyValueInformation,
|
OUT PVOID KeyValueInformation,
|
||||||
IN ULONG Length,
|
IN ULONG Length,
|
||||||
OUT PULONG ResultLength)
|
OUT PULONG ResultLength)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
ULONG NameSize, DataSize;
|
PKEY_OBJECT KeyObject;
|
||||||
PKEY_OBJECT KeyObject;
|
REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
|
||||||
PEREGISTRY_HIVE RegistryHive;
|
REG_POST_OPERATION_INFORMATION PostOperationInfo;
|
||||||
PCM_KEY_NODE KeyCell;
|
PAGED_CODE();
|
||||||
PCM_KEY_VALUE ValueCell;
|
|
||||||
PVOID DataCell;
|
|
||||||
PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
|
|
||||||
PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
|
|
||||||
PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
|
|
||||||
REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
|
|
||||||
REG_POST_OPERATION_INFORMATION PostOperationInfo;
|
|
||||||
|
|
||||||
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("NtQueryValueKey(KeyHandle 0x%p ValueName %S Length %x)\n",
|
/* Setup the callback */
|
||||||
KeyHandle, ValueName->Buffer, Length);
|
PostOperationInfo.Object = (PVOID)KeyObject;
|
||||||
|
QueryValueKeyInfo.Object = (PVOID)KeyObject;
|
||||||
|
QueryValueKeyInfo.ValueName = ValueName;
|
||||||
|
QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
|
||||||
|
QueryValueKeyInfo.Length = Length;
|
||||||
|
QueryValueKeyInfo.ResultLength = ResultLength;
|
||||||
|
|
||||||
/* Verify that the handle is valid and is a registry key */
|
/* Do the callback */
|
||||||
Status = ObReferenceObjectByHandle(KeyHandle,
|
Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo);
|
||||||
KEY_QUERY_VALUE,
|
if (NT_SUCCESS(Status))
|
||||||
CmpKeyObjectType,
|
|
||||||
ExGetPreviousMode(),
|
|
||||||
(PVOID *)&KeyObject,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
{
|
||||||
DPRINT1("ObReferenceObjectByHandle() failed with status %x %p\n", Status, KeyHandle);
|
/* Call the internal API */
|
||||||
return Status;
|
Status = CmQueryValueKey(KeyObject,
|
||||||
|
*ValueName,
|
||||||
|
KeyValueInformationClass,
|
||||||
|
KeyValueInformation,
|
||||||
|
Length,
|
||||||
|
ResultLength);
|
||||||
|
|
||||||
|
/* Do the post callback */
|
||||||
|
PostOperationInfo.Status = Status;
|
||||||
|
CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
PostOperationInfo.Object = (PVOID)KeyObject;
|
ObDereferenceObject(KeyObject);
|
||||||
QueryValueKeyInfo.Object = (PVOID)KeyObject;
|
return Status;
|
||||||
QueryValueKeyInfo.ValueName = ValueName;
|
|
||||||
QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
|
|
||||||
QueryValueKeyInfo.Length = Length;
|
|
||||||
QueryValueKeyInfo.ResultLength = ResultLength;
|
|
||||||
|
|
||||||
Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
PostOperationInfo.Status = Status;
|
|
||||||
CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &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 cell by name */
|
|
||||||
Status = CmiScanKeyForValue(RegistryHive,
|
|
||||||
KeyCell,
|
|
||||||
ValueName,
|
|
||||||
&ValueCell,
|
|
||||||
NULL);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
|
|
||||||
goto ByeBye;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
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 = DataSize;
|
|
||||||
|
|
||||||
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 - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) <
|
|
||||||
NameSize)
|
|
||||||
{
|
|
||||||
NameSize = Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
|
|
||||||
DataSize = 0;
|
|
||||||
Status = STATUS_BUFFER_OVERFLOW;
|
|
||||||
CHECKPOINT;
|
|
||||||
}
|
|
||||||
else if (ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
|
|
||||||
Name[0]) - NameSize, sizeof(PVOID)) < DataSize)
|
|
||||||
{
|
|
||||||
DataSize = ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
|
|
||||||
Name[0]) - NameSize, sizeof(PVOID));
|
|
||||||
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);
|
|
||||||
Status = STATUS_INVALID_INFO_CLASS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByeBye:;
|
|
||||||
ExReleaseResourceLite(&CmpRegistryLock);
|
|
||||||
KeLeaveCriticalRegion();
|
|
||||||
|
|
||||||
PostOperationInfo.Status = Status;
|
|
||||||
CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
|
|
||||||
ObDereferenceObject(KeyObject);
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
|
|
|
@ -157,6 +157,11 @@
|
||||||
#define CMP_CREATE_FAKE_KCB 0x1
|
#define CMP_CREATE_FAKE_KCB 0x1
|
||||||
#define CMP_LOCK_HASHES_FOR_KCB 0x2
|
#define CMP_LOCK_HASHES_FOR_KCB 0x2
|
||||||
|
|
||||||
|
//
|
||||||
|
// Maximum size of Value Cache
|
||||||
|
//
|
||||||
|
#define MAXIMUM_CACHED_DATA 2 * PAGE_SIZE
|
||||||
|
|
||||||
//
|
//
|
||||||
// Number of items that can fit inside an Allocation Page
|
// Number of items that can fit inside an Allocation Page
|
||||||
//
|
//
|
||||||
|
@ -167,6 +172,16 @@
|
||||||
|
|
||||||
#ifndef __INCLUDE_CM_H
|
#ifndef __INCLUDE_CM_H
|
||||||
|
|
||||||
|
//
|
||||||
|
// Value Search Results
|
||||||
|
//
|
||||||
|
typedef enum _VALUE_SEARCH_RETURN_TYPE
|
||||||
|
{
|
||||||
|
SearchSuccess,
|
||||||
|
SearchNeedExclusiveLock,
|
||||||
|
SearchFail
|
||||||
|
} VALUE_SEARCH_RETURN_TYPE;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Key Hash
|
// Key Hash
|
||||||
//
|
//
|
||||||
|
@ -238,7 +253,8 @@ typedef struct _CACHED_CHILD_LIST
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
ULONG ValueList;
|
ULONG ValueList;
|
||||||
struct _CM_KEY_CONTROL_BLOCK *RealKcb;
|
//struct _CM_KEY_CONTROL_BLOCK *RealKcb;
|
||||||
|
struct _KEY_OBJECT *RealKcb;
|
||||||
};
|
};
|
||||||
} CACHED_CHILD_LIST, *PCACHED_CHILD_LIST;
|
} CACHED_CHILD_LIST, *PCACHED_CHILD_LIST;
|
||||||
|
|
||||||
|
@ -595,6 +611,7 @@ typedef struct _CM_CACHED_VALUE
|
||||||
{
|
{
|
||||||
USHORT DataCacheType;
|
USHORT DataCacheType;
|
||||||
USHORT ValueKeySize;
|
USHORT ValueKeySize;
|
||||||
|
ULONG HashKey;
|
||||||
CM_KEY_VALUE KeyValue;
|
CM_KEY_VALUE KeyValue;
|
||||||
} CM_CACHED_VALUE, *PCM_CACHED_VALUE;
|
} CM_CACHED_VALUE, *PCM_CACHED_VALUE;
|
||||||
|
|
||||||
|
@ -644,6 +661,20 @@ typedef struct _CM_SYSTEM_CONTROL_VECTOR
|
||||||
PULONG Type;
|
PULONG Type;
|
||||||
} CM_SYSTEM_CONTROL_VECTOR, *PCM_SYSTEM_CONTROL_VECTOR;
|
} CM_SYSTEM_CONTROL_VECTOR, *PCM_SYSTEM_CONTROL_VECTOR;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Structure for CmpQueryValueDataFromCache
|
||||||
|
//
|
||||||
|
typedef struct _KEY_VALUE_INFORMATION
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
KEY_VALUE_BASIC_INFORMATION KeyValueBasicInformation;
|
||||||
|
KEY_VALUE_FULL_INFORMATION KeyValueFullInformation;
|
||||||
|
KEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInformation;
|
||||||
|
KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 KeyValuePartialInformationAlign64;
|
||||||
|
};
|
||||||
|
} KEY_VALUE_INFORMATION, *PKEY_VALUE_INFORMATION;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// BUGBUG Old Hive Stuff for Temporary Support
|
// BUGBUG Old Hive Stuff for Temporary Support
|
||||||
|
@ -679,6 +710,7 @@ typedef struct _KEY_OBJECT
|
||||||
struct _KEY_OBJECT **SubKeys;
|
struct _KEY_OBJECT **SubKeys;
|
||||||
ULONG TimeStamp;
|
ULONG TimeStamp;
|
||||||
LIST_ENTRY HiveList;
|
LIST_ENTRY HiveList;
|
||||||
|
CACHED_CHILD_LIST ValueCache;
|
||||||
} KEY_OBJECT, *PKEY_OBJECT;
|
} KEY_OBJECT, *PKEY_OBJECT;
|
||||||
extern PEREGISTRY_HIVE CmiVolatileHive;
|
extern PEREGISTRY_HIVE CmiVolatileHive;
|
||||||
extern LIST_ENTRY CmiKeyObjectListHead, CmiConnectedHiveList;
|
extern LIST_ENTRY CmiKeyObjectListHead, CmiConnectedHiveList;
|
||||||
|
@ -708,6 +740,35 @@ CmpInitSecurityCache(
|
||||||
IN PCMHIVE Hive
|
IN PCMHIVE Hive
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Value Cache Functions
|
||||||
|
//
|
||||||
|
VALUE_SEARCH_RETURN_TYPE
|
||||||
|
NTAPI
|
||||||
|
CmpFindValueByNameFromCache(
|
||||||
|
IN PKEY_OBJECT KeyObject,
|
||||||
|
IN PUNICODE_STRING Name,
|
||||||
|
OUT PCM_CACHED_VALUE **CachedValue,
|
||||||
|
OUT ULONG *Index,
|
||||||
|
OUT PCM_KEY_VALUE *Value,
|
||||||
|
OUT BOOLEAN *ValueIsCached,
|
||||||
|
OUT PHCELL_INDEX CellToRelease
|
||||||
|
);
|
||||||
|
|
||||||
|
VALUE_SEARCH_RETURN_TYPE
|
||||||
|
NTAPI
|
||||||
|
CmpQueryKeyValueData(
|
||||||
|
IN PKEY_OBJECT KeyObject,
|
||||||
|
IN PCM_CACHED_VALUE *CachedValue,
|
||||||
|
IN PCM_KEY_VALUE ValueKey,
|
||||||
|
IN BOOLEAN ValueIsCached,
|
||||||
|
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
||||||
|
IN PVOID KeyValueInformation,
|
||||||
|
IN ULONG Length,
|
||||||
|
OUT PULONG ResultLength,
|
||||||
|
OUT PNTSTATUS Status
|
||||||
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Registry Validation Functions
|
// Registry Validation Functions
|
||||||
//
|
//
|
||||||
|
@ -953,6 +1014,22 @@ CmpNameSize(
|
||||||
IN PUNICODE_STRING Name
|
IN PUNICODE_STRING Name
|
||||||
);
|
);
|
||||||
|
|
||||||
|
USHORT
|
||||||
|
NTAPI
|
||||||
|
CmpCompressedNameSize(
|
||||||
|
IN PWCHAR Name,
|
||||||
|
IN ULONG Length
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpCopyCompressedName(
|
||||||
|
IN PWCHAR Destination,
|
||||||
|
IN ULONG DestinationLength,
|
||||||
|
IN PWCHAR Source,
|
||||||
|
IN ULONG SourceLength
|
||||||
|
);
|
||||||
|
|
||||||
USHORT
|
USHORT
|
||||||
NTAPI
|
NTAPI
|
||||||
CmpCopyName(
|
CmpCopyName(
|
||||||
|
@ -1002,6 +1079,14 @@ CmpFindSubKeyByName(
|
||||||
IN PUNICODE_STRING SearchName
|
IN PUNICODE_STRING SearchName
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ULONG
|
||||||
|
NTAPI
|
||||||
|
CmpComputeHashKey(
|
||||||
|
IN ULONG Hash,
|
||||||
|
IN PUNICODE_STRING Name,
|
||||||
|
IN BOOLEAN AllowSeparators
|
||||||
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Cell Value Routines
|
// Cell Value Routines
|
||||||
//
|
//
|
||||||
|
@ -1072,6 +1157,17 @@ CmpRemoveValueFromList(
|
||||||
IN OUT PCHILD_LIST ChildList
|
IN OUT PCHILD_LIST ChildList
|
||||||
);
|
);
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
NTAPI
|
||||||
|
CmpGetValueData(
|
||||||
|
IN PHHIVE Hive,
|
||||||
|
IN PCM_KEY_VALUE Value,
|
||||||
|
IN PULONG Length,
|
||||||
|
OUT PVOID *Buffer,
|
||||||
|
OUT PBOOLEAN BufferAllocated,
|
||||||
|
OUT PHCELL_INDEX CellToRelease
|
||||||
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Boot Routines
|
// Boot Routines
|
||||||
//
|
//
|
||||||
|
|
|
@ -433,7 +433,7 @@ CmDeleteValueKey(IN PKEY_OBJECT KeyObject,
|
||||||
Parent->MaxValueDataLen = 0;
|
Parent->MaxValueDataLen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Change default status to success */
|
/* Change default Status to success */
|
||||||
Status = STATUS_SUCCESS;
|
Status = STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,3 +454,68 @@ Quickie:
|
||||||
KeLeaveCriticalRegion();
|
KeLeaveCriticalRegion();
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
CmQueryValueKey(IN PKEY_OBJECT KeyObject,
|
||||||
|
IN UNICODE_STRING ValueName,
|
||||||
|
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
||||||
|
IN PVOID KeyValueInformation,
|
||||||
|
IN ULONG Length,
|
||||||
|
IN PULONG ResultLength)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
PCM_KEY_VALUE ValueData;
|
||||||
|
ULONG Index;
|
||||||
|
BOOLEAN ValueCached = FALSE;
|
||||||
|
PCM_CACHED_VALUE *CachedValue;
|
||||||
|
HCELL_INDEX CellToRelease;
|
||||||
|
VALUE_SEARCH_RETURN_TYPE Result;
|
||||||
|
PHHIVE Hive;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Acquire hive lock */
|
||||||
|
KeEnterCriticalRegion();
|
||||||
|
ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
|
||||||
|
|
||||||
|
/* Get the hive */
|
||||||
|
Hive = &KeyObject->RegistryHive->Hive;
|
||||||
|
|
||||||
|
/* Find the key value */
|
||||||
|
Result = CmpFindValueByNameFromCache(KeyObject,
|
||||||
|
&ValueName,
|
||||||
|
&CachedValue,
|
||||||
|
&Index,
|
||||||
|
&ValueData,
|
||||||
|
&ValueCached,
|
||||||
|
&CellToRelease);
|
||||||
|
if (Result == SearchSuccess)
|
||||||
|
{
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT(ValueData != NULL);
|
||||||
|
|
||||||
|
/* Query the information requested */
|
||||||
|
Result = CmpQueryKeyValueData(KeyObject,
|
||||||
|
CachedValue,
|
||||||
|
ValueData,
|
||||||
|
ValueCached,
|
||||||
|
KeyValueInformationClass,
|
||||||
|
KeyValueInformation,
|
||||||
|
Length,
|
||||||
|
ResultLength,
|
||||||
|
&Status);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Failed to find the value */
|
||||||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have a cell to release, do so */
|
||||||
|
if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease);
|
||||||
|
|
||||||
|
/* Release hive lock */
|
||||||
|
ExReleaseResourceLite(&CmpRegistryLock);
|
||||||
|
KeLeaveCriticalRegion();
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
|
@ -52,6 +52,24 @@ CmpCopyName(IN PHHIVE Hive,
|
||||||
return Source->Length / sizeof(WCHAR);
|
return Source->Length / sizeof(WCHAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpCopyCompressedName(IN PWCHAR Destination,
|
||||||
|
IN ULONG DestinationLength,
|
||||||
|
IN PWCHAR Source,
|
||||||
|
IN ULONG SourceLength)
|
||||||
|
{
|
||||||
|
ULONG i, Length;
|
||||||
|
|
||||||
|
/* Get the actual length to copy */
|
||||||
|
Length = min(DestinationLength / sizeof(WCHAR), SourceLength);
|
||||||
|
for (i = 0; i < Length; i++)
|
||||||
|
{
|
||||||
|
/* Copy each character */
|
||||||
|
Destination[i] = (WCHAR)((PCHAR)Source)[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
USHORT
|
USHORT
|
||||||
NTAPI
|
NTAPI
|
||||||
CmpNameSize(IN PHHIVE Hive,
|
CmpNameSize(IN PHHIVE Hive,
|
||||||
|
@ -73,6 +91,20 @@ CmpNameSize(IN PHHIVE Hive,
|
||||||
return Name->Length / sizeof(WCHAR);
|
return Name->Length / sizeof(WCHAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
USHORT
|
||||||
|
NTAPI
|
||||||
|
CmpCompressedNameSize(IN PWCHAR Name,
|
||||||
|
IN ULONG Length)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Don't remove this: compressed names are "opaque" and just because
|
||||||
|
* the current implementation turns them into ansi-names doesn't mean
|
||||||
|
* that it will remain that way forever, so -never- assume this code
|
||||||
|
* below internally!
|
||||||
|
*/
|
||||||
|
return Length * sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
|
||||||
LONG
|
LONG
|
||||||
NTAPI
|
NTAPI
|
||||||
CmpCompareCompressedName(IN PUNICODE_STRING SearchName,
|
CmpCompareCompressedName(IN PUNICODE_STRING SearchName,
|
||||||
|
|
643
reactos/ntoskrnl/config/cmvalche.c
Normal file
643
reactos/ntoskrnl/config/cmvalche.c
Normal file
|
@ -0,0 +1,643 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Kernel
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: ntoskrnl/config/cmvalche.c
|
||||||
|
* PURPOSE: Configuration Manager - Value Cell Cache
|
||||||
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
|
#include "ntoskrnl.h"
|
||||||
|
#include "cm.h"
|
||||||
|
#define NDEBUG
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
FORCEINLINE
|
||||||
|
BOOLEAN
|
||||||
|
CmpIsValueCached(IN HCELL_INDEX CellIndex)
|
||||||
|
{
|
||||||
|
/* Make sure that the cell is valid in the first place */
|
||||||
|
if (CellIndex == HCELL_NIL) return FALSE;
|
||||||
|
|
||||||
|
/*Is this cell actually a pointer to the cached value data? */
|
||||||
|
if (CellIndex & 1) return TRUE;
|
||||||
|
|
||||||
|
/* This is a regular cell */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE
|
||||||
|
VOID
|
||||||
|
CmpSetValueCached(IN PHCELL_INDEX CellIndex)
|
||||||
|
{
|
||||||
|
/* Set the cached bit */
|
||||||
|
*CellIndex |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ASSERT_VALUE_CACHE() \
|
||||||
|
ASSERTMSG("Cached Values Not Yet Supported!", FALSE);
|
||||||
|
|
||||||
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
VALUE_SEARCH_RETURN_TYPE
|
||||||
|
NTAPI
|
||||||
|
CmpGetValueListFromCache(IN PKEY_OBJECT KeyObject,
|
||||||
|
OUT PCELL_DATA *CellData,
|
||||||
|
OUT BOOLEAN *IndexIsCached,
|
||||||
|
OUT PHCELL_INDEX ValueListToRelease)
|
||||||
|
{
|
||||||
|
PHHIVE Hive;
|
||||||
|
PCACHED_CHILD_LIST ChildList;
|
||||||
|
HCELL_INDEX CellToRelease;
|
||||||
|
|
||||||
|
/* Set defaults */
|
||||||
|
*ValueListToRelease = HCELL_NIL;
|
||||||
|
*IndexIsCached = FALSE;
|
||||||
|
|
||||||
|
/* Get the hive */
|
||||||
|
Hive = &KeyObject->RegistryHive->Hive;
|
||||||
|
|
||||||
|
/* Get the child value cache */
|
||||||
|
//ChildList = &KeyObject->ValueCache;
|
||||||
|
ChildList = (PCACHED_CHILD_LIST)&KeyObject->KeyCell->ValueList;
|
||||||
|
|
||||||
|
/* Check if the value is cached */
|
||||||
|
if (CmpIsValueCached(ChildList->ValueList))
|
||||||
|
{
|
||||||
|
/* It is: we don't expect this yet! */
|
||||||
|
ASSERT_VALUE_CACHE();
|
||||||
|
*IndexIsCached = TRUE;
|
||||||
|
*CellData = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Select the value list as our cell, and get the actual list array */
|
||||||
|
CellToRelease = ChildList->ValueList;
|
||||||
|
*CellData = (PCELL_DATA)HvGetCell(Hive, CellToRelease);
|
||||||
|
if (!(*CellData)) return SearchFail;
|
||||||
|
|
||||||
|
/* Return the cell to be released */
|
||||||
|
*ValueListToRelease = CellToRelease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we got here, then the value list was found */
|
||||||
|
return SearchSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
PHHIVE Hive;
|
||||||
|
PCM_KEY_VALUE KeyValue;
|
||||||
|
HCELL_INDEX Cell;
|
||||||
|
|
||||||
|
/* Set defaults */
|
||||||
|
*CellToRelease = HCELL_NIL;
|
||||||
|
*Value = NULL;
|
||||||
|
*ValueIsCached = FALSE;
|
||||||
|
|
||||||
|
/* Get the hive */
|
||||||
|
Hive = &KeyObject->RegistryHive->Hive;
|
||||||
|
|
||||||
|
/* Check if the index was cached */
|
||||||
|
if (IndexIsCached)
|
||||||
|
{
|
||||||
|
/* Not expected yet! */
|
||||||
|
ASSERT_VALUE_CACHE();
|
||||||
|
*ValueIsCached = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Get the cell index and the key value associated to it */
|
||||||
|
Cell = CellData->u.KeyList[Index];
|
||||||
|
KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, Cell);
|
||||||
|
if (!KeyValue) return SearchFail;
|
||||||
|
|
||||||
|
/* Return the cell and the actual key value */
|
||||||
|
*CellToRelease = Cell;
|
||||||
|
*Value = KeyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we got here, then we found the key value */
|
||||||
|
return SearchSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE_SEARCH_RETURN_TYPE
|
||||||
|
NTAPI
|
||||||
|
CmpGetValueDataFromCache(IN PKEY_OBJECT KeyObject,
|
||||||
|
IN PCM_CACHED_VALUE *CachedValue,
|
||||||
|
IN PCELL_DATA ValueKey,
|
||||||
|
IN BOOLEAN ValueIsCached,
|
||||||
|
OUT PVOID *DataPointer,
|
||||||
|
OUT PBOOLEAN Allocated,
|
||||||
|
OUT PHCELL_INDEX CellToRelease)
|
||||||
|
{
|
||||||
|
PHHIVE Hive;
|
||||||
|
ULONG Length;
|
||||||
|
|
||||||
|
/* Sanity checks */
|
||||||
|
ASSERT(MAXIMUM_CACHED_DATA < CM_KEY_VALUE_BIG);
|
||||||
|
ASSERT((ValueKey->u.KeyValue.DataLength & CM_KEY_VALUE_SPECIAL_SIZE) == 0);
|
||||||
|
|
||||||
|
/* Set defaults */
|
||||||
|
*DataPointer = NULL;
|
||||||
|
*Allocated = FALSE;
|
||||||
|
*CellToRelease = HCELL_NIL;
|
||||||
|
|
||||||
|
/* Get the hive */
|
||||||
|
Hive = &KeyObject->RegistryHive->Hive;
|
||||||
|
|
||||||
|
/* Check it the value is cached */
|
||||||
|
if (ValueIsCached)
|
||||||
|
{
|
||||||
|
/* This isn't expected! */
|
||||||
|
ASSERT_VALUE_CACHE();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* It's not, get the value data using the typical routine */
|
||||||
|
if (!CmpGetValueData(Hive,
|
||||||
|
&ValueKey->u.KeyValue,
|
||||||
|
&Length,
|
||||||
|
DataPointer,
|
||||||
|
Allocated,
|
||||||
|
CellToRelease))
|
||||||
|
{
|
||||||
|
/* Nothing found: make sure no data was allocated */
|
||||||
|
ASSERT(*Allocated == FALSE);
|
||||||
|
ASSERT(*DataPointer == NULL);
|
||||||
|
return SearchFail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We found the actual data, return success */
|
||||||
|
return SearchSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE_SEARCH_RETURN_TYPE
|
||||||
|
NTAPI
|
||||||
|
CmpFindValueByNameFromCache(IN PKEY_OBJECT KeyObject,
|
||||||
|
IN PUNICODE_STRING Name,
|
||||||
|
OUT PCM_CACHED_VALUE **CachedValue,
|
||||||
|
OUT ULONG *Index,
|
||||||
|
OUT PCM_KEY_VALUE *Value,
|
||||||
|
OUT BOOLEAN *ValueIsCached,
|
||||||
|
OUT PHCELL_INDEX CellToRelease)
|
||||||
|
{
|
||||||
|
PHHIVE Hive;
|
||||||
|
VALUE_SEARCH_RETURN_TYPE SearchResult = SearchFail;
|
||||||
|
LONG Result;
|
||||||
|
UNICODE_STRING SearchName;
|
||||||
|
PCELL_DATA CellData;
|
||||||
|
PCACHED_CHILD_LIST ChildList;
|
||||||
|
PCM_KEY_VALUE KeyValue;
|
||||||
|
BOOLEAN IndexIsCached;
|
||||||
|
ULONG i = 0;
|
||||||
|
HCELL_INDEX Cell = HCELL_NIL;
|
||||||
|
|
||||||
|
/* Set defaults */
|
||||||
|
*CellToRelease = HCELL_NIL;
|
||||||
|
*Value = NULL;
|
||||||
|
|
||||||
|
/* Get the hive and child list */
|
||||||
|
Hive = &KeyObject->RegistryHive->Hive;
|
||||||
|
//ChildList = &KeyObject->ValueCache;
|
||||||
|
ChildList = (PCACHED_CHILD_LIST)&KeyObject->KeyCell->ValueList;
|
||||||
|
|
||||||
|
/* Check if the child list has any entries */
|
||||||
|
if (ChildList->Count != 0)
|
||||||
|
{
|
||||||
|
/* Get the value list associated to this child list */
|
||||||
|
SearchResult = CmpGetValueListFromCache(KeyObject,
|
||||||
|
&CellData,
|
||||||
|
&IndexIsCached,
|
||||||
|
&Cell);
|
||||||
|
if (SearchResult != SearchSuccess) return SearchResult;
|
||||||
|
|
||||||
|
/* The index shouldn't be cached right now */
|
||||||
|
if (IndexIsCached) ASSERT_VALUE_CACHE();
|
||||||
|
|
||||||
|
/* Loop every value */
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* Check if there's any cell to release */
|
||||||
|
if (*CellToRelease != HCELL_NIL)
|
||||||
|
{
|
||||||
|
/* Release it now */
|
||||||
|
HvReleaseCell(Hive, *CellToRelease);
|
||||||
|
*CellToRelease = HCELL_NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the key value for this index */
|
||||||
|
SearchResult = CmpGetValueKeyFromCache(KeyObject,
|
||||||
|
CellData,
|
||||||
|
i,
|
||||||
|
CachedValue,
|
||||||
|
Value,
|
||||||
|
IndexIsCached,
|
||||||
|
ValueIsCached,
|
||||||
|
CellToRelease);
|
||||||
|
if (SearchResult != SearchSuccess) return SearchResult;
|
||||||
|
|
||||||
|
/* Check if the both the index and the value are cached */
|
||||||
|
if ((IndexIsCached) && (*ValueIsCached))
|
||||||
|
{
|
||||||
|
/* We don't expect this yet */
|
||||||
|
ASSERT_VALUE_CACHE();
|
||||||
|
Result = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No cache, so try to compare the name. Is it compressed? */
|
||||||
|
KeyValue = *Value;
|
||||||
|
if (KeyValue->Flags & VALUE_COMP_NAME)
|
||||||
|
{
|
||||||
|
/* It is, do a compressed name comparison */
|
||||||
|
Result = CmpCompareCompressedName(Name,
|
||||||
|
KeyValue->Name,
|
||||||
|
KeyValue->NameLength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* It's not compressed, so do a standard comparison */
|
||||||
|
SearchName.Length = KeyValue->NameLength;
|
||||||
|
SearchName.MaximumLength = SearchName.Length;
|
||||||
|
SearchName.Buffer = KeyValue->Name;
|
||||||
|
Result = RtlCompareUnicodeString(Name, &SearchName, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we found the value data */
|
||||||
|
if (!Result)
|
||||||
|
{
|
||||||
|
/* We have, return the index of the value and success */
|
||||||
|
*Index = i;
|
||||||
|
SearchResult = SearchSuccess;
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We didn't find it, try the next entry */
|
||||||
|
if (++i == ChildList->Count)
|
||||||
|
{
|
||||||
|
/* The entire list was parsed, fail */
|
||||||
|
*Value = NULL;
|
||||||
|
SearchResult = SearchFail;
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We should only get here if the child list is empty */
|
||||||
|
ASSERT(ChildList->Count == 0);
|
||||||
|
|
||||||
|
Quickie:
|
||||||
|
/* Release the value list cell if required, and return search result */
|
||||||
|
if (Cell != HCELL_NIL) HvReleaseCell(Hive, Cell);
|
||||||
|
return SearchResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE_SEARCH_RETURN_TYPE
|
||||||
|
NTAPI
|
||||||
|
CmpQueryKeyValueData(IN PKEY_OBJECT KeyObject,
|
||||||
|
IN PCM_CACHED_VALUE *CachedValue,
|
||||||
|
IN PCM_KEY_VALUE ValueKey,
|
||||||
|
IN BOOLEAN ValueIsCached,
|
||||||
|
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
||||||
|
IN PVOID KeyValueInformation,
|
||||||
|
IN ULONG Length,
|
||||||
|
OUT PULONG ResultLength,
|
||||||
|
OUT PNTSTATUS Status)
|
||||||
|
{
|
||||||
|
PHHIVE Hive;
|
||||||
|
PKEY_VALUE_INFORMATION Info = (PKEY_VALUE_INFORMATION)KeyValueInformation;
|
||||||
|
PCELL_DATA CellData;
|
||||||
|
USHORT NameSize;
|
||||||
|
ULONG Size, MinimumSize, SizeLeft, KeySize, AlignedData = 0, DataOffset;
|
||||||
|
PVOID Buffer;
|
||||||
|
BOOLEAN IsSmall, BufferAllocated = FALSE;
|
||||||
|
HCELL_INDEX CellToRelease = HCELL_NIL;
|
||||||
|
VALUE_SEARCH_RETURN_TYPE Result = SearchSuccess;
|
||||||
|
|
||||||
|
/* Get the hive and cell data */
|
||||||
|
Hive = &KeyObject->RegistryHive->Hive;
|
||||||
|
CellData = (PCELL_DATA)ValueKey;
|
||||||
|
|
||||||
|
/* Check if the value is compressed */
|
||||||
|
if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME)
|
||||||
|
{
|
||||||
|
/* Get the compressed name size */
|
||||||
|
NameSize = CmpCompressedNameSize(CellData->u.KeyValue.Name,
|
||||||
|
CellData->u.KeyValue.NameLength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Get the real size */
|
||||||
|
NameSize = CellData->u.KeyValue.NameLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check what kind of information the caller is requesting */
|
||||||
|
switch (KeyValueInformationClass)
|
||||||
|
{
|
||||||
|
/* Basic information */
|
||||||
|
case KeyValueBasicInformation:
|
||||||
|
|
||||||
|
/* This is how much size we'll need */
|
||||||
|
Size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) + NameSize;
|
||||||
|
|
||||||
|
/* This is the minimum we can work with */
|
||||||
|
MinimumSize = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);
|
||||||
|
|
||||||
|
/* Return the size we'd like, and assume success */
|
||||||
|
*ResultLength = Size;
|
||||||
|
*Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
/* Check if the caller gave us below our minimum */
|
||||||
|
if (Length < MinimumSize)
|
||||||
|
{
|
||||||
|
/* Then we must fail */
|
||||||
|
*Status = STATUS_BUFFER_TOO_SMALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill out the basic information */
|
||||||
|
Info->KeyValueBasicInformation.TitleIndex = 0;
|
||||||
|
Info->KeyValueBasicInformation.Type = CellData->u.KeyValue.Type;
|
||||||
|
Info->KeyValueBasicInformation.NameLength = NameSize;
|
||||||
|
|
||||||
|
/* Now only the name is left */
|
||||||
|
SizeLeft = Length - MinimumSize;
|
||||||
|
Size = NameSize;
|
||||||
|
|
||||||
|
/* Check if the remaining buffer is too small for the name */
|
||||||
|
if (SizeLeft < Size)
|
||||||
|
{
|
||||||
|
/* Copy only as much as can fit, and tell the caller */
|
||||||
|
Size = SizeLeft;
|
||||||
|
*Status = STATUS_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if this is a compressed name */
|
||||||
|
if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME)
|
||||||
|
{
|
||||||
|
/* Copy as much as we can of the compressed name */
|
||||||
|
CmpCopyCompressedName(Info->KeyValueBasicInformation.Name,
|
||||||
|
Size,
|
||||||
|
CellData->u.KeyValue.Name,
|
||||||
|
CellData->u.KeyValue.NameLength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Copy as much as we can of the raw name */
|
||||||
|
RtlCopyMemory(Info->KeyValueBasicInformation.Name,
|
||||||
|
CellData->u.KeyValue.Name,
|
||||||
|
Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're all done */
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Full key information */
|
||||||
|
case KeyValueFullInformation:
|
||||||
|
|
||||||
|
/* Check if this is a small key and compute key size */
|
||||||
|
IsSmall = CmpIsKeyValueSmall(&KeySize,
|
||||||
|
CellData->u.KeyValue.DataLength);
|
||||||
|
|
||||||
|
/* Calculate the total size required */
|
||||||
|
Size = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) +
|
||||||
|
NameSize +
|
||||||
|
KeySize;
|
||||||
|
|
||||||
|
/* And this is the least we can work with */
|
||||||
|
MinimumSize = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
|
||||||
|
|
||||||
|
/* Check if there's any key data */
|
||||||
|
if (KeySize > 0)
|
||||||
|
{
|
||||||
|
/* Calculate the data offset */
|
||||||
|
DataOffset = Size - KeySize;
|
||||||
|
|
||||||
|
/* Align the offset to 4 bytes */
|
||||||
|
AlignedData = ALIGN_UP(DataOffset, ULONG);
|
||||||
|
|
||||||
|
/* If alignment was required, we'll need more space */
|
||||||
|
if (AlignedData > DataOffset) Size += (AlignedData-DataOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell the caller the size we'll finally need, and set success */
|
||||||
|
*ResultLength = Size;
|
||||||
|
*Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
/* Check if the caller is giving us too little */
|
||||||
|
if (Length < MinimumSize)
|
||||||
|
{
|
||||||
|
/* Then fail right now */
|
||||||
|
*Status = STATUS_BUFFER_TOO_SMALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill out the basic information */
|
||||||
|
Info->KeyValueFullInformation.TitleIndex = 0;
|
||||||
|
Info->KeyValueFullInformation.Type = CellData->u.KeyValue.Type;
|
||||||
|
Info->KeyValueFullInformation.DataLength = KeySize;
|
||||||
|
Info->KeyValueFullInformation.NameLength = NameSize;
|
||||||
|
|
||||||
|
/* Only the name is left now */
|
||||||
|
SizeLeft = Length - MinimumSize;
|
||||||
|
Size = NameSize;
|
||||||
|
|
||||||
|
/* Check if the name fits */
|
||||||
|
if (SizeLeft < Size)
|
||||||
|
{
|
||||||
|
/* It doesn't, truncate what we'll copy, and tell the caller */
|
||||||
|
Size = SizeLeft;
|
||||||
|
*Status = STATUS_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if this key value is compressed */
|
||||||
|
if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME)
|
||||||
|
{
|
||||||
|
/* It is, copy the compressed name */
|
||||||
|
CmpCopyCompressedName(Info->KeyValueFullInformation.Name,
|
||||||
|
Size,
|
||||||
|
CellData->u.KeyValue.Name,
|
||||||
|
CellData->u.KeyValue.NameLength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* It's not, copy the raw name */
|
||||||
|
RtlCopyMemory(Info->KeyValueFullInformation.Name,
|
||||||
|
CellData->u.KeyValue.Name,
|
||||||
|
Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now check if the key had any data */
|
||||||
|
if (KeySize > 0)
|
||||||
|
{
|
||||||
|
/* Was it a small key? */
|
||||||
|
if (IsSmall)
|
||||||
|
{
|
||||||
|
/* Then the data is directly into the cell */
|
||||||
|
Buffer = &CellData->u.KeyValue.Data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, we must retrieve it from the value cache */
|
||||||
|
Result = CmpGetValueDataFromCache(KeyObject,
|
||||||
|
CachedValue,
|
||||||
|
CellData,
|
||||||
|
ValueIsCached,
|
||||||
|
&Buffer,
|
||||||
|
&BufferAllocated,
|
||||||
|
&CellToRelease);
|
||||||
|
if (Result != SearchSuccess)
|
||||||
|
{
|
||||||
|
/* We failed, nothing should be allocated */
|
||||||
|
ASSERT(Buffer == NULL);
|
||||||
|
ASSERT(BufferAllocated == FALSE);
|
||||||
|
*Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now that we know we truly have data, set its offset */
|
||||||
|
Info->KeyValueFullInformation.DataOffset = AlignedData;
|
||||||
|
|
||||||
|
/* Only the data remains to be copied */
|
||||||
|
SizeLeft = max(0, Length - AlignedData);
|
||||||
|
Size = KeySize;
|
||||||
|
|
||||||
|
/* Check if the caller has no space for it */
|
||||||
|
if (SizeLeft < Size)
|
||||||
|
{
|
||||||
|
/* Truncate what we'll copy, and tell the caller */
|
||||||
|
Size = SizeLeft;
|
||||||
|
*Status = STATUS_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE));
|
||||||
|
|
||||||
|
/* Make sure we have a valid buffer */
|
||||||
|
if (Buffer)
|
||||||
|
{
|
||||||
|
/* Copy the data into the aligned offset */
|
||||||
|
RtlCopyMemory((PVOID)((ULONG_PTR)Info + AlignedData),
|
||||||
|
Buffer,
|
||||||
|
Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We don't have any data, set the offset to -1, not 0! */
|
||||||
|
Info->KeyValueFullInformation.DataOffset = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're done! */
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Partial information requested (no name or alignment!) */
|
||||||
|
case KeyValuePartialInformation:
|
||||||
|
|
||||||
|
/* Check if this is a small key and compute key size */
|
||||||
|
IsSmall = CmpIsKeyValueSmall(&KeySize,
|
||||||
|
CellData->u.KeyValue.DataLength);
|
||||||
|
|
||||||
|
/* Calculate the total size required */
|
||||||
|
Size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + KeySize;
|
||||||
|
|
||||||
|
/* And this is the least we can work with */
|
||||||
|
MinimumSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
|
||||||
|
|
||||||
|
/* Tell the caller the size we'll finally need, and set success */
|
||||||
|
*ResultLength = Size;
|
||||||
|
*Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
/* Check if the caller is giving us too little */
|
||||||
|
if (Length < MinimumSize)
|
||||||
|
{
|
||||||
|
/* Then fail right now */
|
||||||
|
*Status = STATUS_BUFFER_TOO_SMALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill out the basic information */
|
||||||
|
Info->KeyValuePartialInformation.TitleIndex = 0;
|
||||||
|
Info->KeyValuePartialInformation.Type = CellData->u.KeyValue.Type;
|
||||||
|
Info->KeyValuePartialInformation.DataLength = KeySize;
|
||||||
|
|
||||||
|
/* Now check if the key had any data */
|
||||||
|
if (KeySize > 0)
|
||||||
|
{
|
||||||
|
/* Was it a small key? */
|
||||||
|
if (IsSmall)
|
||||||
|
{
|
||||||
|
/* Then the data is directly into the cell */
|
||||||
|
Buffer = &CellData->u.KeyValue.Data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, we must retrieve it from the value cache */
|
||||||
|
Result = CmpGetValueDataFromCache(KeyObject,
|
||||||
|
CachedValue,
|
||||||
|
CellData,
|
||||||
|
ValueIsCached,
|
||||||
|
&Buffer,
|
||||||
|
&BufferAllocated,
|
||||||
|
&CellToRelease);
|
||||||
|
if (Result != SearchSuccess)
|
||||||
|
{
|
||||||
|
/* We failed, nothing should be allocated */
|
||||||
|
ASSERT(Buffer == NULL);
|
||||||
|
ASSERT(BufferAllocated == FALSE);
|
||||||
|
*Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only the data remains to be copied */
|
||||||
|
SizeLeft = Length - MinimumSize;
|
||||||
|
Size = KeySize;
|
||||||
|
|
||||||
|
/* Check if the caller has no space for it */
|
||||||
|
if (SizeLeft < Size)
|
||||||
|
{
|
||||||
|
/* Truncate what we'll copy, and tell the caller */
|
||||||
|
Size = SizeLeft;
|
||||||
|
*Status = STATUS_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE));
|
||||||
|
|
||||||
|
/* Make sure we have a valid buffer */
|
||||||
|
if (Buffer)
|
||||||
|
{
|
||||||
|
/* Copy the data into the aligned offset */
|
||||||
|
RtlCopyMemory(Info->KeyValuePartialInformation.Data,
|
||||||
|
Buffer,
|
||||||
|
Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're done! */
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Other information class */
|
||||||
|
default:
|
||||||
|
|
||||||
|
/* We got some class that we don't support */
|
||||||
|
*Status = STATUS_INVALID_PARAMETER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the search result as well */
|
||||||
|
return Result;
|
||||||
|
}
|
|
@ -106,6 +106,7 @@
|
||||||
<file>cmsecach.c</file>
|
<file>cmsecach.c</file>
|
||||||
<file>cmsysini.c</file>
|
<file>cmsysini.c</file>
|
||||||
<file>cmvalue.c</file>
|
<file>cmvalue.c</file>
|
||||||
|
<file>cmvalche.c</file>
|
||||||
<file>cmwraprs.c</file>
|
<file>cmwraprs.c</file>
|
||||||
</directory>
|
</directory>
|
||||||
<directory name="cm">
|
<directory name="cm">
|
||||||
|
|
Loading…
Reference in a new issue