Exemple #1
0
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)
{
    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 value data */
    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:
        case KeyValueFullInformationAlign64:

            /* 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;

#ifdef _WIN64
                /* On 64-bit, always align to 8 bytes */
                AlignedData = ALIGN_UP(DataOffset, ULONGLONG);
#else
                /* On 32-bit, align the offset to 4 or 8 bytes */
                if (KeyValueInformationClass == KeyValueFullInformationAlign64)
                {
                    AlignedData = ALIGN_UP(DataOffset, ULONGLONG);
                }
                else
                {
                    AlignedData = ALIGN_UP(DataOffset, ULONG);
                }
#endif
                /* 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 */
            DPRINT1("Caller requested unknown class: %lx\n", KeyValueInformationClass);
            *Status = STATUS_INVALID_PARAMETER;
            break;
    }

    /* Return the search result as well */
    return Result;
}
Exemple #2
0
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;
}
Exemple #3
0
VALUE_SEARCH_RETURN_TYPE
CmpQueryKeyValueData(
    PCM_KEY_CONTROL_BLOCK KeyControlBlock,
    PPCM_CACHED_VALUE   ContainingList,
    PCM_KEY_VALUE       ValueKey,
    BOOLEAN             ValueCached,
    KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
    PVOID               KeyValueInformation,
    ULONG               Length,
    PULONG              ResultLength,
    NTSTATUS            *status
    )
/*++

Routine Description:

    Do the actual copy of data for a key value into caller's buffer.

    If KeyValueInformation is not long enough to hold all requested data,
    STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
    set to the number of bytes actually required.

Arguments:

    Hive - supplies a pointer to the hive control structure for the hive

    Cell - supplies index of node to whose sub keys are to be found

    KeyValueInformationClass - Specifies the type of information returned in
        KeyValueInformation.  One of the following types:

    KeyValueInformation -Supplies pointer to buffer to receive the data.

    Length - Length of KeyInformation in bytes.

    ResultLength - Number of bytes actually written into KeyInformation.

Return Value:

    NTSTATUS

--*/
{
    PKEY_VALUE_INFORMATION pbuffer;
    PCELL_DATA  pcell;
    LONG        leftlength;
    ULONG       requiredlength;
    ULONG       minimumlength;
    ULONG       offset;
    ULONG       base;
    ULONG       realsize;
    PUCHAR      datapointer;
    BOOLEAN     small;
    USHORT      NameLength;
    BOOLEAN     BufferAllocated = FALSE;
    HCELL_INDEX CellToRelease = HCELL_NIL;
    PHHIVE      Hive;
    VALUE_SEARCH_RETURN_TYPE SearchValue = SearchSuccess;

    Hive = KeyControlBlock->KeyHive;
    pbuffer = (PKEY_VALUE_INFORMATION)KeyValueInformation;

    pcell = (PCELL_DATA) ValueKey;
    NameLength = CmpValueNameLen(&pcell->u.KeyValue);

    switch (KeyValueInformationClass) {

    case KeyValueBasicInformation:

        //
        // TitleIndex, Type, NameLength, Name
        //
        requiredlength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) +
                         NameLength;

        minimumlength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);

        *ResultLength = requiredlength;

        *status = STATUS_SUCCESS;

        if (Length < minimumlength) {

            *status = STATUS_BUFFER_TOO_SMALL;

        } else {

            pbuffer->KeyValueBasicInformation.TitleIndex = 0;

            pbuffer->KeyValueBasicInformation.Type =
                pcell->u.KeyValue.Type;

            pbuffer->KeyValueBasicInformation.NameLength =
                NameLength;

            leftlength = Length - minimumlength;
            requiredlength = NameLength;

            if (leftlength < (LONG)requiredlength) {
                requiredlength = leftlength;
                *status = STATUS_BUFFER_OVERFLOW;
            }

            if (pcell->u.KeyValue.Flags & VALUE_COMP_NAME) {
                CmpCopyCompressedName(pbuffer->KeyValueBasicInformation.Name,
                                      requiredlength,
                                      pcell->u.KeyValue.Name,
                                      pcell->u.KeyValue.NameLength);
            } else {
                RtlCopyMemory(&(pbuffer->KeyValueBasicInformation.Name[0]),
                              &(pcell->u.KeyValue.Name[0]),
                              requiredlength);
            }
        }

        break;



    case KeyValueFullInformation:
    case KeyValueFullInformationAlign64:

        //
        // TitleIndex, Type, DataOffset, DataLength, NameLength,
        // Name, Data
        //
        small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);

        requiredlength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) +
                         NameLength +
                         realsize;

        minimumlength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
        offset = 0;
        if (realsize > 0) {
            base = requiredlength - realsize;

#if defined(_WIN64)

            offset = ALIGN_OFFSET64(base);

#else

            if (KeyValueInformationClass == KeyValueFullInformationAlign64) {
                offset = ALIGN_OFFSET64(base);

            } else {
                offset = ALIGN_OFFSET(base);
            }

#endif

            if (offset > base) {
                requiredlength += (offset - base);
            }

#if DBG && defined(_WIN64)

            //
            // Some clients will have passed in a structure that they "know"
            // will be exactly the right size.  The fact that alignment
            // has changed on NT64 may cause these clients to have problems.
            //
            // The solution is to fix the client, but print out some debug
            // spew here if it looks like this is the case.  This problem
            // isn't particularly easy to spot from the client end.
            //

            if((KeyValueInformationClass == KeyValueFullInformation) &&
                (Length != minimumlength) &&
                (requiredlength > Length) &&
                ((requiredlength - Length) <=
                                (ALIGN_OFFSET64(base) - ALIGN_OFFSET(base)))) {

                CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"ntos/config-64 KeyValueFullInformation: "
                                                                 "Possible client buffer size problem.\n"));

                CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"    Required size = %d\n", requiredlength));
                CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"    Supplied size = %d\n", Length));
            }

