[ros-diffs] [ion] 26774: - 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.

ion at svn.reactos.org ion at svn.reactos.org
Mon May 14 07:36:25 CEST 2007


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&r1=26773&r2=26774&view=diff
==============================================================================
--- 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=26774&r1=26773&r2=26774&view=diff
==============================================================================
--- 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=26774&r1=26773&r2=26774&view=diff
==============================================================================
--- 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?rev=26774&r1=26773&r2=26774&view=diff
==============================================================================
--- 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?rev=26774&r1=26773&r2=26774&view=diff
==============================================================================
--- 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?rev=26774&view=auto
==============================================================================
--- 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 at 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?rev=26774&r1=26773&r2=26774&view=diff
==============================================================================
--- 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">




More information about the Ros-diffs mailing list