mirror of
https://github.com/reactos/reactos.git
synced 2025-05-25 20:18:22 +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 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 */
|
||||
|
||||
/* 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 HiveList;
|
||||
|
||||
CACHED_CHILD_LIST ValueCache;
|
||||
} KEY_OBJECT, *PKEY_OBJECT;
|
||||
|
||||
/* Bits 31-22 (top 10 bits) of the cell index is the directory index */
|
||||
|
@ -265,6 +281,15 @@ NTAPI
|
|||
CmDeleteValueKey(IN PKEY_OBJECT KeyControlBlock,
|
||||
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
|
||||
CmiAllocateHashTableCell(IN PEREGISTRY_HIVE RegistryHive,
|
||||
OUT PHASH_TABLE_CELL *HashBlock,
|
||||
|
|
|
@ -385,6 +385,8 @@ NtCreateKey(OUT PHANDLE KeyHandle,
|
|||
|
||||
KeyObject->KeyCell->Parent = KeyObject->ParentKey->KeyCellOffset;
|
||||
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);
|
||||
|
||||
|
@ -1536,267 +1538,57 @@ NtQueryKey(IN HANDLE KeyHandle,
|
|||
return(Status);
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtQueryValueKey(IN HANDLE KeyHandle,
|
||||
IN PUNICODE_STRING ValueName,
|
||||
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
||||
OUT PVOID KeyValueInformation,
|
||||
IN ULONG Length,
|
||||
OUT PULONG ResultLength)
|
||||
IN PUNICODE_STRING ValueName,
|
||||
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
||||
OUT PVOID KeyValueInformation,
|
||||
IN ULONG Length,
|
||||
OUT PULONG ResultLength)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG NameSize, DataSize;
|
||||
PKEY_OBJECT KeyObject;
|
||||
PEREGISTRY_HIVE RegistryHive;
|
||||
PCM_KEY_NODE KeyCell;
|
||||
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;
|
||||
NTSTATUS Status;
|
||||
PKEY_OBJECT KeyObject;
|
||||
REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
|
||||
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("NtQueryValueKey(KeyHandle 0x%p ValueName %S Length %x)\n",
|
||||
KeyHandle, ValueName->Buffer, Length);
|
||||
/* Setup the callback */
|
||||
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 */
|
||||
Status = ObReferenceObjectByHandle(KeyHandle,
|
||||
KEY_QUERY_VALUE,
|
||||
CmpKeyObjectType,
|
||||
ExGetPreviousMode(),
|
||||
(PVOID *)&KeyObject,
|
||||
NULL);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
/* Do the callback */
|
||||
Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("ObReferenceObjectByHandle() failed with status %x %p\n", Status, KeyHandle);
|
||||
return Status;
|
||||
/* Call the internal API */
|
||||
Status = CmQueryValueKey(KeyObject,
|
||||
*ValueName,
|
||||
KeyValueInformationClass,
|
||||
KeyValueInformation,
|
||||
Length,
|
||||
ResultLength);
|
||||
|
||||
/* Do the post callback */
|
||||
PostOperationInfo.Status = Status;
|
||||
CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
|
||||
}
|
||||
|
||||
PostOperationInfo.Object = (PVOID)KeyObject;
|
||||
QueryValueKeyInfo.Object = (PVOID)KeyObject;
|
||||
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;
|
||||
ObDereferenceObject(KeyObject);
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
|
|
|
@ -157,6 +157,11 @@
|
|||
#define CMP_CREATE_FAKE_KCB 0x1
|
||||
#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
|
||||
//
|
||||
|
@ -167,6 +172,16 @@
|
|||
|
||||
#ifndef __INCLUDE_CM_H
|
||||
|
||||
//
|
||||
// Value Search Results
|
||||
//
|
||||
typedef enum _VALUE_SEARCH_RETURN_TYPE
|
||||
{
|
||||
SearchSuccess,
|
||||
SearchNeedExclusiveLock,
|
||||
SearchFail
|
||||
} VALUE_SEARCH_RETURN_TYPE;
|
||||
|
||||
//
|
||||
// Key Hash
|
||||
//
|
||||
|
@ -238,7 +253,8 @@ typedef struct _CACHED_CHILD_LIST
|
|||
union
|
||||
{
|
||||
ULONG ValueList;
|
||||
struct _CM_KEY_CONTROL_BLOCK *RealKcb;
|
||||
//struct _CM_KEY_CONTROL_BLOCK *RealKcb;
|
||||
struct _KEY_OBJECT *RealKcb;
|
||||
};
|
||||
} CACHED_CHILD_LIST, *PCACHED_CHILD_LIST;
|
||||
|
||||
|
@ -595,6 +611,7 @@ typedef struct _CM_CACHED_VALUE
|
|||
{
|
||||
USHORT DataCacheType;
|
||||
USHORT ValueKeySize;
|
||||
ULONG HashKey;
|
||||
CM_KEY_VALUE KeyValue;
|
||||
} CM_CACHED_VALUE, *PCM_CACHED_VALUE;
|
||||
|
||||
|
@ -644,6 +661,20 @@ typedef struct _CM_SYSTEM_CONTROL_VECTOR
|
|||
PULONG Type;
|
||||
} 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
|
||||
|
@ -679,6 +710,7 @@ typedef struct _KEY_OBJECT
|
|||
struct _KEY_OBJECT **SubKeys;
|
||||
ULONG TimeStamp;
|
||||
LIST_ENTRY HiveList;
|
||||
CACHED_CHILD_LIST ValueCache;
|
||||
} KEY_OBJECT, *PKEY_OBJECT;
|
||||
extern PEREGISTRY_HIVE CmiVolatileHive;
|
||||
extern LIST_ENTRY CmiKeyObjectListHead, CmiConnectedHiveList;
|
||||
|
@ -708,6 +740,35 @@ CmpInitSecurityCache(
|
|||
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
|
||||
//
|
||||
|
@ -953,6 +1014,22 @@ CmpNameSize(
|
|||
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
|
||||
NTAPI
|
||||
CmpCopyName(
|
||||
|
@ -1002,6 +1079,14 @@ CmpFindSubKeyByName(
|
|||
IN PUNICODE_STRING SearchName
|
||||
);
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
CmpComputeHashKey(
|
||||
IN ULONG Hash,
|
||||
IN PUNICODE_STRING Name,
|
||||
IN BOOLEAN AllowSeparators
|
||||
);
|
||||
|
||||
//
|
||||
// Cell Value Routines
|
||||
//
|
||||
|
@ -1072,6 +1157,17 @@ CmpRemoveValueFromList(
|
|||
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
|
||||
//
|
||||
|
|
|
@ -433,7 +433,7 @@ CmDeleteValueKey(IN PKEY_OBJECT KeyObject,
|
|||
Parent->MaxValueDataLen = 0;
|
||||
}
|
||||
|
||||
/* Change default status to success */
|
||||
/* Change default Status to success */
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -454,3 +454,68 @@ Quickie:
|
|||
KeLeaveCriticalRegion();
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
NTAPI
|
||||
CmpNameSize(IN PHHIVE Hive,
|
||||
|
@ -73,6 +91,20 @@ CmpNameSize(IN PHHIVE Hive,
|
|||
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
|
||||
NTAPI
|
||||
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>cmsysini.c</file>
|
||||
<file>cmvalue.c</file>
|
||||
<file>cmvalche.c</file>
|
||||
<file>cmwraprs.c</file>
|
||||
</directory>
|
||||
<directory name="cm">
|
||||
|
|
Loading…
Reference in a new issue