#endif

        }

        *ResultLength = requiredlength;

        *status = STATUS_SUCCESS;

        if (Length < minimumlength) {

            *status = STATUS_BUFFER_TOO_SMALL;

        } else {

            pbuffer->KeyValueFullInformation.TitleIndex = 0;

            pbuffer->KeyValueFullInformation.Type =
                pcell->u.KeyValue.Type;

            pbuffer->KeyValueFullInformation.DataLength =
                realsize;

            pbuffer->KeyValueFullInformation.NameLength =
                NameLength;

            leftlength = Length - minimumlength;
            requiredlength = NameLength;

            if (leftlength < (LONG)requiredlength) {
                requiredlength = leftlength;
                *status = STATUS_BUFFER_OVERFLOW;
            }

            if (pcell->u.KeyValue.Flags & VALUE_COMP_NAME) {
                CmpCopyCompressedName(pbuffer->KeyValueFullInformation.Name,
                                      requiredlength,
                                      pcell->u.KeyValue.Name,
                                      pcell->u.KeyValue.NameLength);
            } else {
                RtlCopyMemory(
                    &(pbuffer->KeyValueFullInformation.Name[0]),
                    &(pcell->u.KeyValue.Name[0]),
                    requiredlength
                    );
            }

            if (realsize > 0) {

                if (small == TRUE) {
                    datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
                } else {
                    SearchValue = CmpGetValueDataFromCache(KeyControlBlock, ContainingList, pcell, ValueCached,&datapointer,&BufferAllocated,&CellToRelease);
                    if( SearchValue != SearchSuccess ) {
                        ASSERT( datapointer == NULL );
                        ASSERT( BufferAllocated == FALSE );
                        *status = STATUS_INSUFFICIENT_RESOURCES;
                    }
                }

                pbuffer->KeyValueFullInformation.DataOffset = offset;

                leftlength = (((LONG)Length - (LONG)offset) < 0) ?
                                    0 :
                                    Length - offset;

                requiredlength = realsize;

                if (leftlength < (LONG)requiredlength) {
                    requiredlength = leftlength;
                    *status = STATUS_BUFFER_OVERFLOW;
                }

                ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));

                if( datapointer != NULL ) {
                    try {
                        RtlCopyMemory(
                            ((PUCHAR)pbuffer + offset),
                            datapointer,
                            requiredlength
                            );
                    } finally {
                        if( BufferAllocated == TRUE ) {
                            ExFreePool(datapointer);
                        }
                        if( CellToRelease != HCELL_NIL ) {
                            HvReleaseCell(Hive,CellToRelease);
                        }
                    }
                }

            } else {
                pbuffer->KeyValueFullInformation.DataOffset = (ULONG)-1;
            }
        }

        break;


    case KeyValuePartialInformation:

        //
        // TitleIndex, Type, DataLength, Data
        //
        small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);
        requiredlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) +
                         realsize;

        minimumlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);

        *ResultLength = requiredlength;

        *status = STATUS_SUCCESS;

        if (Length < minimumlength) {

            *status = STATUS_BUFFER_TOO_SMALL;

        } else {

            pbuffer->KeyValuePartialInformation.TitleIndex = 0;

            pbuffer->KeyValuePartialInformation.Type =
                pcell->u.KeyValue.Type;

            pbuffer->KeyValuePartialInformation.DataLength =
                realsize;

            leftlength = Length - minimumlength;
            requiredlength = realsize;

            if (leftlength < (LONG)requiredlength) {
                requiredlength = leftlength;
                *status = STATUS_BUFFER_OVERFLOW;
            }

            if (realsize > 0) {

                if (small == TRUE) {
                    datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
                } else {
                    SearchValue = CmpGetValueDataFromCache(KeyControlBlock, ContainingList, pcell, ValueCached,&datapointer,&BufferAllocated,&CellToRelease);
                    if( SearchValue != SearchSuccess ) {
                        ASSERT( datapointer == NULL );
                        ASSERT( BufferAllocated == FALSE );
                        *status = STATUS_INSUFFICIENT_RESOURCES;
                    }
                }

                ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));

                if( datapointer != NULL ) {
                    try {
                        RtlCopyMemory((PUCHAR)&(pbuffer->KeyValuePartialInformation.Data[0]),
                                      datapointer,
                                      requiredlength);
                    } finally {
                        if( BufferAllocated == TRUE ) {
                            ExFreePool(datapointer);
                        }
                        if(CellToRelease != HCELL_NIL) {
                            HvReleaseCell(Hive,CellToRelease);
                        }
                    }
                }
            }
        }

        break;
    case KeyValuePartialInformationAlign64:

        //
        // TitleIndex, Type, DataLength, Data
        //
        small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);
        requiredlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, Data) +
                         realsize;

        minimumlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, Data);

        *ResultLength = requiredlength;

        *status = STATUS_SUCCESS;

        if (Length < minimumlength) {

            *status = STATUS_BUFFER_TOO_SMALL;

        } else {

            pbuffer->KeyValuePartialInformationAlign64.Type =
                pcell->u.KeyValue.Type;

            pbuffer->KeyValuePartialInformationAlign64.DataLength =
                realsize;

            leftlength = Length - minimumlength;
            requiredlength = realsize;

            if (leftlength < (LONG)requiredlength) {
                requiredlength = leftlength;
                *status = STATUS_BUFFER_OVERFLOW;
            }

            if (realsize > 0) {

                if (small == TRUE) {
                    datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
                } else {
                    SearchValue = CmpGetValueDataFromCache(KeyControlBlock, ContainingList, pcell, ValueCached,&datapointer,&BufferAllocated,&CellToRelease);
                    if( SearchValue != SearchSuccess ) {
                        ASSERT( datapointer == NULL );
                        ASSERT( BufferAllocated == FALSE );
                        *status = STATUS_INSUFFICIENT_RESOURCES;
                    }
                }

                ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));
                if( datapointer != NULL ) {
                    try {
                        RtlCopyMemory((PUCHAR)&(pbuffer->KeyValuePartialInformationAlign64.Data[0]),
                                      datapointer,
                                      requiredlength);
                    } finally {
                        if( BufferAllocated == TRUE ) {
                            ExFreePool(datapointer);
                        }
                        if(CellToRelease != HCELL_NIL) {
                            HvReleaseCell(Hive,CellToRelease);
                        }
                    }
                }
            }
        }

        break;

    default:
        *status = STATUS_INVALID_PARAMETER;
        break;
    }