1510 lines
39 KiB
C
1510 lines
39 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
cmvalue.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains cm routines for operating on (sorted)
|
||
|
value list. Insertion, Deletion,Searching ...
|
||
|
|
||
|
Routines to deal with a KeyValue data; whether it is small,
|
||
|
big - new hives format - , or normal
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Dragos C. Sambotin (dragoss) 12-Aug-1999
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "cmp.h"
|
||
|
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
#pragma alloc_text(PAGE,CmpFindValueByName)
|
||
|
#pragma alloc_text(PAGE,CmpFindNameInList)
|
||
|
#pragma alloc_text(PAGE,CmpAddValueToList)
|
||
|
#pragma alloc_text(PAGE,CmpRemoveValueFromList)
|
||
|
#pragma alloc_text(PAGE,CmpGetValueData)
|
||
|
#pragma alloc_text(PAGE,CmpMarkValueDataDirty)
|
||
|
#pragma alloc_text(PAGE,CmpFreeValue)
|
||
|
#pragma alloc_text(PAGE,CmpSetValueDataNew)
|
||
|
#pragma alloc_text(PAGE,CmpSetValueDataExisting)
|
||
|
#pragma alloc_text(PAGE,CmpFreeValueData)
|
||
|
#pragma alloc_text(PAGE,CmpValueToData)
|
||
|
#endif
|
||
|
|
||
|
HCELL_INDEX
|
||
|
CmpFindValueByName(
|
||
|
PHHIVE Hive,
|
||
|
PCM_KEY_NODE KeyNode,
|
||
|
PUNICODE_STRING Name
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Underlying CmpFindNameInList was changed to return an error code;
|
||
|
Had to make it a function instead of a macro
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Hive - pointer to hive control structure for hive of interest
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
|
||
|
HCELL_INDEX or HCELL_NIL on error
|
||
|
--*/
|
||
|
{
|
||
|
HCELL_INDEX CellIndex;
|
||
|
|
||
|
#ifndef _CM_LDR_
|
||
|
PAGED_CODE();
|
||
|
#endif //_CM_LDR_
|
||
|
|
||
|
if( CmpFindNameInList(Hive,&((KeyNode)->ValueList),Name,NULL,&CellIndex) == FALSE ) {
|
||
|
//
|
||
|
// above should set this right
|
||
|
//
|
||
|
ASSERT( CellIndex == HCELL_NIL );
|
||
|
}
|
||
|
return CellIndex;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
CmpFindNameInList(
|
||
|
IN PHHIVE Hive,
|
||
|
IN PCHILD_LIST ChildList,
|
||
|
IN PUNICODE_STRING Name,
|
||
|
IN OPTIONAL PULONG ChildIndex,
|
||
|
OUT PHCELL_INDEX CellIndex
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Find a child object in an object list. Child List must be sorted
|
||
|
based on the name. (for new hives format)
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Hive - pointer to hive control structure for hive of interest
|
||
|
|
||
|
List - pointer to mapped in list structure
|
||
|
|
||
|
Count - number of elements in list structure
|
||
|
|
||
|
Name - name of child object to find
|
||
|
|
||
|
ChildIndex - pointer to variable to receive index for child;
|
||
|
|
||
|
CellIndex - pointer to receive the index of the child.
|
||
|
On return, this is:
|
||
|
HCELL_INDEX for the found cell
|
||
|
HCELL_NIL if not found
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - success
|
||
|
FALSE - error, insufficient resources
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
ChildIndex is always filled with the position where Name should be in the list.
|
||
|
The difference whether Name is in the list or not is made upon CellIndex
|
||
|
- CellIndex == HCELL_NIL ==> Name not found in the list
|
||
|
- CellIndex <> HCELL_NIL ==> Name already exists in the list
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
PCM_KEY_VALUE pchild;
|
||
|
UNICODE_STRING Candidate;
|
||
|
LONG Result;
|
||
|
PCELL_DATA List = NULL;
|
||
|
ULONG Current;
|
||
|
HCELL_INDEX CellToRelease = HCELL_NIL;
|
||
|
BOOLEAN ReturnValue = FALSE;
|
||
|
|
||
|
#ifndef _CM_LDR_
|
||
|
PAGED_CODE();
|
||
|
#endif //_CM_LDR_
|
||
|
|
||
|
if (ChildList->Count != 0) {
|
||
|
List = (PCELL_DATA)HvGetCell(Hive,ChildList->List);
|
||
|
if( List == NULL ) {
|
||
|
//
|
||
|
// we could not map the view containing the cell
|
||
|
//
|
||
|
*CellIndex = HCELL_NIL;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// old plain hive; simulate a for
|
||
|
//
|
||
|
Current = 0;
|
||
|
|
||
|
while( TRUE ) {
|
||
|
|
||
|
if( CellToRelease != HCELL_NIL ) {
|
||
|
HvReleaseCell(Hive,CellToRelease);
|
||
|
CellToRelease = HCELL_NIL;
|
||
|
}
|
||
|
pchild = (PCM_KEY_VALUE)HvGetCell(Hive, List->u.KeyList[Current]);
|
||
|
if( pchild == NULL ) {
|
||
|
//
|
||
|
// we could not map the view containing the cell
|
||
|
//
|
||
|
*CellIndex = HCELL_NIL;
|
||
|
ReturnValue = FALSE;
|
||
|
goto JustReturn;
|
||
|
}
|
||
|
CellToRelease = List->u.KeyList[Current];
|
||
|
|
||
|
if (pchild->Flags & VALUE_COMP_NAME) {
|
||
|
Result = CmpCompareCompressedName(Name,
|
||
|
pchild->Name,
|
||
|
pchild->NameLength,
|
||
|
0);
|
||
|
} else {
|
||
|
Candidate.Length = pchild->NameLength;
|
||
|
Candidate.MaximumLength = Candidate.Length;
|
||
|
Candidate.Buffer = pchild->Name;
|
||
|
Result = RtlCompareUnicodeString(Name,
|
||
|
&Candidate,
|
||
|
TRUE);
|
||
|
}
|
||
|
|
||
|
if (Result == 0) {
|
||
|
//
|
||
|
// Success, return data to caller and exit
|
||
|
//
|
||
|
|
||
|
if (ARGUMENT_PRESENT(ChildIndex)) {
|
||
|
*ChildIndex = Current;
|
||
|
}
|
||
|
*CellIndex = List->u.KeyList[Current];
|
||
|
ReturnValue = TRUE;
|
||
|
goto JustReturn;
|
||
|
}
|
||
|
//
|
||
|
// compute the next index to try: old'n plain hive; go on
|
||
|
//
|
||
|
Current++;
|
||
|
if( Current == ChildList->Count ) {
|
||
|
//
|
||
|
// we've reached the end of the list
|
||
|
//
|
||
|
if (ARGUMENT_PRESENT(ChildIndex)) {
|
||
|
*ChildIndex = Current;
|
||
|
}
|
||
|
//
|
||
|
// nicely return
|
||
|
//
|
||
|
*CellIndex = HCELL_NIL;
|
||
|
ReturnValue = TRUE;
|
||
|
goto JustReturn;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// in the new design we shouldn't get here; we should exit the while loop with return
|
||
|
//
|
||
|
ASSERT( ChildList->Count == 0 );
|
||
|
// add it first; as it's the only one
|
||
|
if (ARGUMENT_PRESENT(ChildIndex)) {
|
||
|
*ChildIndex = 0;
|
||
|
}
|
||
|
*CellIndex = HCELL_NIL;
|
||
|
return TRUE;
|
||
|
|
||
|
JustReturn:
|
||
|
if( List != NULL ) {
|
||
|
HvReleaseCell(Hive,ChildList->List);
|
||
|
}
|
||
|
if( CellToRelease != HCELL_NIL ) {
|
||
|
HvReleaseCell(Hive,CellToRelease);
|
||
|
}
|
||
|
return ReturnValue;
|
||
|
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
CmpGetValueData(IN PHHIVE Hive,
|
||
|
IN PCM_KEY_VALUE Value,
|
||
|
OUT PULONG realsize,
|
||
|
IN OUT PVOID *Buffer,
|
||
|
OUT PBOOLEAN Allocated,
|
||
|
OUT PHCELL_INDEX CellToRelease
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Retrieves the real valueData, given the key value.
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Hive - pointer to hive control structure for hive of interest
|
||
|
|
||
|
Value - CM_KEY_VALUE to retrieve the data for.
|
||
|
|
||
|
realsize - the actual size of the data (in bytes)
|
||
|
|
||
|
Buffer - pointer to the data; if the cell is a BIG_CELL
|
||
|
we should allocate a buffer
|
||
|
|
||
|
Allocated - here we signal the caller that he has to free the
|
||
|
buffer on return;
|
||
|
TRUE - a new buffer was allocated to gather together the BIG_CELL data
|
||
|
FALSE - Buffer points directly in the hive, the caller shouldn't free it
|
||
|
|
||
|
CellToRelease - Cell to release after finishing work with Buffer
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - success
|
||
|
|
||
|
FALSE - not enough resources available; (to map a cell or to allocate the buffer)
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
The caller is responsible to remove the buffer, when Allocated is set on TRUE on return;
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
#ifndef _CM_LDR_
|
||
|
PAGED_CODE();
|
||
|
#endif //_CM_LDR_
|
||
|
|
||
|
ASSERT_KEY_VALUE(Value);
|
||
|
//
|
||
|
// normally we don't allocate buffer
|
||
|
//
|
||
|
*Allocated = FALSE;
|
||
|
*Buffer = NULL;
|
||
|
*CellToRelease = HCELL_NIL;
|
||
|
|
||
|
//
|
||
|
// check for small values
|
||
|
//
|
||
|
if( CmpIsHKeyValueSmall(*realsize, Value->DataLength) == TRUE ) {
|
||
|
//
|
||
|
// data is stored inside the cell
|
||
|
//
|
||
|
*Buffer = &Value->Data;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
#ifndef _CM_LDR_
|
||
|
//
|
||
|
// check for big values
|
||
|
//
|
||
|
if( CmpIsHKeyValueBig(Hive,*realsize) == TRUE ) {
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
PCM_BIG_DATA BigData = NULL;
|
||
|
PUCHAR WorkBuffer;
|
||
|
ULONG Length;
|
||
|
USHORT i;
|
||
|
PUCHAR PartialData;
|
||
|
PHCELL_INDEX Plist = NULL;
|
||
|
|
||
|
#ifndef _CM_LDR_
|
||
|
try {
|
||
|
#endif //_CM_LDR_
|
||
|
BigData = (PCM_BIG_DATA)HvGetCell(Hive,Value->Data);
|
||
|
if( BigData == NULL ) {
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
//
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
ASSERT_BIG_DATA(BigData);
|
||
|
|
||
|
Plist = (PHCELL_INDEX)HvGetCell(Hive,BigData->List);
|
||
|
if( Plist == NULL ) {
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
//
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
Length = Value->DataLength;
|
||
|
//
|
||
|
// sanity check
|
||
|
//
|
||
|
ASSERT( Length <= (ULONG)(BigData->Count * CM_KEY_VALUE_BIG) );
|
||
|
|
||
|
//
|
||
|
// allocate a buffer to merge bring all the pieces together
|
||
|
//
|
||
|
WorkBuffer = (PUCHAR)ExAllocatePoolWithTag(PagedPool, Length, CM_POOL_TAG);
|
||
|
if( WorkBuffer == NULL ){
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
for(i=0;i<BigData->Count;i++) {
|
||
|
//
|
||
|
// sanity check
|
||
|
//
|
||
|
ASSERT( Length > 0 );
|
||
|
|
||
|
PartialData = (PUCHAR)HvGetCell(Hive,Plist[i]);
|
||
|
if( PartialData == NULL ){
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
//
|
||
|
ExFreePool(WorkBuffer);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// copy this piece of data to the work buffer
|
||
|
//
|
||
|
RtlCopyMemory(WorkBuffer + CM_KEY_VALUE_BIG*i,PartialData,(Length>CM_KEY_VALUE_BIG)?CM_KEY_VALUE_BIG:Length);
|
||
|
HvReleaseCell(Hive,Plist[i]);
|
||
|
|
||
|
//
|
||
|
// adjust the data still to copy.
|
||
|
// All cells in Plist should be of size CM_KEY_VALUE_BIG, except the last one, which is the remaining
|
||
|
//
|
||
|
Length -= CM_KEY_VALUE_BIG;
|
||
|
}
|
||
|
#ifndef _CM_LDR_
|
||
|
} finally {
|
||
|
if( BigData != NULL ) {
|
||
|
HvReleaseCell(Hive,Value->Data);
|
||
|
if( Plist != NULL ) {
|
||
|
HvReleaseCell(Hive,BigData->List);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif //_CM_LDR_
|
||
|
//
|
||
|
// if we are here; we successfuly have copied all data into WorkBuffer.
|
||
|
// update the return buffer and return; Caller is responsible to free the return buffer
|
||
|
// We signal the caller by setting Allocated on TRUE
|
||
|
//
|
||
|
*Buffer = WorkBuffer;
|
||
|
*Allocated = TRUE;
|
||
|
return TRUE;
|
||
|
}
|
||
|
#endif //_CM_LDR_
|
||
|
|
||
|
//
|
||
|
// normal, old plain case
|
||
|
//
|
||
|
*Buffer = HvGetCell(Hive,Value->Data);
|
||
|
if( *Buffer == NULL ) {
|
||
|
//
|
||
|
// insufficient resources to map the view containing this cell
|
||
|
//
|
||
|
return FALSE;
|
||
|
}
|
||
|
//
|
||
|
// signal to the caller to release this cell after finishing with buffer
|
||
|
//
|
||
|
*CellToRelease = Value->Data;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
PCELL_DATA
|
||
|
CmpValueToData(IN PHHIVE Hive,
|
||
|
IN PCM_KEY_VALUE Value,
|
||
|
OUT PULONG realsize
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Retrieves the real valueData, given the key value.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Hive - pointer to hive control structure for hive of interest
|
||
|
|
||
|
Value - CM_KEY_VALUE to retrieve the data for.
|
||
|
|
||
|
realsize - the actual size of the data (in bytes)
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
pointer to the value data; NULL if any error (insuficient resources)
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
This function doesn't support big cells; It is intended to be called just
|
||
|
by the loader, which doesn't store large data. It'll bugcheck if big cell
|
||
|
is queried.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PCELL_DATA Buffer;
|
||
|
BOOLEAN BufferAllocated;
|
||
|
HCELL_INDEX CellToRelease;
|
||
|
|
||
|
#ifndef _CM_LDR_
|
||
|
PAGED_CODE();
|
||
|
#endif //_CM_LDR_
|
||
|
|
||
|
ASSERT( Hive->ReleaseCellRoutine == NULL );
|
||
|
|
||
|
if( CmpGetValueData(Hive,Value,realsize,&Buffer,&BufferAllocated,&CellToRelease) == FALSE ) {
|
||
|
//
|
||
|
// insufficient resources; return NULL
|
||
|
//
|
||
|
ASSERT( BufferAllocated == FALSE );
|
||
|
ASSERT( Buffer == NULL );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// we specificallly ignore CellToRelease as this is not a mapped view
|
||
|
//
|
||
|
if( BufferAllocated == TRUE ) {
|
||
|
//
|
||
|
// this function is not intended for big cells;
|
||
|
//
|
||
|
#ifndef _CM_LDR_
|
||
|
ExFreePool( Buffer );
|
||
|
#endif //_CM_LDR_
|
||
|
CM_BUGCHECK( REGISTRY_ERROR,BIG_CELL_ERROR,0,Hive,Value);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// success
|
||
|
//
|
||
|
return Buffer;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef _CM_LDR_
|
||
|
|
||
|
NTSTATUS
|
||
|
CmpAddValueToList(
|
||
|
IN PHHIVE Hive,
|
||
|
IN HCELL_INDEX ValueCell,
|
||
|
IN ULONG Index,
|
||
|
IN ULONG Type,
|
||
|
IN OUT PCHILD_LIST ChildList
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Adds a value to the value list, keeping the list sorted
|
||
|
(for new hives format)
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Hive - pointer to hive control structure for hive of interest
|
||
|
|
||
|
ValueCell - value index
|
||
|
|
||
|
Index - index at which to add the value
|
||
|
|
||
|
ChildList - pointer to the list of values
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
STATUS_SUCCESS - success
|
||
|
|
||
|
STATUS_INSUFFICIENT_RESOURCES - an error occured
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
HCELL_INDEX NewCell;
|
||
|
ULONG count;
|
||
|
ULONG AllocateSize;
|
||
|
ULONG i;
|
||
|
PCELL_DATA pdata;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// we have the lock exclusive or nobody is operating inside this hive
|
||
|
//
|
||
|
//ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
||
|
ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
|
||
|
|
||
|
//
|
||
|
// sanity check for index range
|
||
|
//
|
||
|
ASSERT( (((LONG)Index) >= 0) && (Index <= ChildList->Count) );
|
||
|
|
||
|
count = ChildList->Count;
|
||
|
count++;
|
||
|
if (count > 1) {
|
||
|
|
||
|
ASSERT_CELL_DIRTY(Hive,ChildList->List);
|
||
|
|
||
|
if (count < CM_MAX_REASONABLE_VALUES) {
|
||
|
|
||
|
//
|
||
|
// A reasonable number of values, allocate just enough
|
||
|
// space.
|
||
|
//
|
||
|
|
||
|
AllocateSize = count * sizeof(HCELL_INDEX);
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// An excessive number of values, pad the allocation out
|
||
|
// to avoid fragmentation. (if there's this many values,
|
||
|
// there'll probably be more pretty soon)
|
||
|
//
|
||
|
AllocateSize = ROUND_UP(count, CM_MAX_REASONABLE_VALUES) * sizeof(HCELL_INDEX);
|
||
|
if (AllocateSize > HBLOCK_SIZE) {
|
||
|
AllocateSize = ROUND_UP(AllocateSize, HBLOCK_SIZE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NewCell = HvReallocateCell(
|
||
|
Hive,
|
||
|
ChildList->List,
|
||
|
AllocateSize
|
||
|
);
|
||
|
} else {
|
||
|
NewCell = HvAllocateCell(Hive, sizeof(HCELL_INDEX), Type,ValueCell);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// put ourselves on the list
|
||
|
//
|
||
|
if (NewCell != HCELL_NIL) {
|
||
|
// sanity
|
||
|
ChildList->List = NewCell;
|
||
|
|
||
|
pdata = HvGetCell(Hive, NewCell);
|
||
|
if( pdata == NULL ) {
|
||
|
//
|
||
|
// we couldn't map a view for the bin containing this cell
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// normally this shouldn't happen as we just allocated ValueCell
|
||
|
// i.e. the bin containing NewCell should be mapped in memory at this point.
|
||
|
//
|
||
|
ASSERT( FALSE );
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// make room for the new cell; move values in the reverse order !
|
||
|
// adding at the end makes this a nop
|
||
|
//
|
||
|
for( i = count - 1; i > Index; i-- ) {
|
||
|
pdata->u.KeyList[i] = pdata->u.KeyList[i-1];
|
||
|
}
|
||
|
pdata->u.KeyList[Index] = ValueCell;
|
||
|
ChildList->Count = count;
|
||
|
|
||
|
HvReleaseCell(Hive,NewCell);
|
||
|
// sanity
|
||
|
ASSERT_CELL_DIRTY(Hive,ValueCell);
|
||
|
|
||
|
} else {
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
CmpRemoveValueFromList(
|
||
|
IN PHHIVE Hive,
|
||
|
IN ULONG Index,
|
||
|
IN OUT PCHILD_LIST ChildList
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Removes the value at the specified index from the value list
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Hive - pointer to hive control structure for hive of interest
|
||
|
|
||
|
Index - index at which to add the value
|
||
|
|
||
|
ChildList - pointer to the list of values
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
STATUS_SUCCESS - success
|
||
|
|
||
|
STATUS_INSUFFICIENT_RESOURCES - an error occured
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
The caller is responsible for freeing the removed value
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG newcount;
|
||
|
HCELL_INDEX newcell;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
||
|
|
||
|
//
|
||
|
// sanity check for index range
|
||
|
//
|
||
|
ASSERT( (((LONG)Index) >= 0) && (Index <= ChildList->Count) );
|
||
|
|
||
|
newcount = ChildList->Count - 1;
|
||
|
|
||
|
if (newcount > 0) {
|
||
|
PCELL_DATA pvector;
|
||
|
|
||
|
//
|
||
|
// more than one entry list, squeeze
|
||
|
//
|
||
|
pvector = HvGetCell(Hive, ChildList->List);
|
||
|
if( pvector == NULL ) {
|
||
|
//
|
||
|
// we couldn't map a view for the bin containing this cell
|
||
|
//
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,ChildList->List);
|
||
|
|
||
|
// sanity
|
||
|
ASSERT_CELL_DIRTY(Hive,ChildList->List);
|
||
|
ASSERT_CELL_DIRTY(Hive,pvector->u.KeyList[Index]);
|
||
|
|
||
|
for ( ; Index < newcount; Index++) {
|
||
|
pvector->u.KeyList[ Index ] = pvector->u.KeyList[ Index + 1 ];
|
||
|
}
|
||
|
|
||
|
newcell = HvReallocateCell(
|
||
|
Hive,
|
||
|
ChildList->List,
|
||
|
newcount * sizeof(HCELL_INDEX)
|
||
|
);
|
||
|
ASSERT(newcell != HCELL_NIL);
|
||
|
ChildList->List = newcell;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// list is empty, free it
|
||
|
//
|
||
|
HvFreeCell(Hive, ChildList->List);
|
||
|
ChildList->List = HCELL_NIL;
|
||
|
}
|
||
|
ChildList->Count = newcount;
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
CmpMarkValueDataDirty( IN PHHIVE Hive,
|
||
|
IN PCM_KEY_VALUE Value
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Marks the cell(s) storing the value data as dirty;
|
||
|
Knows how to deal with bigcells
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Hive - pointer to hive control structure for hive of interest
|
||
|
|
||
|
Value - CM_KEY_VALUE to retrieve the data for.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - success
|
||
|
FALSE - failure to mark all the cells involved;
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG realsize;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// we have the lock exclusive or nobody is operating inside this hive
|
||
|
//
|
||
|
//ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
||
|
ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
|
||
|
|
||
|
ASSERT_KEY_VALUE(Value);
|
||
|
|
||
|
if( Value->Data != HCELL_NIL ) {
|
||
|
//
|
||
|
// Could be that value was just partially initialized (CmpSetValueKeyNew case)
|
||
|
//
|
||
|
//
|
||
|
// check for small values
|
||
|
//
|
||
|
if( CmpIsHKeyValueSmall(realsize, Value->DataLength) == TRUE ) {
|
||
|
//
|
||
|
// data is stored inside the cell
|
||
|
//
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// check for big values
|
||
|
//
|
||
|
if( CmpIsHKeyValueBig(Hive,realsize) == TRUE ) {
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
PCM_BIG_DATA BigData;
|
||
|
PHCELL_INDEX Plist;
|
||
|
USHORT i;
|
||
|
|
||
|
BigData = (PCM_BIG_DATA)HvGetCell(Hive,Value->Data);
|
||
|
if( BigData == NULL ) {
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
//
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
ASSERT_BIG_DATA(BigData);
|
||
|
|
||
|
if( BigData->List != HCELL_NIL ) {
|
||
|
Plist = (PHCELL_INDEX)HvGetCell(Hive,BigData->List);
|
||
|
if( Plist == NULL ) {
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
//
|
||
|
HvReleaseCell(Hive,Value->Data);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
for(i=0;i<BigData->Count;i++) {
|
||
|
//
|
||
|
// mark this chunk dirty
|
||
|
//
|
||
|
if( Plist[i] != HCELL_NIL ) {
|
||
|
if (! HvMarkCellDirty(Hive, Plist[i])) {
|
||
|
HvReleaseCell(Hive,Value->Data);
|
||
|
HvReleaseCell(Hive,BigData->List);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// mark the list as dirty
|
||
|
//
|
||
|
if (! HvMarkCellDirty(Hive, BigData->List)) {
|
||
|
HvReleaseCell(Hive,Value->Data);
|
||
|
HvReleaseCell(Hive,BigData->List);
|
||
|
return FALSE;
|
||
|
}
|
||
|
//
|
||
|
// we can safely remove it here as it is now dirty/pinned
|
||
|
//
|
||
|
HvReleaseCell(Hive,BigData->List);
|
||
|
}
|
||
|
//
|
||
|
// we don't need this cell anymore
|
||
|
//
|
||
|
HvReleaseCell(Hive,Value->Data);
|
||
|
//
|
||
|
// fall through to mark the cell itself as dirty
|
||
|
//
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Data is a HCELL_INDEX; mark it dirty
|
||
|
//
|
||
|
if (! HvMarkCellDirty(Hive, Value->Data)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
CmpFreeValueData(
|
||
|
PHHIVE Hive,
|
||
|
HCELL_INDEX DataCell,
|
||
|
ULONG DataLength
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Free the Value Data DataCell carries with.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Hive - supplies a pointer to the hive control structure for the hive
|
||
|
|
||
|
DataCell - supplies index of value who's data to free
|
||
|
|
||
|
DataLength - length of the data; used to detect the type of the cell
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE: Success
|
||
|
FALSE: Error
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
Knows how to deal with big cell(s)
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG realsize;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
||
|
|
||
|
//
|
||
|
// check for small values
|
||
|
//
|
||
|
if( CmpIsHKeyValueSmall(realsize, DataLength) == TRUE ) {
|
||
|
//
|
||
|
// data is stored inside the cell; this is a nop
|
||
|
//
|
||
|
} else {
|
||
|
//
|
||
|
// Could be that value was just partially initialized (CmpSetValueKeyNew case)
|
||
|
//
|
||
|
if( DataCell == HCELL_NIL ) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
ASSERT(HvIsCellAllocated(Hive,DataCell));
|
||
|
//
|
||
|
// check for big values
|
||
|
//
|
||
|
if( CmpIsHKeyValueBig(Hive,realsize) == TRUE ) {
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
PCM_BIG_DATA BigData;
|
||
|
PHCELL_INDEX Plist;
|
||
|
USHORT i;
|
||
|
|
||
|
BigData = (PCM_BIG_DATA)HvGetCell(Hive,DataCell);
|
||
|
if( BigData == NULL ) {
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
//
|
||
|
// This shouldn't happen as this cell is marked ditry by
|
||
|
// this time (i.e. its view is pinned in memory)
|
||
|
//
|
||
|
ASSERT( FALSE );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,DataCell);
|
||
|
|
||
|
ASSERT_BIG_DATA(BigData);
|
||
|
|
||
|
if( BigData->List != HCELL_NIL ) {
|
||
|
Plist = (PHCELL_INDEX)HvGetCell(Hive,BigData->List);
|
||
|
if( Plist == NULL ) {
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
//
|
||
|
//
|
||
|
// This shouldn't happen as this cell is marked ditry by
|
||
|
// this time (i.e. its view is pinned in memory)
|
||
|
//
|
||
|
ASSERT( FALSE );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,BigData->List);
|
||
|
|
||
|
for(i=0;i<BigData->Count;i++) {
|
||
|
//
|
||
|
// mark this chunk dirty
|
||
|
//
|
||
|
if( Plist[i] != HCELL_NIL ) {
|
||
|
HvFreeCell(Hive, Plist[i]);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// mark the list as dirty
|
||
|
//
|
||
|
HvFreeCell(Hive, BigData->List);
|
||
|
}
|
||
|
//
|
||
|
// fall through to free the cell data itself
|
||
|
//
|
||
|
|
||
|
}
|
||
|
//
|
||
|
// normal case free the Data cell
|
||
|
//
|
||
|
HvFreeCell(Hive, DataCell);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
CmpFreeValue(
|
||
|
PHHIVE Hive,
|
||
|
HCELL_INDEX Cell
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Free the value entry Hive.Cell refers to, including
|
||
|
its name and data cells.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Hive - supplies a pointer to the hive control structure for the hive
|
||
|
|
||
|
Cell - supplies index of value to delete
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE: Success
|
||
|
FALSE: Error
|
||
|
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PCM_KEY_VALUE Value;
|
||
|
ULONG realsize;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
||
|
|
||
|
//
|
||
|
// map in the cell
|
||
|
//
|
||
|
Value = (PCM_KEY_VALUE)HvGetCell(Hive, Cell);
|
||
|
if( Value == NULL ) {
|
||
|
//
|
||
|
// we couldn't map the bin containing this cell
|
||
|
// sorry we cannot free value
|
||
|
//
|
||
|
// This shouldn't happen as the value is marked ditry by
|
||
|
// this time (i.e. its view is pinned in memory)
|
||
|
//
|
||
|
ASSERT( FALSE );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,Cell);
|
||
|
|
||
|
if( CmpFreeValueData(Hive,Value->Data,Value->DataLength) == FALSE ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// free the cell itself
|
||
|
//
|
||
|
HvFreeCell(Hive, Cell);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
CmpSetValueDataNew(
|
||
|
IN PHHIVE Hive,
|
||
|
IN PVOID Data,
|
||
|
IN ULONG DataSize,
|
||
|
IN ULONG StorageType,
|
||
|
IN HCELL_INDEX ValueCell,
|
||
|
OUT PHCELL_INDEX DataCell
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Allocates a new cell (or big data cell) to accomodate DataSize;
|
||
|
Initialize and copy information from Data to the new cell;
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Hive - supplies a pointer to the hive control structure for the hive
|
||
|
|
||
|
Data - data buffer (possibly from user-mode)
|
||
|
|
||
|
DataSize - size of the buffer
|
||
|
|
||
|
StorageType - Stable or Volatile
|
||
|
|
||
|
ValueCell - The value setting the data for (locality purposes).
|
||
|
|
||
|
DataCell - return value:HCELL_INDEX of the new cell; HCELL_NIL on some error
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status of the operation (STATUS_SUCCESS or the exception code - if any)
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
Knows how to deal with big cell(s)
|
||
|
Data buffer comes from user mode, so it should be guarded by a try-except
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PCELL_DATA pdata;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
|
||
|
|
||
|
//
|
||
|
// bogus args; we don't deal with small values here!
|
||
|
//
|
||
|
ASSERT(DataSize > CM_KEY_VALUE_SMALL);
|
||
|
|
||
|
if( CmpIsHKeyValueBig(Hive,DataSize) == TRUE ) {
|
||
|
//
|
||
|
// request for a big data value
|
||
|
//
|
||
|
PCM_BIG_DATA BigData = NULL;
|
||
|
USHORT Count;
|
||
|
PHCELL_INDEX Plist = NULL;
|
||
|
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
|
||
|
//
|
||
|
// allocate the embedding cell
|
||
|
//
|
||
|
*DataCell = HvAllocateCell(Hive, sizeof(CM_BIG_DATA), StorageType,ValueCell);
|
||
|
if (*DataCell == HCELL_NIL) {
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// init the BIG_DATA cell
|
||
|
//
|
||
|
BigData = (PCM_BIG_DATA)HvGetCell(Hive,*DataCell);
|
||
|
if( BigData == NULL) {
|
||
|
//
|
||
|
// couldn't map view for this cell
|
||
|
// this shouldn't happen as we just allocated this cell
|
||
|
// (i.e. its view should be pinned in memory)
|
||
|
//
|
||
|
ASSERT( FALSE );
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,*DataCell);
|
||
|
|
||
|
BigData->Signature = CM_BIG_DATA_SIGNATURE;
|
||
|
BigData->Count = 0;
|
||
|
BigData->List = HCELL_NIL;
|
||
|
|
||
|
//
|
||
|
// Compute the number of cells needed
|
||
|
//
|
||
|
Count = (USHORT)((DataSize + CM_KEY_VALUE_BIG - 1) / CM_KEY_VALUE_BIG);
|
||
|
|
||
|
//
|
||
|
// allocate the embeded list
|
||
|
//
|
||
|
BigData->List = HvAllocateCell(Hive, Count * sizeof(HCELL_INDEX), StorageType,*DataCell);
|
||
|
if( BigData->List == HCELL_NIL ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
Plist = (PHCELL_INDEX)HvGetCell(Hive,BigData->List);
|
||
|
if( Plist == NULL ) {
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
//
|
||
|
//
|
||
|
// This shouldn't happen as this cell is marked ditry by
|
||
|
// this time (i.e. its view is pinned in memory)
|
||
|
//
|
||
|
ASSERT( FALSE );
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,BigData->List);
|
||
|
|
||
|
//
|
||
|
// allocate each chunk and copy the data; if we fail part through, we'll free the already allocated values
|
||
|
//
|
||
|
for( ;BigData->Count < Count;(BigData->Count)++) {
|
||
|
//
|
||
|
// allocate this chunk
|
||
|
//
|
||
|
Plist[BigData->Count] = HvAllocateCell(Hive, CM_KEY_VALUE_BIG, StorageType,BigData->List);
|
||
|
if( Plist[BigData->Count] == HCELL_NIL ) {
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
pdata = HvGetCell(Hive,Plist[BigData->Count]);
|
||
|
if( pdata == NULL ) {
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
//
|
||
|
//
|
||
|
// This shouldn't happen as this cell is marked ditry by
|
||
|
// this time (i.e. its view is pinned in memory)
|
||
|
//
|
||
|
ASSERT( FALSE );
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,Plist[BigData->Count]);
|
||
|
|
||
|
//
|
||
|
// now, copy this chunk data
|
||
|
//
|
||
|
try {
|
||
|
|
||
|
RtlCopyMemory(pdata, (PUCHAR)Data, (DataSize>CM_KEY_VALUE_BIG)?CM_KEY_VALUE_BIG:DataSize);
|
||
|
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"!!CmpSetValueDataNew: code:%08lx\n", GetExceptionCode()));
|
||
|
|
||
|
status = GetExceptionCode();
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// update the data pointer and the remaining size
|
||
|
//
|
||
|
((PUCHAR)Data) += CM_KEY_VALUE_BIG;
|
||
|
DataSize -= CM_KEY_VALUE_BIG;
|
||
|
|
||
|
}
|
||
|
|
||
|
ASSERT( Count == BigData->Count );
|
||
|
return STATUS_SUCCESS;
|
||
|
|
||
|
Cleanup:
|
||
|
//
|
||
|
// free what we already allocated
|
||
|
//
|
||
|
if( BigData != NULL) {
|
||
|
if( Plist != NULL ) {
|
||
|
for(;BigData->Count;BigData->Count--) {
|
||
|
if( Plist[BigData->Count] != HCELL_NIL ) {
|
||
|
HvFreeCell(Hive, Plist[BigData->Count]);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
ASSERT( BigData->Count == 0 );
|
||
|
}
|
||
|
|
||
|
if( BigData->List != HCELL_NIL ) {
|
||
|
HvFreeCell(Hive, BigData->List);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HvFreeCell(Hive, *DataCell);
|
||
|
*DataCell = HCELL_NIL;
|
||
|
return status;
|
||
|
} else {
|
||
|
//
|
||
|
// normal old'n plain value
|
||
|
//
|
||
|
*DataCell = HvAllocateCell(Hive, DataSize, StorageType,ValueCell);
|
||
|
if (*DataCell == HCELL_NIL) {
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
pdata = HvGetCell(Hive, *DataCell);
|
||
|
if( pdata == NULL ) {
|
||
|
//
|
||
|
// we couldn't map a view for the bin containing this cell
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// normally this shouldn't happen as we just allocated ValueCell
|
||
|
// i.e. the bin containing DataCell should be mapped in memory at this point.
|
||
|
//
|
||
|
ASSERT( FALSE );
|
||
|
if (*DataCell != HCELL_NIL) {
|
||
|
HvFreeCell(Hive, *DataCell);
|
||
|
*DataCell = HCELL_NIL;
|
||
|
}
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,*DataCell);
|
||
|
|
||
|
//
|
||
|
// copy the actual data, guarding the buffer as it may be a user-mode buffer
|
||
|
//
|
||
|
try {
|
||
|
|
||
|
RtlCopyMemory(pdata, Data, DataSize);
|
||
|
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"!!CmpSetValueDataNew: code:%08lx\n", GetExceptionCode()));
|
||
|
|
||
|
//
|
||
|
// We have bombed out loading user data, clean up and exit.
|
||
|
//
|
||
|
if (*DataCell != HCELL_NIL) {
|
||
|
HvFreeCell(Hive, *DataCell);
|
||
|
*DataCell = HCELL_NIL;
|
||
|
}
|
||
|
return GetExceptionCode();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
CmpSetValueDataExisting(
|
||
|
IN PHHIVE Hive,
|
||
|
IN PVOID Data,
|
||
|
IN ULONG DataSize,
|
||
|
IN ULONG StorageType,
|
||
|
IN HCELL_INDEX OldDataCell
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Grows an existing big data cell and copies the new data into it.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Hive - supplies a pointer to the hive control structure for the hive
|
||
|
|
||
|
Data - data buffer (possibly from user-mode)
|
||
|
|
||
|
DataSize - size of the buffer
|
||
|
|
||
|
StorageType - Stable or Volatile
|
||
|
|
||
|
OldDataCell - old big data cell
|
||
|
|
||
|
NewDataCell - return value:HCELL_INDEX of the new cell; HCELL_NIL on some error
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status of the operation (STATUS_SUCCESS or the exception code - if any)
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
Knows how to deal with big cell(s)
|
||
|
Data buffer is secured by the time this function is called
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PCELL_DATA pdata;
|
||
|
PCM_BIG_DATA BigData = NULL;
|
||
|
USHORT NewCount,i;
|
||
|
PHCELL_INDEX Plist = NULL;
|
||
|
HCELL_INDEX NewList;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
||
|
|
||
|
//
|
||
|
// bogus args; we deal only with big data cells!
|
||
|
//
|
||
|
ASSERT(DataSize > CM_KEY_VALUE_BIG );
|
||
|
|
||
|
|
||
|
BigData = (PCM_BIG_DATA)HvGetCell(Hive,OldDataCell);
|
||
|
if( BigData == NULL) {
|
||
|
//
|
||
|
// couldn't map view for this cell
|
||
|
// this shouldn't happen as we just marked it as dirty
|
||
|
// (i.e. its view should be pinned in memory)
|
||
|
//
|
||
|
ASSERT( FALSE );
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,OldDataCell);
|
||
|
|
||
|
ASSERT_BIG_DATA(BigData);
|
||
|
|
||
|
|
||
|
|
||
|
Plist = (PHCELL_INDEX)HvGetCell(Hive,BigData->List);
|
||
|
if( Plist == NULL ) {
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
// this shouldn't happen as we just marked it as dirty
|
||
|
// (i.e. its view should be pinned in memory)
|
||
|
//
|
||
|
ASSERT(FALSE);
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,BigData->List);
|
||
|
|
||
|
//
|
||
|
// what's the new size?
|
||
|
//
|
||
|
NewCount = (USHORT)((DataSize + CM_KEY_VALUE_BIG - 1) / CM_KEY_VALUE_BIG);
|
||
|
|
||
|
if( NewCount > BigData->Count ) {
|
||
|
//
|
||
|
// grow the list and allocate additional cells to it
|
||
|
//
|
||
|
NewList = HvReallocateCell(Hive,BigData->List,NewCount * sizeof(HCELL_INDEX));
|
||
|
if( NewList == HCELL_NIL ) {
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// we can now safely alter the list; if allocating the aditional cells below fails
|
||
|
// we'll end up with some wasted space, but we'll be safe
|
||
|
//
|
||
|
BigData->List = NewList;
|
||
|
|
||
|
//
|
||
|
// read the new list
|
||
|
//
|
||
|
Plist = (PHCELL_INDEX)HvGetCell(Hive,NewList);
|
||
|
if( Plist == NULL ) {
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
// this shouldn't happen as we just reallocated the cell
|
||
|
// (i.e. its view should be pinned in memory)
|
||
|
//
|
||
|
ASSERT(FALSE);
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,NewList);
|
||
|
|
||
|
for(i= BigData->Count;i<NewCount;i++) {
|
||
|
Plist[i] = HvAllocateCell(Hive, CM_KEY_VALUE_BIG, StorageType,NewList);
|
||
|
if( Plist[i] == HCELL_NIL ) {
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
}
|
||
|
} else if( NewCount < BigData->Count ) {
|
||
|
//
|
||
|
// shrink the list and free additional unneccessary cells
|
||
|
//
|
||
|
for(i=NewCount;i<BigData->Count;i++) {
|
||
|
//
|
||
|
// this CANNOT fail as the cell is already marked dirty (i.e. pinned in memory).
|
||
|
//
|
||
|
HvFreeCell(Hive,Plist[i]);
|
||
|
}
|
||
|
//
|
||
|
// this WON'T fail, 'cause it's a shrink
|
||
|
//
|
||
|
NewList = HvReallocateCell(Hive,BigData->List,NewCount * sizeof(HCELL_INDEX));
|
||
|
if( NewList == HCELL_NIL ) {
|
||
|
ASSERT( FALSE );
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// read the new list (in the current implementation we don't shrink cells,
|
||
|
// so this is not really needed - just to be consistent)
|
||
|
//
|
||
|
Plist = (PHCELL_INDEX)HvGetCell(Hive,NewList);
|
||
|
if( Plist == NULL ) {
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
// this shouldn't happen as we just reallocated the cell
|
||
|
// (i.e. its view should be pinned in memory)
|
||
|
//
|
||
|
ASSERT(FALSE);
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,NewList);
|
||
|
|
||
|
//
|
||
|
// we can now safely alter the list
|
||
|
//
|
||
|
BigData->List = NewList;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// if we came to this point, we have successfully grown the list and
|
||
|
// allocated the additional space; nothing should go wrong further
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// go on and fill in the data onto the (new) big data cell
|
||
|
//
|
||
|
for( i=0;i<NewCount;i++) {
|
||
|
pdata = HvGetCell(Hive,Plist[i]);
|
||
|
if( pdata == NULL ) {
|
||
|
//
|
||
|
// cannot map view containing the cell; bail out
|
||
|
//
|
||
|
//
|
||
|
// This shouldn't happen as this cell is marked dirty by
|
||
|
// this time - or is a new allocated cell
|
||
|
// (i.e. its view is pinned in memory)
|
||
|
//
|
||
|
ASSERT( FALSE );
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
// release the cell here as the reglock is held exclusive
|
||
|
HvReleaseCell(Hive,Plist[i]);
|
||
|
|
||
|
//
|
||
|
// now, copy this chunk data
|
||
|
//
|
||
|
RtlCopyMemory(pdata, (PUCHAR)Data, (DataSize>CM_KEY_VALUE_BIG)?CM_KEY_VALUE_BIG:DataSize);
|
||
|
|
||
|
//
|
||
|
// update the data pointer and the remaining size
|
||
|
//
|
||
|
Data = (PVOID)((PCHAR)Data + CM_KEY_VALUE_BIG);
|
||
|
DataSize -= CM_KEY_VALUE_BIG;
|
||
|
}
|
||
|
|
||
|
|
||
|
BigData->Count = NewCount;
|
||
|
return STATUS_SUCCESS;
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif //_CM_LDR_
|
||
|
|
||
|
|
||
|
|