Use memory wrappers instead of ExAllocatePool/ExFreePool directly
[reactos.git] / reactos / ntoskrnl / config / cmvalche.c
index 7b302dd..8f59857 100644 (file)
-/*\r
- * PROJECT:         ReactOS Kernel\r
- * LICENSE:         GPL - See COPYING in the top level directory\r
- * FILE:            ntoskrnl/config/cmvalche.c\r
- * PURPOSE:         Configuration Manager - Value Cell Cache\r
- * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)\r
- */\r
-\r
-/* INCLUDES ******************************************************************/\r
-\r
-#include "ntoskrnl.h"\r
-#include "cm.h"\r
-#define NDEBUG\r
-#include "debug.h"\r
-\r
-FORCEINLINE\r
-BOOLEAN\r
-CmpIsValueCached(IN HCELL_INDEX CellIndex)\r
-{\r
-    /* Make sure that the cell is valid in the first place */\r
-    if (CellIndex == HCELL_NIL) return FALSE;\r
-\r
-    /*Is this cell actually a pointer to the cached value data? */\r
-    if (CellIndex & 1) return TRUE;\r
-\r
-    /* This is a regular cell */\r
-    return FALSE;\r
-}\r
-\r
-FORCEINLINE\r
-VOID\r
-CmpSetValueCached(IN PHCELL_INDEX CellIndex)\r
-{\r
-    /* Set the cached bit */\r
-    *CellIndex |= 1;\r
-}\r
-\r
-#define ASSERT_VALUE_CACHE() \\r
-    ASSERTMSG("Cached Values Not Yet Supported!", FALSE);\r
-\r
-/* FUNCTIONS *****************************************************************/\r
-\r
-VALUE_SEARCH_RETURN_TYPE\r
-NTAPI\r
-CmpGetValueListFromCache(IN PKEY_OBJECT KeyObject,\r
-                         OUT PCELL_DATA *CellData,\r
-                         OUT BOOLEAN *IndexIsCached,\r
-                         OUT PHCELL_INDEX ValueListToRelease)\r
-{\r
-    PHHIVE Hive;\r
-    PCACHED_CHILD_LIST ChildList;\r
-    HCELL_INDEX CellToRelease;\r
-\r
-    /* Set defaults */\r
-    *ValueListToRelease = HCELL_NIL;\r
-    *IndexIsCached = FALSE;\r
-\r
-    /* Get the hive */\r
-    Hive = &KeyObject->RegistryHive->Hive;\r
-\r
-    /* Get the child value cache */\r
-    //ChildList = &KeyObject->ValueCache;\r
-    ChildList = (PCACHED_CHILD_LIST)&KeyObject->KeyCell->ValueList;\r
-\r
-    /* Check if the value is cached */\r
-    if (CmpIsValueCached(ChildList->ValueList))\r
-    {\r
-        /* It is: we don't expect this yet! */\r
-        ASSERT_VALUE_CACHE();\r
-        *IndexIsCached = TRUE;\r
-        *CellData = NULL;\r
-    }\r
-    else\r
-    {\r
-        /* Select the value list as our cell, and get the actual list array */\r
-        CellToRelease = ChildList->ValueList;\r
-        *CellData = (PCELL_DATA)HvGetCell(Hive, CellToRelease);\r
-        if (!(*CellData)) return SearchFail;\r
-\r
-        /* Return the cell to be released */\r
-        *ValueListToRelease = CellToRelease;\r
-    }\r
-\r
-    /* If we got here, then the value list was found */\r
-    return SearchSuccess;\r
-}\r
-\r
-VALUE_SEARCH_RETURN_TYPE\r
-NTAPI\r
-CmpGetValueKeyFromCache(IN PKEY_OBJECT KeyObject,\r
-                        IN PCELL_DATA CellData,\r
-                        IN ULONG Index,\r
-                        OUT PCM_CACHED_VALUE **CachedValue,\r
-                        OUT PCM_KEY_VALUE *Value,\r
-                        IN BOOLEAN IndexIsCached,\r
-                        OUT BOOLEAN *ValueIsCached,\r
-                        OUT PHCELL_INDEX CellToRelease)\r
-{\r
-    PHHIVE Hive;\r
-    PCM_KEY_VALUE KeyValue;\r
-    HCELL_INDEX Cell;\r
-\r
-    /* Set defaults */\r
-    *CellToRelease = HCELL_NIL;\r
-    *Value = NULL;\r
-    *ValueIsCached = FALSE;\r
-\r
-    /* Get the hive */\r
-    Hive = &KeyObject->RegistryHive->Hive;\r
-\r
-    /* Check if the index was cached */\r
-    if (IndexIsCached)\r
-    {\r
-        /* Not expected yet! */\r
-        ASSERT_VALUE_CACHE();\r
-        *ValueIsCached = TRUE;\r
-    }\r
-    else\r
-    {\r
-        /* Get the cell index and the key value associated to it */\r
-        Cell = CellData->u.KeyList[Index];\r
-        KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, Cell);\r
-        if (!KeyValue) return SearchFail;\r
-\r
-        /* Return the cell and the actual key value */\r
-        *CellToRelease = Cell;\r
-        *Value = KeyValue;\r
-    }\r
-\r
-    /* If we got here, then we found the key value */\r
-    return SearchSuccess;\r
-}\r
-\r
-VALUE_SEARCH_RETURN_TYPE\r
-NTAPI\r
-CmpGetValueDataFromCache(IN PKEY_OBJECT KeyObject,\r
-                         IN PCM_CACHED_VALUE *CachedValue,\r
-                         IN PCELL_DATA ValueKey,\r
-                         IN BOOLEAN ValueIsCached,\r
-                         OUT PVOID *DataPointer,\r
-                         OUT PBOOLEAN Allocated,\r
-                         OUT PHCELL_INDEX CellToRelease)\r
-{\r
-    PHHIVE Hive;\r
-    ULONG Length;\r
-\r
-    /* Sanity checks */\r
-    ASSERT(MAXIMUM_CACHED_DATA < CM_KEY_VALUE_BIG);\r
-    ASSERT((ValueKey->u.KeyValue.DataLength & CM_KEY_VALUE_SPECIAL_SIZE) == 0);\r
-\r
-    /* Set defaults */\r
-    *DataPointer = NULL;\r
-    *Allocated = FALSE;\r
-    *CellToRelease = HCELL_NIL;\r
-\r
-    /* Get the hive */\r
-    Hive = &KeyObject->RegistryHive->Hive;\r
-\r
-    /* Check it the value is cached */\r
-    if (ValueIsCached)\r
-    {\r
-        /* This isn't expected! */\r
-        ASSERT_VALUE_CACHE();\r
-    }\r
-    else\r
-    {\r
-        /* It's not, get the value data using the typical routine */\r
-        if (!CmpGetValueData(Hive,\r
-                             &ValueKey->u.KeyValue,\r
-                             &Length,\r
-                             DataPointer,\r
-                             Allocated,\r
-                             CellToRelease))\r
-        {\r
-            /* Nothing found: make sure no data was allocated */\r
-            ASSERT(*Allocated == FALSE);\r
-            ASSERT(*DataPointer == NULL);\r
-            return SearchFail;\r
-        }\r
-    }\r
-\r
-    /* We found the actual data, return success */\r
-    return SearchSuccess;\r
-}\r
-\r
-VALUE_SEARCH_RETURN_TYPE\r
-NTAPI\r
-CmpFindValueByNameFromCache(IN PKEY_OBJECT KeyObject,\r
-                            IN PUNICODE_STRING Name,\r
-                            OUT PCM_CACHED_VALUE **CachedValue,\r
-                            OUT ULONG *Index,\r
-                            OUT PCM_KEY_VALUE *Value,\r
-                            OUT BOOLEAN *ValueIsCached,\r
-                            OUT PHCELL_INDEX CellToRelease)\r
-{\r
-    PHHIVE Hive;\r
-    VALUE_SEARCH_RETURN_TYPE SearchResult = SearchFail;\r
-    LONG Result;\r
-    UNICODE_STRING SearchName;\r
-    PCELL_DATA CellData;\r
-    PCACHED_CHILD_LIST ChildList;\r
-    PCM_KEY_VALUE KeyValue;\r
-    BOOLEAN IndexIsCached;\r
-    ULONG i = 0;\r
-    HCELL_INDEX Cell = HCELL_NIL;\r
-\r
-    /* Set defaults */\r
-    *CellToRelease = HCELL_NIL;\r
-    *Value = NULL;\r
-\r
-    /* Get the hive and child list */\r
-    Hive = &KeyObject->RegistryHive->Hive;\r
-    //ChildList = &KeyObject->ValueCache;\r
-    ChildList = (PCACHED_CHILD_LIST)&KeyObject->KeyCell->ValueList;\r
-\r
-    /* Check if the child list has any entries */\r
-    if (ChildList->Count != 0)\r
-    {\r
-        /* Get the value list associated to this child list */\r
-        SearchResult = CmpGetValueListFromCache(KeyObject,\r
-                                                &CellData,\r
-                                                &IndexIsCached,\r
-                                                &Cell);\r
-        if (SearchResult != SearchSuccess) return SearchResult;\r
-\r
-        /* The index shouldn't be cached right now */\r
-        if (IndexIsCached) ASSERT_VALUE_CACHE();\r
-\r
-        /* Loop every value */\r
-        while (TRUE)\r
-        {\r
-            /* Check if there's any cell to release */\r
-            if (*CellToRelease != HCELL_NIL)\r
-            {\r
-                /* Release it now */\r
-                HvReleaseCell(Hive, *CellToRelease);\r
-                *CellToRelease = HCELL_NIL;\r
-            }\r
-\r
-            /* Get the key value for this index */\r
-            SearchResult =  CmpGetValueKeyFromCache(KeyObject,\r
-                                                    CellData,\r
-                                                    i,\r
-                                                    CachedValue,\r
-                                                    Value,\r
-                                                    IndexIsCached,\r
-                                                    ValueIsCached,\r
-                                                    CellToRelease);\r
-            if (SearchResult != SearchSuccess) return SearchResult;\r
-\r
-            /* Check if the both the index and the value are cached */\r
-            if ((IndexIsCached) && (*ValueIsCached))\r
-            {\r
-                /* We don't expect this yet */\r
-                ASSERT_VALUE_CACHE();\r
-                Result = -1;\r
-            }\r
-            else\r
-            {\r
-                /* No cache, so try to compare the name. Is it compressed? */\r
-                KeyValue = *Value;\r
-                if (KeyValue->Flags & VALUE_COMP_NAME)\r
-                {\r
-                    /* It is, do a compressed name comparison */\r
-                    Result = CmpCompareCompressedName(Name,\r
-                                                      KeyValue->Name,\r
-                                                      KeyValue->NameLength);\r
-                }\r
-                else\r
-                {\r
-                    /* It's not compressed, so do a standard comparison */\r
-                    SearchName.Length = KeyValue->NameLength;\r
-                    SearchName.MaximumLength = SearchName.Length;\r
-                    SearchName.Buffer = KeyValue->Name;\r
-                    Result = RtlCompareUnicodeString(Name, &SearchName, TRUE);\r
-                }\r
-            }\r
-\r
-            /* Check if we found the value data */\r
-            if (!Result)\r
-            {\r
-                /* We have, return the index of the value and success */\r
-                *Index = i;\r
-                SearchResult = SearchSuccess;\r
-                goto Quickie;\r
-            }\r
-\r
-            /* We didn't find it, try the next entry */\r
-            if (++i == ChildList->Count)\r
-            {\r
-                /* The entire list was parsed, fail */\r
-                *Value = NULL;\r
-                SearchResult = SearchFail;\r
-                goto Quickie;\r
-            }\r
-        }\r
-    }\r
-\r
-    /* We should only get here if the child list is empty */\r
-    ASSERT(ChildList->Count == 0);\r
-\r
-Quickie:\r
-    /* Release the value list cell if required, and return search result */\r
-    if (Cell != HCELL_NIL) HvReleaseCell(Hive, Cell);\r
-    return SearchResult;\r
-}\r
-\r
-VALUE_SEARCH_RETURN_TYPE\r
-NTAPI\r
-CmpQueryKeyValueData(IN PKEY_OBJECT KeyObject,\r
-                     IN PCM_CACHED_VALUE *CachedValue,\r
-                     IN PCM_KEY_VALUE ValueKey,\r
-                     IN BOOLEAN ValueIsCached,\r
-                     IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,\r
-                     IN PVOID KeyValueInformation,\r
-                     IN ULONG Length,\r
-                     OUT PULONG ResultLength,\r
-                     OUT PNTSTATUS Status)\r
-{\r
-    PHHIVE Hive;\r
-    PKEY_VALUE_INFORMATION Info = (PKEY_VALUE_INFORMATION)KeyValueInformation;\r
-    PCELL_DATA CellData;\r
-    USHORT NameSize;\r
-    ULONG Size, MinimumSize, SizeLeft, KeySize, AlignedData = 0, DataOffset;\r
-    PVOID Buffer;\r
-    BOOLEAN IsSmall, BufferAllocated = FALSE;\r
-    HCELL_INDEX CellToRelease = HCELL_NIL;\r
-    VALUE_SEARCH_RETURN_TYPE Result = SearchSuccess;\r
-\r
-    /* Get the hive and cell data */\r
-    Hive = &KeyObject->RegistryHive->Hive;\r
-    CellData = (PCELL_DATA)ValueKey;\r
-\r
-    /* Check if the value is compressed */\r
-    if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME)\r
-    {\r
-        /* Get the compressed name size */\r
-        NameSize = CmpCompressedNameSize(CellData->u.KeyValue.Name,\r
-                                         CellData->u.KeyValue.NameLength);\r
-    }\r
-    else\r
-    {\r
-        /* Get the real size */\r
-        NameSize = CellData->u.KeyValue.NameLength;\r
-    }\r
-\r
-    /* Check what kind of information the caller is requesting */\r
-    switch (KeyValueInformationClass)\r
-    {\r
-        /* Basic information */\r
-        case KeyValueBasicInformation:\r
-\r
-            /* This is how much size we'll need */\r
-            Size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) + NameSize;\r
-\r
-            /* This is the minimum we can work with */\r
-            MinimumSize = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);\r
-\r
-            /* Return the size we'd like, and assume success */\r
-            *ResultLength = Size;\r
-            *Status = STATUS_SUCCESS;\r
-\r
-            /* Check if the caller gave us below our minimum */\r
-            if (Length < MinimumSize)\r
-            {\r
-                /* Then we must fail */\r
-                *Status = STATUS_BUFFER_TOO_SMALL;\r
-                break;\r
-            }\r
-\r
-            /* Fill out the basic information */\r
-            Info->KeyValueBasicInformation.TitleIndex = 0;\r
-            Info->KeyValueBasicInformation.Type = CellData->u.KeyValue.Type;\r
-            Info->KeyValueBasicInformation.NameLength = NameSize;\r
-\r
-            /* Now only the name is left */\r
-            SizeLeft = Length - MinimumSize;\r
-            Size = NameSize;\r
-\r
-            /* Check if the remaining buffer is too small for the name */\r
-            if (SizeLeft < Size)\r
-            {\r
-                /* Copy only as much as can fit, and tell the caller */\r
-                Size = SizeLeft;\r
-                *Status = STATUS_BUFFER_OVERFLOW;\r
-            }\r
-\r
-            /* Check if this is a compressed name */\r
-            if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME)\r
-            {\r
-                /* Copy as much as we can of the compressed name */\r
-                CmpCopyCompressedName(Info->KeyValueBasicInformation.Name,\r
-                                      Size,\r
-                                      CellData->u.KeyValue.Name,\r
-                                      CellData->u.KeyValue.NameLength);\r
-            }\r
-            else\r
-            {\r
-                /* Copy as much as we can of the raw name */\r
-                RtlCopyMemory(Info->KeyValueBasicInformation.Name,\r
-                              CellData->u.KeyValue.Name,\r
-                              Size);\r
-            }\r
-\r
-            /* We're all done */\r
-            break;\r
-\r
-        /* Full key information */\r
-        case KeyValueFullInformation:\r
-\r
-            /* Check if this is a small key and compute key size */\r
-            IsSmall = CmpIsKeyValueSmall(&KeySize,\r
-                                         CellData->u.KeyValue.DataLength);\r
-\r
-            /* Calculate the total size required */\r
-            Size = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) +\r
-                   NameSize +\r
-                   KeySize;\r
-\r
-            /* And this is the least we can work with */\r
-            MinimumSize = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);\r
-\r
-            /* Check if there's any key data */\r
-            if (KeySize > 0)\r
-            {\r
-                /* Calculate the data offset */\r
-                DataOffset = Size - KeySize;\r
-\r
-                /* Align the offset to 4 bytes */\r
-                AlignedData = ALIGN_UP(DataOffset, ULONG);\r
-\r
-                /* If alignment was required, we'll need more space */\r
-                if (AlignedData > DataOffset) Size += (AlignedData-DataOffset);\r
-            }\r
-\r
-            /* Tell the caller the size we'll finally need, and set success */\r
-            *ResultLength = Size;\r
-            *Status = STATUS_SUCCESS;\r
-\r
-            /* Check if the caller is giving us too little */\r
-            if (Length < MinimumSize)\r
-            {\r
-                /* Then fail right now */\r
-                *Status = STATUS_BUFFER_TOO_SMALL;\r
-                break;\r
-            }\r
-\r
-            /* Fill out the basic information */\r
-            Info->KeyValueFullInformation.TitleIndex = 0;\r
-            Info->KeyValueFullInformation.Type = CellData->u.KeyValue.Type;\r
-            Info->KeyValueFullInformation.DataLength = KeySize;\r
-            Info->KeyValueFullInformation.NameLength = NameSize;\r
-\r
-            /* Only the name is left now */\r
-            SizeLeft = Length - MinimumSize;\r
-            Size = NameSize;\r
-\r
-            /* Check if the name fits */\r
-            if (SizeLeft < Size)\r
-            {\r
-                /* It doesn't, truncate what we'll copy, and tell the caller */\r
-                Size = SizeLeft;\r
-                *Status = STATUS_BUFFER_OVERFLOW;\r
-            }\r
-\r
-            /* Check if this key value is compressed */\r
-            if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME)\r
-            {\r
-                /* It is, copy the compressed name */\r
-                CmpCopyCompressedName(Info->KeyValueFullInformation.Name,\r
-                                      Size,\r
-                                      CellData->u.KeyValue.Name,\r
-                                      CellData->u.KeyValue.NameLength);\r
-            }\r
-            else\r
-            {\r
-                /* It's not, copy the raw name */\r
-                RtlCopyMemory(Info->KeyValueFullInformation.Name,\r
-                              CellData->u.KeyValue.Name,\r
-                              Size);\r
-            }\r
-\r
-            /* Now check if the key had any data */\r
-            if (KeySize > 0)\r
-            {\r
-                /* Was it a small key? */\r
-                if (IsSmall)\r
-                {\r
-                    /* Then the data is directly into the cell */\r
-                    Buffer = &CellData->u.KeyValue.Data;\r
-                }\r
-                else\r
-                {\r
-                    /* Otherwise, we must retrieve it from the value cache */\r
-                    Result = CmpGetValueDataFromCache(KeyObject,\r
-                                                      CachedValue,\r
-                                                      CellData,\r
-                                                      ValueIsCached,\r
-                                                      &Buffer,\r
-                                                      &BufferAllocated,\r
-                                                      &CellToRelease);\r
-                    if (Result != SearchSuccess)\r
-                    {\r
-                        /* We failed, nothing should be allocated */\r
-                        ASSERT(Buffer == NULL);\r
-                        ASSERT(BufferAllocated == FALSE);\r
-                        *Status = STATUS_INSUFFICIENT_RESOURCES;\r
-                    }\r
-                }\r
-\r
-                /* Now that we know we truly have data, set its offset */\r
-                Info->KeyValueFullInformation.DataOffset = AlignedData;\r
-\r
-                /* Only the data remains to be copied */\r
-                SizeLeft = (((LONG)Length - (LONG)AlignedData) < 0) ?\r
-                           0 : (Length - AlignedData);\r
-                Size = KeySize;\r
-\r
-                /* Check if the caller has no space for it */\r
-                if (SizeLeft < Size)\r
-                {\r
-                    /* Truncate what we'll copy, and tell the caller */\r
-                    Size = SizeLeft;\r
-                    *Status = STATUS_BUFFER_OVERFLOW;\r
-                }\r
-\r
-                /* Sanity check */\r
-                ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE));\r
-\r
-                /* Make sure we have a valid buffer */\r
-                if (Buffer)\r
-                {\r
-                    /* Copy the data into the aligned offset */\r
-                    RtlCopyMemory((PVOID)((ULONG_PTR)Info + AlignedData),\r
-                                  Buffer,\r
-                                  Size);\r
-                }\r
-            }\r
-            else\r
-            {\r
-                /* We don't have any data, set the offset to -1, not 0! */\r
-                Info->KeyValueFullInformation.DataOffset = 0xFFFFFFFF;\r
-            }\r
-\r
-            /* We're done! */\r
-            break;\r
-\r
-        /* Partial information requested (no name or alignment!) */\r
-        case KeyValuePartialInformation:\r
-\r
-            /* Check if this is a small key and compute key size */\r
-            IsSmall = CmpIsKeyValueSmall(&KeySize,\r
-                                         CellData->u.KeyValue.DataLength);\r
-\r
-            /* Calculate the total size required */\r
-            Size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + KeySize;\r
-\r
-            /* And this is the least we can work with */\r
-            MinimumSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);\r
-\r
-            /* Tell the caller the size we'll finally need, and set success */\r
-            *ResultLength = Size;\r
-            *Status = STATUS_SUCCESS;\r
-\r
-            /* Check if the caller is giving us too little */\r
-            if (Length < MinimumSize)\r
-            {\r
-                /* Then fail right now */\r
-                *Status = STATUS_BUFFER_TOO_SMALL;\r
-                break;\r
-            }\r
-\r
-            /* Fill out the basic information */\r
-            Info->KeyValuePartialInformation.TitleIndex = 0;\r
-            Info->KeyValuePartialInformation.Type = CellData->u.KeyValue.Type;\r
-            Info->KeyValuePartialInformation.DataLength = KeySize;\r
-\r
-            /* Now check if the key had any data */\r
-            if (KeySize > 0)\r
-            {\r
-                /* Was it a small key? */\r
-                if (IsSmall)\r
-                {\r
-                    /* Then the data is directly into the cell */\r
-                    Buffer = &CellData->u.KeyValue.Data;\r
-                }\r
-                else\r
-                {\r
-                    /* Otherwise, we must retrieve it from the value cache */\r
-                    Result = CmpGetValueDataFromCache(KeyObject,\r
-                                                      CachedValue,\r
-                                                      CellData,\r
-                                                      ValueIsCached,\r
-                                                      &Buffer,\r
-                                                      &BufferAllocated,\r
-                                                      &CellToRelease);\r
-                    if (Result != SearchSuccess)\r
-                    {\r
-                        /* We failed, nothing should be allocated */\r
-                        ASSERT(Buffer == NULL);\r
-                        ASSERT(BufferAllocated == FALSE);\r
-                        *Status = STATUS_INSUFFICIENT_RESOURCES;\r
-                    }\r
-                }\r
-\r
-                /* Only the data remains to be copied */\r
-                SizeLeft = Length - MinimumSize;\r
-                Size = KeySize;\r
-\r
-                /* Check if the caller has no space for it */\r
-                if (SizeLeft < Size)\r
-                {\r
-                    /* Truncate what we'll copy, and tell the caller */\r
-                    Size = SizeLeft;\r
-                    *Status = STATUS_BUFFER_OVERFLOW;\r
-                }\r
-\r
-                /* Sanity check */\r
-                ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE));\r
-\r
-                /* Make sure we have a valid buffer */\r
-                if (Buffer)\r
-                {\r
-                    /* Copy the data into the aligned offset */\r
-                    RtlCopyMemory(Info->KeyValuePartialInformation.Data,\r
-                                  Buffer,\r
-                                  Size);\r
-                }\r
-            }\r
-\r
-            /* We're done! */\r
-            break;\r
-\r
-        /* Other information class */\r
-        default:\r
-\r
-            /* We got some class that we don't support */\r
-            *Status = STATUS_INVALID_PARAMETER;\r
-            break;\r
-    }\r
-\r
-    /* Return the search result as well */\r
-    return Result;\r
-}\r
+/*
+ * 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"
+#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 PCM_KEY_CONTROL_BLOCK Kcb,
+                         OUT PCELL_DATA *CellData,
+                         OUT BOOLEAN *IndexIsCached,
+                         OUT PHCELL_INDEX ValueListToRelease)
+{
+    PHHIVE Hive;
+    PCACHED_CHILD_LIST ChildList;
+    HCELL_INDEX CellToRelease;
+    PCM_KEY_NODE KeyNode;
+
+    /* Set defaults */
+    *ValueListToRelease = HCELL_NIL;
+    *IndexIsCached = FALSE;
+
+    /* Get the hive and value cache */
+    Hive = Kcb->KeyHive;
+    ChildList = &Kcb->ValueCache;
+    KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell);
+    ChildList = (PCACHED_CHILD_LIST)&KeyNode->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
+    {
+        /* Make sure the KCB is locked exclusive */
+        if (!(CmpIsKcbLockedExclusive(Kcb)) &&
+            !(CmpTryToConvertKcbSharedToExclusive(Kcb)))
+        {
+            /* We need the exclusive lock */
+            return SearchNeedExclusiveLock;
+        }
+                
+        /* 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;
+        
+        /* FIXME: Here we would cache the value */
+
+        /* 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 PCM_KEY_CONTROL_BLOCK Kcb,
+                        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 = Kcb->KeyHive;
+
+    /* 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 PCM_KEY_CONTROL_BLOCK Kcb,
+                         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 = Kcb->KeyHive;
+
+    /* 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 PCM_KEY_CONTROL_BLOCK Kcb,
+                            IN PCUNICODE_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;
+    PCM_KEY_NODE KeyNode;
+
+    /* Set defaults */
+    *CellToRelease = HCELL_NIL;
+    *Value = NULL;
+
+    /* Get the hive and child list */
+    Hive = Kcb->KeyHive;
+    ChildList = &Kcb->ValueCache;
+    KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell);
+    ChildList = (PCACHED_CHILD_LIST)&KeyNode->ValueList;
+
+    /* Check if the child list has any entries */
+    if (ChildList->Count != 0)
+    {
+        /* Get the value list associated to this child list */
+        SearchResult = CmpGetValueListFromCache(Kcb,
+                                                &CellData,
+                                                &IndexIsCached,
+                                                &Cell);
+        if (SearchResult != SearchSuccess)
+        {
+            /* We either failed or need the exclusive lock */
+            ASSERT((SearchResult == SearchFail) || !(CmpIsKcbLockedExclusive(Kcb)));
+            ASSERT(Cell == HCELL_NIL);
+            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(Kcb,
+                                                    CellData,
+                                                    i,
+                                                    CachedValue,
+                                                    Value,
+                                                    IndexIsCached,
+                                                    ValueIsCached,
+                                                    CellToRelease);
+            if (SearchResult != SearchSuccess)
+            {
+                /* We either failed or need the exclusive lock */
+                ASSERT((SearchResult == SearchFail) || !(CmpIsKcbLockedExclusive(Kcb)));
+                ASSERT(Cell == HCELL_NIL);
+                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 PCM_KEY_CONTROL_BLOCK Kcb,
+                     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 = Kcb->KeyHive;
+    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(Kcb,
+                                                      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 = (((LONG)Length - (LONG)AlignedData) < 0) ?
+                           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(Kcb,
+                                                      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;
+}
+
+VALUE_SEARCH_RETURN_TYPE
+NTAPI
+CmpCompareNewValueDataAgainstKCBCache(IN PCM_KEY_CONTROL_BLOCK Kcb,
+                                      IN PUNICODE_STRING ValueName,
+                                      IN ULONG Type,
+                                      IN PVOID Data,
+                                      IN ULONG DataSize)
+{
+    VALUE_SEARCH_RETURN_TYPE SearchResult;
+    PCM_KEY_NODE KeyNode;
+    PCM_CACHED_VALUE *CachedValue;
+    ULONG Index;
+    PCM_KEY_VALUE Value;
+    BOOLEAN ValueCached, BufferAllocated = FALSE;
+    PVOID Buffer;
+    HCELL_INDEX ValueCellToRelease = HCELL_NIL, CellToRelease = HCELL_NIL;
+    BOOLEAN IsSmall;
+    ULONG CompareResult;
+    PAGED_CODE();
+
+    /* Check if this is a symlink */
+    if (Kcb->Flags & KEY_SYM_LINK)
+    {
+        /* We need the exclusive lock */
+        if (!(CmpIsKcbLockedExclusive(Kcb)) &&
+            !(CmpTryToConvertKcbSharedToExclusive(Kcb)))
+        {
+            /* We need the exclusive lock */
+            return SearchNeedExclusiveLock;
+        }
+        
+        /* Otherwise, get the key node */
+        KeyNode = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive, Kcb->KeyCell);
+        if (!KeyNode) return SearchFail;
+        
+        /* Cleanup the KCB cache */
+        CmpCleanUpKcbValueCache(Kcb);
+        
+        /* Sanity checks */
+        ASSERT(!(CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList)));
+        ASSERT(!(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND));
+        
+        /* Set the value cache */
+        Kcb->ValueCache.Count = KeyNode->ValueList.Count;
+        Kcb->ValueCache.ValueList = KeyNode->ValueList.List;
+        
+        /* Release the cell */
+        HvReleaseCell(Kcb->KeyHive, Kcb->KeyCell);
+    }
+    
+    /* Do the search */
+    SearchResult = CmpFindValueByNameFromCache(Kcb,
+                                               ValueName,
+                                               &CachedValue,
+                                               &Index,
+                                               &Value,
+                                               &ValueCached,
+                                               &ValueCellToRelease);
+    if (SearchResult == SearchNeedExclusiveLock)
+    {
+        /* We need the exclusive lock */
+        ASSERT(!CmpIsKcbLockedExclusive(Kcb));
+        ASSERT(ValueCellToRelease == HCELL_NIL);
+        ASSERT(Value == NULL);
+        goto Quickie;
+    }
+    else if (SearchResult == SearchSuccess)
+    {
+        /* Sanity check */
+        ASSERT(Value);
+        
+        /* First of all, check if the key size and type matches */
+        if ((Type == Value->Type) &&
+            (DataSize == (Value->DataLength & ~CM_KEY_VALUE_SPECIAL_SIZE)))
+        {
+            /* Check if this is a small key */
+            IsSmall = (DataSize <= CM_KEY_VALUE_SMALL) ? TRUE: FALSE;
+            if (IsSmall)
+            {
+                /* Compare against the data directly */
+                Buffer = &Value->Data;
+            }
+            else
+            {
+                /* Do a search */
+                SearchResult = CmpGetValueDataFromCache(Kcb,
+                                                        CachedValue,
+                                                        (PCELL_DATA)Value,
+                                                        ValueCached,
+                                                        &Buffer,
+                                                        &BufferAllocated,
+                                                        &CellToRelease);
+                if (SearchResult != SearchSuccess)
+                {
+                    /* Sanity checks */
+                    ASSERT(Buffer == NULL);
+                    ASSERT(BufferAllocated == FALSE);
+                    goto Quickie;
+                }
+            }
+            
+            /* Now check the data size */
+            if (DataSize)
+            {
+                /* Do the compare */
+                CompareResult = RtlCompareMemory(Buffer,
+                                                 Data,
+                                                 DataSize &
+                                                 ~CM_KEY_VALUE_SPECIAL_SIZE);
+            }
+            else
+            {
+                /* It's equal */
+                CompareResult = 0;
+            }
+            
+            /* Now check if the compare wasn't equal */
+            if (CompareResult != DataSize) SearchResult = SearchFail;
+        }
+        else
+        {
+            /* The length or type isn't equal */
+            SearchResult = SearchFail;
+        }
+    }
+
+Quickie:
+    /* Release the value cell */
+    if (ValueCellToRelease) HvReleaseCell(Kcb->KeyHive, ValueCellToRelease);
+    
+    /* Free the buffer */
+    if (BufferAllocated) CmpFree(Buffer, 0);
+    
+    /* Free the cell */
+    if (CellToRelease) HvReleaseCell(Kcb->KeyHive, CellToRelease);
+
+    /* Return the search result */
+    return SearchResult;
+}