Author: ion
Date: Mon May 14 09:36:25 2007
New Revision: 26774
URL:
http://svn.reactos.org/svn/reactos?rev=26774&view=rev
Log:
- 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.
Added:
trunk/reactos/ntoskrnl/config/cmvalche.c
Modified:
trunk/reactos/ntoskrnl/cm/cm.h
trunk/reactos/ntoskrnl/cm/ntfunc.c
trunk/reactos/ntoskrnl/config/cm.h
trunk/reactos/ntoskrnl/config/cmapi.c
trunk/reactos/ntoskrnl/config/cmname.c
trunk/reactos/ntoskrnl/ntoskrnl.rbuild
Modified: trunk/reactos/ntoskrnl/cm/cm.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/cm/cm.h?rev=26774…
==============================================================================
--- trunk/reactos/ntoskrnl/cm/cm.h (original)
+++ trunk/reactos/ntoskrnl/cm/cm.h Mon May 14 09:36:25 2007
@@ -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 @@
/* 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 */
@@ -264,6 +280,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,
Modified: trunk/reactos/ntoskrnl/cm/ntfunc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/cm/ntfunc.c?rev=2…
==============================================================================
--- trunk/reactos/ntoskrnl/cm/ntfunc.c (original)
+++ trunk/reactos/ntoskrnl/cm/ntfunc.c Mon May 14 09:36:25 2007
@@ -385,6 +385,8 @@
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 @@
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)
-{
- 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;
-
- PAGED_CODE();
-
- DPRINT("NtQueryValueKey(KeyHandle 0x%p ValueName %S Length %x)\n",
- KeyHandle, ValueName->Buffer, Length);
-
- /* 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))
- {
- DPRINT1("ObReferenceObjectByHandle() failed with status %x %p\n", Status,
KeyHandle);
- return Status;
- }
-
- 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;
+ IN PUNICODE_STRING ValueName,
+ IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
+ OUT PVOID KeyValueInformation,
+ IN ULONG Length,
+ OUT PULONG ResultLength)
+{
+ NTSTATUS Status;
+ PKEY_OBJECT KeyObject;
+ 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;
+
+ /* Setup the callback */
+ PostOperationInfo.Object = (PVOID)KeyObject;
+ QueryValueKeyInfo.Object = (PVOID)KeyObject;
+ QueryValueKeyInfo.ValueName = ValueName;
+ QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
+ QueryValueKeyInfo.Length = Length;
+ QueryValueKeyInfo.ResultLength = ResultLength;
+
+ /* Do the callback */
+ Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo);
+ if (NT_SUCCESS(Status))
+ {
+ /* Call the internal API */
+ Status = CmQueryValueKey(KeyObject,
+ *ValueName,
+ KeyValueInformationClass,
+ KeyValueInformation,
+ Length,
+ ResultLength);
+
+ /* Do the post callback */
+ PostOperationInfo.Status = Status;
+ CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
+ }
+
+ ObDereferenceObject(KeyObject);
+ return Status;
}
NTSTATUS
Modified: trunk/reactos/ntoskrnl/config/cm.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cm.h?rev=2…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cm.h (original)
+++ trunk/reactos/ntoskrnl/config/cm.h Mon May 14 09:36:25 2007
@@ -158,6 +158,11 @@
#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
//
#define CM_KCBS_PER_PAGE \
@@ -166,6 +171,16 @@
PAGE_SIZE / sizeof(CM_DELAYED_CLOSE_ENTRY)
#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 @@
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 @@
{
USHORT DataCacheType;
USHORT ValueKeySize;
+ ULONG HashKey;
CM_KEY_VALUE KeyValue;
} CM_CACHED_VALUE, *PCM_CACHED_VALUE;
@@ -643,6 +660,20 @@
PULONG BufferLength;
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;
///////////////////////////////////////////////////////////////////////////////
//
@@ -679,6 +710,7 @@
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;
@@ -706,6 +738,35 @@
NTAPI
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
);
//
@@ -955,6 +1016,22 @@
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(
IN PHHIVE Hive,
IN PWCHAR Destination,
@@ -1000,6 +1077,14 @@
IN PHHIVE Hive,
IN PCM_KEY_NODE Parent,
IN PUNICODE_STRING SearchName
+);
+
+ULONG
+NTAPI
+CmpComputeHashKey(
+ IN ULONG Hash,
+ IN PUNICODE_STRING Name,
+ IN BOOLEAN AllowSeparators
);
//
@@ -1070,6 +1155,17 @@
IN PHHIVE Hive,
IN ULONG Index,
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
);
//
Modified: trunk/reactos/ntoskrnl/config/cmapi.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cmapi.c?re…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cmapi.c (original)
+++ trunk/reactos/ntoskrnl/config/cmapi.c Mon May 14 09:36:25 2007
@@ -433,7 +433,7 @@
Parent->MaxValueDataLen = 0;
}
- /* Change default status to success */
+ /* Change default Status to success */
Status = STATUS_SUCCESS;
}
@@ -454,3 +454,68 @@
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;
+}
Modified: trunk/reactos/ntoskrnl/config/cmname.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cmname.c?r…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cmname.c (original)
+++ trunk/reactos/ntoskrnl/config/cmname.c Mon May 14 09:36:25 2007
@@ -52,6 +52,24 @@
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,
@@ -71,6 +89,20 @@
/* Compressed name, return length */
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
Added: trunk/reactos/ntoskrnl/config/cmvalche.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cmvalche.c…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cmvalche.c (added)
+++ trunk/reactos/ntoskrnl/config/cmvalche.c Mon May 14 09:36:25 2007
@@ -1,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(a)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;
+}
Modified: trunk/reactos/ntoskrnl/ntoskrnl.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ntoskrnl.rbuild?r…
==============================================================================
--- trunk/reactos/ntoskrnl/ntoskrnl.rbuild (original)
+++ trunk/reactos/ntoskrnl/ntoskrnl.rbuild Mon May 14 09:36:25 2007
@@ -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">