1302 lines
31 KiB
C
1302 lines
31 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
keydata.c
|
|
|
|
Abstract:
|
|
|
|
Routines that manage data for the memdb key structures.
|
|
|
|
Author:
|
|
|
|
Matthew Vanderzee (mvander) 13-Aug-1999
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#include "memdbp.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// KeyStruct Data Functions
|
|
//
|
|
|
|
|
|
BOOL
|
|
KeyStructSetValue (
|
|
IN UINT KeyIndex,
|
|
IN UINT Value
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
sets the value for a key
|
|
|
|
Arguments:
|
|
|
|
KeyIndex - index of key
|
|
Value - value to put in key
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful
|
|
|
|
--*/
|
|
|
|
{
|
|
PKEYSTRUCT KeyStruct;
|
|
|
|
KeyStruct = GetKeyStruct(KeyIndex);
|
|
MYASSERT(KeyStruct);
|
|
|
|
KeyStruct->Value = Value;
|
|
|
|
KeyStruct->DataFlags |= DATAFLAG_VALUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
KeyStructSetFlags (
|
|
IN UINT KeyIndex,
|
|
IN BOOL ReplaceFlags,
|
|
IN UINT SetFlags,
|
|
IN UINT ClearFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
sets the flags for a key
|
|
|
|
Arguments:
|
|
|
|
KeyIndex - index of key
|
|
ReplaceFlags - Specifies if the existing flags are to be replaced. If TRUE then we only
|
|
consider SetFlags as the replacing flags, ClearFlags will be ignored
|
|
SetFlags - Specifies the bit flags that need to be set (if ReplaceFlags is FALSE) or the
|
|
replacement flags (if ReplaceFlags is TRUE).
|
|
ClearFlags - Specifies the bit flags that should be cleared (ignored if ReplaceFlags is TRUE).
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PKEYSTRUCT KeyStruct;
|
|
|
|
KeyStruct = GetKeyStruct(KeyIndex);
|
|
MYASSERT(KeyStruct);
|
|
|
|
if (KeyStruct->DataFlags & DATAFLAG_FLAGS) {
|
|
if (ReplaceFlags) {
|
|
KeyStruct->Flags = SetFlags;
|
|
} else {
|
|
KeyStruct->Flags &= ~ClearFlags;
|
|
KeyStruct->Flags |= SetFlags;
|
|
}
|
|
} else {
|
|
KeyStruct->Flags = SetFlags;
|
|
KeyStruct->DataFlags |= DATAFLAG_FLAGS;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// LINT - in the next function keystruct is thought to be possibly NULL.
|
|
// If we examine the code we'll see that this is not a possibility so...
|
|
//lint -save -e794
|
|
|
|
UINT g_TotalData = 0;
|
|
|
|
UINT
|
|
pAllocateNewDataStruct (
|
|
IN UINT DataSize,
|
|
IN UINT AltDataSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pAllocateNewDataStruct allocates a block of memory in the single
|
|
heap, for holding a data structure.
|
|
|
|
Arguments:
|
|
|
|
DataSize - Size of the binary data that needs to be stored here
|
|
|
|
Return Value:
|
|
|
|
An Index to the new structure.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT size;
|
|
PKEYSTRUCT keyStruct = NULL;
|
|
UINT offset;
|
|
UINT prevDel;
|
|
UINT result;
|
|
|
|
MYASSERT (g_CurrentDatabase);
|
|
|
|
size = DataSize + KEYSTRUCT_SIZE;
|
|
|
|
//
|
|
// Look for free block
|
|
//
|
|
prevDel = INVALID_OFFSET;
|
|
offset = g_CurrentDatabase->FirstKeyDeleted;
|
|
|
|
while (offset != INVALID_OFFSET) {
|
|
keyStruct = GetKeyStructFromOffset (offset);
|
|
MYASSERT (keyStruct);
|
|
if ((keyStruct->Size >= size) && (keyStruct->Size < (size + ALLOC_TOLERANCE))) {
|
|
break;
|
|
}
|
|
|
|
prevDel = offset;
|
|
offset = keyStruct->NextDeleted;
|
|
}
|
|
|
|
if (offset == INVALID_OFFSET) {
|
|
//
|
|
// We could not find one so we need to allocate a new block
|
|
//
|
|
g_TotalData ++;
|
|
|
|
offset = DatabaseAllocBlock (size + AltDataSize);
|
|
if (offset == INVALID_OFFSET) {
|
|
return INVALID_OFFSET;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
//
|
|
// if we are in debug mode, and we are using debug structs, set
|
|
// pointer normally and set Signature DWORD. if we are not using
|
|
// debug structs, then set pointer to 4 bytes below actual offset,
|
|
// so all members are shifted down.
|
|
//
|
|
if (g_UseDebugStructs) {
|
|
keyStruct = (PKEYSTRUCT)OFFSET_TO_PTR (offset);
|
|
keyStruct->Signature = KEYSTRUCT_SIGNATURE;
|
|
} else {
|
|
keyStruct = (PKEYSTRUCT)OFFSET_TO_PTR (offset - KEYSTRUCT_HEADER_SIZE);
|
|
}
|
|
#else
|
|
keyStruct = (PKEYSTRUCT)OFFSET_TO_PTR(offset);
|
|
#endif
|
|
|
|
keyStruct->Size = size + AltDataSize;
|
|
} else {
|
|
//
|
|
// Delink free block if recovering free space
|
|
//
|
|
if (prevDel != INVALID_OFFSET) {
|
|
GetKeyStructFromOffset (prevDel)->NextDeleted = keyStruct->NextDeleted;
|
|
} else {
|
|
g_CurrentDatabase->FirstKeyDeleted = keyStruct->NextDeleted;
|
|
}
|
|
#ifdef DEBUG
|
|
keyStruct->KeyFlags &= ~KSF_DELETED;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Init new block
|
|
//
|
|
keyStruct->DataSize = DataSize;
|
|
keyStruct->DataStructIndex = INVALID_OFFSET;
|
|
keyStruct->NextLevelTree = INVALID_OFFSET;
|
|
keyStruct->PrevLevelIndex = INVALID_OFFSET;
|
|
keyStruct->Flags = 0;
|
|
keyStruct->KeyFlags = KSF_DATABLOCK;
|
|
keyStruct->DataFlags = 0;
|
|
|
|
result = AddKeyOffsetToBuffer (offset);
|
|
|
|
return result;
|
|
}
|
|
//lint -restore
|
|
|
|
UINT
|
|
KeyStructAddBinaryData (
|
|
IN UINT KeyIndex,
|
|
IN BYTE Type,
|
|
IN BYTE Instance,
|
|
IN PCBYTE Data,
|
|
IN UINT DataSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
KeyStructAddBinaryData adds a certain type of binary data to a key
|
|
if it doesn't exist yet. If it does, the function fails.
|
|
|
|
Arguments:
|
|
|
|
KeyIndex - index of key
|
|
Type - type of data
|
|
Instance - instance of data
|
|
Data - pointer to the data
|
|
DataSize - size of data
|
|
|
|
Return Value:
|
|
|
|
A valid data handle if successfull, INVALID_OFFSET otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PKEYSTRUCT prevStruct,dataStruct,nextStruct,keyStruct;
|
|
UINT dataIndex, prevIndex;
|
|
BOOL found = FALSE;
|
|
|
|
keyStruct = GetKeyStruct (KeyIndex);
|
|
MYASSERT (keyStruct);
|
|
|
|
// check to see if the data is already there
|
|
dataIndex = keyStruct->DataStructIndex;
|
|
prevIndex = KeyIndex;
|
|
prevStruct = keyStruct;
|
|
|
|
while (dataIndex != INVALID_OFFSET) {
|
|
|
|
dataStruct = GetKeyStruct (dataIndex);
|
|
MYASSERT (dataStruct);
|
|
|
|
if (((dataStruct->DataFlags & DATAFLAG_BINARYMASK)== Type) &&
|
|
((dataStruct->DataFlags & DATAFLAG_INSTANCEMASK) == Instance)
|
|
) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
if (((dataStruct->DataFlags & DATAFLAG_BINARYMASK) > Type) ||
|
|
(((dataStruct->DataFlags & DATAFLAG_BINARYMASK) == Type) &&
|
|
((dataStruct->DataFlags & DATAFLAG_INSTANCEMASK) > Instance)
|
|
)
|
|
) {
|
|
break;
|
|
}
|
|
prevIndex = dataIndex;
|
|
prevStruct = dataStruct;
|
|
dataIndex = dataStruct->DataStructIndex;
|
|
}
|
|
|
|
if (found) {
|
|
return INVALID_OFFSET;
|
|
}
|
|
|
|
dataIndex = pAllocateNewDataStruct (DataSize, 0);
|
|
|
|
if (dataIndex == INVALID_OFFSET) {
|
|
return INVALID_OFFSET;
|
|
}
|
|
|
|
keyStruct = GetKeyStruct (KeyIndex);
|
|
MYASSERT (keyStruct);
|
|
prevStruct = GetKeyStruct (prevIndex);
|
|
MYASSERT (prevStruct);
|
|
|
|
dataStruct = GetKeyStruct (dataIndex);
|
|
MYASSERT (dataStruct);
|
|
|
|
keyStruct->DataFlags |= Type;
|
|
dataStruct->DataFlags |= Type;
|
|
dataStruct->DataFlags |= Instance;
|
|
CopyMemory (dataStruct->Data, Data, DataSize);
|
|
|
|
dataStruct->DataStructIndex = prevStruct->DataStructIndex;
|
|
dataStruct->PrevLevelIndex = prevIndex;
|
|
prevStruct->DataStructIndex = dataIndex;
|
|
|
|
if (dataStruct->DataStructIndex != INVALID_OFFSET) {
|
|
nextStruct = GetKeyStruct (dataStruct->DataStructIndex);
|
|
MYASSERT (nextStruct);
|
|
nextStruct->PrevLevelIndex = dataIndex;
|
|
}
|
|
|
|
return dataIndex;
|
|
}
|
|
|
|
// LINT - in the next function keystruct is thought to be possibly NULL.
|
|
// If we examine the code we'll see that this is not a possibility so...
|
|
//lint -save -e771
|
|
UINT
|
|
KeyStructGrowBinaryData (
|
|
IN UINT KeyIndex,
|
|
IN BYTE Type,
|
|
IN BYTE Instance,
|
|
IN PCBYTE Data,
|
|
IN UINT DataSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
KeyStructGrowBinaryData appends a certain type of binary data to a key
|
|
if it does exist. If it doesn't, the new data is added.
|
|
|
|
Arguments:
|
|
|
|
KeyIndex - index of key
|
|
Type - type of data
|
|
Instance - instance of data
|
|
Data - pointer to the data
|
|
DataSize - size of data
|
|
|
|
Return Value:
|
|
|
|
A valid data handle if successfull, INVALID_OFFSET otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PKEYSTRUCT prevStruct;
|
|
PKEYSTRUCT dataStruct;
|
|
PKEYSTRUCT keyStruct;
|
|
PKEYSTRUCT nextStruct;
|
|
PKEYSTRUCT newStruct;
|
|
UINT dataIndex;
|
|
UINT newIndex;
|
|
UINT prevIndex;
|
|
BOOL found = FALSE;
|
|
|
|
MYASSERT (g_CurrentDatabase);
|
|
|
|
keyStruct = GetKeyStruct (KeyIndex);
|
|
MYASSERT (keyStruct);
|
|
|
|
// check to see if the data is already there
|
|
dataIndex = keyStruct->DataStructIndex;
|
|
prevStruct = keyStruct;
|
|
prevIndex = KeyIndex;
|
|
|
|
while (dataIndex != INVALID_OFFSET) {
|
|
|
|
dataStruct = GetKeyStruct (dataIndex);
|
|
MYASSERT (dataStruct);
|
|
|
|
if (((dataStruct->DataFlags & DATAFLAG_BINARYMASK)== Type) &&
|
|
((dataStruct->DataFlags & DATAFLAG_INSTANCEMASK) == Instance)
|
|
) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
if (((dataStruct->DataFlags & DATAFLAG_BINARYMASK) > Type) ||
|
|
(((dataStruct->DataFlags & DATAFLAG_BINARYMASK) == Type) &&
|
|
((dataStruct->DataFlags & DATAFLAG_INSTANCEMASK) > Instance)
|
|
)
|
|
) {
|
|
break;
|
|
}
|
|
prevStruct = dataStruct;
|
|
prevIndex = dataIndex;
|
|
dataIndex = dataStruct->DataStructIndex;
|
|
}
|
|
|
|
if ((dataIndex == INVALID_OFFSET) || (!found)) {
|
|
return KeyStructAddBinaryData (KeyIndex, Type, Instance, Data, DataSize);
|
|
}
|
|
|
|
if (dataStruct->Size >= KEYSTRUCT_SIZE + DataSize + dataStruct->DataSize) {
|
|
|
|
CopyMemory (dataStruct->Data + dataStruct->DataSize, Data, DataSize);
|
|
dataStruct->DataSize += DataSize;
|
|
return dataIndex;
|
|
|
|
} else {
|
|
|
|
newIndex = pAllocateNewDataStruct (DataSize + dataStruct->DataSize, min (dataStruct->DataSize, 65536));
|
|
|
|
if (newIndex == INVALID_OFFSET) {
|
|
return INVALID_OFFSET;
|
|
}
|
|
|
|
// now we need to reget all keystructs used so far because the database
|
|
// might have moved
|
|
keyStruct = GetKeyStruct (KeyIndex);
|
|
MYASSERT (keyStruct);
|
|
dataStruct = GetKeyStruct (dataIndex);
|
|
MYASSERT (dataStruct);
|
|
prevStruct = GetKeyStruct (prevIndex);
|
|
MYASSERT (prevStruct);
|
|
|
|
newStruct = GetKeyStruct (newIndex);
|
|
MYASSERT (newStruct);
|
|
|
|
newStruct->DataSize = dataStruct->DataSize + DataSize;
|
|
newStruct->DataFlags = dataStruct->DataFlags;
|
|
newStruct->DataStructIndex = dataStruct->DataStructIndex;
|
|
newStruct->PrevLevelIndex = dataStruct->PrevLevelIndex;
|
|
CopyMemory (newStruct->Data, dataStruct->Data, dataStruct->DataSize);
|
|
CopyMemory (newStruct->Data + dataStruct->DataSize, Data, DataSize);
|
|
|
|
prevStruct->DataStructIndex = newIndex;
|
|
|
|
if (newStruct->DataStructIndex != INVALID_OFFSET) {
|
|
nextStruct = GetKeyStruct (newStruct->DataStructIndex);
|
|
MYASSERT (nextStruct);
|
|
nextStruct->PrevLevelIndex = newIndex;
|
|
}
|
|
|
|
// now simply remove the block
|
|
//
|
|
// Donate block to free space
|
|
//
|
|
|
|
dataStruct->NextDeleted = g_CurrentDatabase->FirstKeyDeleted;
|
|
g_CurrentDatabase->FirstKeyDeleted = KeyIndexToOffset (dataIndex);
|
|
#ifdef DEBUG
|
|
dataStruct->KeyFlags |= KSF_DELETED;
|
|
#endif
|
|
// let's empty the keystruct (for better compression)
|
|
ZeroMemory (dataStruct->Data, dataStruct->Size - KEYSTRUCT_SIZE);
|
|
|
|
RemoveKeyOffsetFromBuffer (dataIndex);
|
|
|
|
return newIndex;
|
|
}
|
|
}
|
|
//lint -restore
|
|
|
|
UINT
|
|
KeyStructGrowBinaryDataByIndex (
|
|
IN UINT OldIndex,
|
|
IN PCBYTE Data,
|
|
IN UINT DataSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
KeyStructGrowBinaryDataByIndex appends a certain type of binary data to
|
|
an existing structure identified by OldIndex. The old structure is
|
|
deleted and a new one is allocated holding both old and new data.
|
|
|
|
Arguments:
|
|
|
|
OldIndex - index of data
|
|
Data - pointer to the data
|
|
DataSize - size of data
|
|
|
|
Return Value:
|
|
|
|
A valid data index if successfull, INVALID_OFFSET otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT newIndex;
|
|
PKEYSTRUCT oldStruct, newStruct, prevStruct, nextStruct;
|
|
|
|
MYASSERT (g_CurrentDatabase);
|
|
|
|
oldStruct = GetKeyStruct (OldIndex);
|
|
MYASSERT (oldStruct);
|
|
|
|
if (oldStruct->Size >= KEYSTRUCT_SIZE + DataSize + oldStruct->DataSize) {
|
|
|
|
CopyMemory (oldStruct->Data + oldStruct->DataSize, Data, DataSize);
|
|
oldStruct->DataSize += DataSize;
|
|
return OldIndex;
|
|
|
|
} else {
|
|
|
|
newIndex = pAllocateNewDataStruct (DataSize + oldStruct->DataSize, min (oldStruct->DataSize, 65536));
|
|
|
|
if (newIndex == INVALID_OFFSET) {
|
|
return INVALID_OFFSET;
|
|
}
|
|
|
|
// now we need to reget all keystructs used so far because the database
|
|
// might have moved
|
|
oldStruct = GetKeyStruct (OldIndex);
|
|
MYASSERT (oldStruct);
|
|
|
|
newStruct = GetKeyStruct (newIndex);
|
|
MYASSERT (newStruct);
|
|
|
|
newStruct->DataStructIndex = oldStruct->DataStructIndex;
|
|
newStruct->PrevLevelIndex = oldStruct->PrevLevelIndex;
|
|
newStruct->DataFlags = oldStruct->DataFlags;
|
|
CopyMemory (newStruct->Data, oldStruct->Data, oldStruct->DataSize);
|
|
CopyMemory (newStruct->Data + oldStruct->DataSize, Data, DataSize);
|
|
|
|
prevStruct = GetKeyStruct (newStruct->PrevLevelIndex);
|
|
MYASSERT (prevStruct);
|
|
prevStruct->DataStructIndex = newIndex;
|
|
|
|
if (newStruct->DataStructIndex != INVALID_OFFSET) {
|
|
nextStruct = GetKeyStruct (newStruct->DataStructIndex);
|
|
MYASSERT (nextStruct);
|
|
nextStruct->PrevLevelIndex = newIndex;
|
|
}
|
|
|
|
// now simply remove the block
|
|
//
|
|
// Donate block to free space
|
|
//
|
|
|
|
oldStruct->NextDeleted = g_CurrentDatabase->FirstKeyDeleted;
|
|
g_CurrentDatabase->FirstKeyDeleted = KeyIndexToOffset (OldIndex);
|
|
#ifdef DEBUG
|
|
oldStruct->KeyFlags |= KSF_DELETED;
|
|
#endif
|
|
// let's empty the keystruct (for better compression)
|
|
ZeroMemory (oldStruct->Data, oldStruct->Size - KEYSTRUCT_SIZE);
|
|
|
|
RemoveKeyOffsetFromBuffer (OldIndex);
|
|
|
|
return newIndex;
|
|
}
|
|
}
|
|
|
|
// LINT - in the next function prevstruct is thought to be possibly not initialized.
|
|
// If we examine the code we'll see that this is not a possibility so...
|
|
//lint -save -e771
|
|
BOOL
|
|
KeyStructDeleteBinaryData (
|
|
IN UINT KeyIndex,
|
|
IN BYTE Type,
|
|
IN BYTE Instance
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
KeyStructDeleteBinaryData deletes a certain type of binary data from a key
|
|
if it exists. If it doesn't, the function will simply return success.
|
|
|
|
Arguments:
|
|
|
|
KeyIndex - index of key
|
|
Type - type of data
|
|
Instance - instance of data
|
|
|
|
Return Value:
|
|
|
|
TRUE if successfull, FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
PKEYSTRUCT prevStruct, nextStruct, dataStruct, keyStruct;
|
|
UINT dataIndex, prevIndex;
|
|
BOOL found = FALSE;
|
|
UINT typeInstances = 0;
|
|
|
|
MYASSERT (g_CurrentDatabase);
|
|
|
|
keyStruct = GetKeyStruct (KeyIndex);
|
|
MYASSERT (keyStruct);
|
|
|
|
if (!(keyStruct->DataFlags & Type)) {
|
|
// no such type of data, exiting
|
|
return TRUE;
|
|
}
|
|
|
|
// check to see if the data is already there
|
|
dataIndex = keyStruct->DataStructIndex;
|
|
prevIndex = KeyIndex;
|
|
prevStruct = keyStruct;
|
|
|
|
while (dataIndex != INVALID_OFFSET) {
|
|
|
|
dataStruct = GetKeyStruct (dataIndex);
|
|
MYASSERT (dataStruct);
|
|
|
|
if ((dataStruct->DataFlags & DATAFLAG_BINARYMASK) == Type) {
|
|
typeInstances ++;
|
|
if ((dataStruct->DataFlags & DATAFLAG_INSTANCEMASK) == Instance) {
|
|
found = TRUE;
|
|
//
|
|
// now let's see if we have more instances of this binary type
|
|
//
|
|
if (dataStruct->DataStructIndex != INVALID_OFFSET) {
|
|
nextStruct = GetKeyStruct (dataStruct->DataStructIndex);
|
|
if ((nextStruct->DataFlags & DATAFLAG_BINARYMASK) == Type) {
|
|
typeInstances ++;
|
|
}
|
|
}
|
|
break;
|
|
} else if ((dataStruct->DataFlags & DATAFLAG_INSTANCEMASK) > Instance) {
|
|
break;
|
|
}
|
|
} else if ((dataStruct->DataFlags & DATAFLAG_BINARYMASK) > Type) {
|
|
break;
|
|
}
|
|
prevIndex = dataIndex;
|
|
prevStruct = dataStruct;
|
|
dataIndex = dataStruct->DataStructIndex;
|
|
}
|
|
|
|
if ((dataIndex == INVALID_OFFSET) || (!found)) {
|
|
return TRUE;
|
|
}
|
|
|
|
// remove the linkage
|
|
prevStruct->DataStructIndex = dataStruct->DataStructIndex;
|
|
|
|
if (dataStruct->DataStructIndex != INVALID_OFFSET) {
|
|
nextStruct = GetKeyStruct (dataStruct->DataStructIndex);
|
|
MYASSERT (nextStruct);
|
|
nextStruct->PrevLevelIndex = prevIndex;
|
|
}
|
|
|
|
// now simply remove the block
|
|
//
|
|
// Donate block to free space
|
|
//
|
|
|
|
dataStruct->NextDeleted = g_CurrentDatabase->FirstKeyDeleted;
|
|
g_CurrentDatabase->FirstKeyDeleted = KeyIndexToOffset (dataIndex);
|
|
#ifdef DEBUG
|
|
dataStruct->KeyFlags |= KSF_DELETED;
|
|
#endif
|
|
// let's empty the keystruct (for better compression)
|
|
ZeroMemory (dataStruct->Data, dataStruct->Size - KEYSTRUCT_SIZE);
|
|
|
|
RemoveKeyOffsetFromBuffer (dataIndex);
|
|
|
|
//
|
|
// finally, fix the keystruct if this was the only instance of this type
|
|
//
|
|
MYASSERT (typeInstances >= 1);
|
|
if (typeInstances == 1) {
|
|
keyStruct->DataFlags &= ~Type;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
//lint -restore
|
|
|
|
BOOL
|
|
KeyStructDeleteBinaryDataByIndex (
|
|
IN UINT DataIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
KeyStructDeleteBinaryDataByIndex deletes a certain type of binary data from a key.
|
|
|
|
Arguments:
|
|
|
|
DataIndex - index of data
|
|
|
|
Return Value:
|
|
|
|
TRUE if successfull, FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
PKEYSTRUCT prevStruct, nextStruct, dataStruct, keyStruct;
|
|
BYTE type = 0;
|
|
UINT typeInstances = 0;
|
|
|
|
MYASSERT (g_CurrentDatabase);
|
|
|
|
dataStruct = GetKeyStruct (DataIndex);
|
|
MYASSERT (dataStruct);
|
|
type = dataStruct->DataFlags & DATAFLAG_BINARYMASK;
|
|
typeInstances ++;
|
|
|
|
prevStruct = GetKeyStruct (dataStruct->PrevLevelIndex);
|
|
MYASSERT (prevStruct);
|
|
if ((prevStruct->DataFlags & DATAFLAG_BINARYMASK) == type) {
|
|
typeInstances ++;
|
|
}
|
|
prevStruct->DataStructIndex = dataStruct->DataStructIndex;
|
|
|
|
if (dataStruct->DataStructIndex != INVALID_OFFSET) {
|
|
nextStruct = GetKeyStruct (dataStruct->DataStructIndex);
|
|
MYASSERT (nextStruct);
|
|
if ((nextStruct->DataFlags & DATAFLAG_BINARYMASK) == type) {
|
|
typeInstances ++;
|
|
}
|
|
nextStruct->PrevLevelIndex = dataStruct->PrevLevelIndex;
|
|
}
|
|
|
|
// now simply remove the block
|
|
//
|
|
// Donate block to free space
|
|
//
|
|
|
|
dataStruct->NextDeleted = g_CurrentDatabase->FirstKeyDeleted;
|
|
g_CurrentDatabase->FirstKeyDeleted = KeyIndexToOffset (DataIndex);
|
|
#ifdef DEBUG
|
|
dataStruct->KeyFlags |= KSF_DELETED;
|
|
#endif
|
|
// let's empty the keystruct (for better compression)
|
|
ZeroMemory (dataStruct->Data, dataStruct->Size - KEYSTRUCT_SIZE);
|
|
|
|
RemoveKeyOffsetFromBuffer (DataIndex);
|
|
|
|
//
|
|
// finally, fix the keystruct if this was the only instance of this type
|
|
//
|
|
MYASSERT (typeInstances >= 1);
|
|
if (typeInstances == 1) {
|
|
// first we need to find the key starting with the current database struct
|
|
keyStruct = dataStruct;
|
|
while (keyStruct->KeyFlags & KSF_DATABLOCK) {
|
|
// still a datablock
|
|
if (keyStruct->PrevLevelIndex == INVALID_OFFSET) {
|
|
// something is wrong, the first level is a datablock??
|
|
break;
|
|
}
|
|
keyStruct = GetKeyStruct (keyStruct->PrevLevelIndex);
|
|
MYASSERT (keyStruct);
|
|
}
|
|
if (!(keyStruct->KeyFlags & KSF_DATABLOCK)) {
|
|
keyStruct->DataFlags &= ~type;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
UINT
|
|
KeyStructReplaceBinaryDataByIndex (
|
|
IN UINT OldIndex,
|
|
IN PCBYTE Data,
|
|
IN UINT DataSize
|
|
)
|
|
{
|
|
UINT newIndex;
|
|
PKEYSTRUCT oldStruct, newStruct, prevStruct, nextStruct;
|
|
|
|
MYASSERT (g_CurrentDatabase);
|
|
|
|
// NTRAID#NTBUG9-153308-2000/08/01-jimschm Optimize this by keeping the current structure is big enough.
|
|
|
|
newIndex = pAllocateNewDataStruct (DataSize, 0);
|
|
|
|
if (newIndex == INVALID_OFFSET) {
|
|
return INVALID_OFFSET;
|
|
}
|
|
|
|
oldStruct = GetKeyStruct (OldIndex);
|
|
MYASSERT (oldStruct);
|
|
|
|
newStruct = GetKeyStruct (newIndex);
|
|
MYASSERT (newStruct);
|
|
|
|
newStruct->DataStructIndex = oldStruct->DataStructIndex;
|
|
newStruct->PrevLevelIndex = oldStruct->PrevLevelIndex;
|
|
newStruct->DataFlags = oldStruct->DataFlags;
|
|
CopyMemory (newStruct->Data, Data, DataSize);
|
|
|
|
prevStruct = GetKeyStruct (newStruct->PrevLevelIndex);
|
|
MYASSERT (prevStruct);
|
|
prevStruct->DataStructIndex = newIndex;
|
|
|
|
if (newStruct->DataStructIndex != INVALID_OFFSET) {
|
|
nextStruct = GetKeyStruct (newStruct->DataStructIndex);
|
|
MYASSERT (nextStruct);
|
|
nextStruct->PrevLevelIndex = newIndex;
|
|
}
|
|
|
|
// now simply remove the block
|
|
//
|
|
// Donate block to free space
|
|
//
|
|
|
|
oldStruct->NextDeleted = g_CurrentDatabase->FirstKeyDeleted;
|
|
g_CurrentDatabase->FirstKeyDeleted = KeyIndexToOffset (OldIndex);
|
|
#ifdef DEBUG
|
|
oldStruct->KeyFlags |= KSF_DELETED;
|
|
#endif
|
|
// let's empty the keystruct (for better compression)
|
|
ZeroMemory (oldStruct->Data, oldStruct->Size - KEYSTRUCT_SIZE);
|
|
|
|
RemoveKeyOffsetFromBuffer (OldIndex);
|
|
|
|
return newIndex;
|
|
}
|
|
|
|
// LINT - in the next function prevstruct is thought to be possibly not initialized.
|
|
// If we examine the code we'll see that this is not a possibility so...
|
|
//lint -save -e771
|
|
PBYTE
|
|
KeyStructGetBinaryData (
|
|
IN UINT KeyIndex,
|
|
IN BYTE Type,
|
|
IN BYTE Instance,
|
|
OUT PUINT DataSize,
|
|
OUT PUINT DataIndex //OPTIONAL
|
|
)
|
|
{
|
|
PKEYSTRUCT dataStruct,keyStruct;
|
|
UINT dataIndex;
|
|
BOOL found = FALSE;
|
|
|
|
keyStruct = GetKeyStruct (KeyIndex);
|
|
MYASSERT (keyStruct);
|
|
|
|
if (!(keyStruct->DataFlags & Type)) {
|
|
return NULL;
|
|
}
|
|
|
|
// check to see if the data is already there
|
|
dataIndex = keyStruct->DataStructIndex;
|
|
|
|
while (dataIndex != INVALID_OFFSET) {
|
|
|
|
dataStruct = GetKeyStruct (dataIndex);
|
|
MYASSERT (dataStruct);
|
|
|
|
if (((dataStruct->DataFlags & DATAFLAG_BINARYMASK)== Type) &&
|
|
((dataStruct->DataFlags & DATAFLAG_INSTANCEMASK) == Instance)
|
|
) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
if (((dataStruct->DataFlags & DATAFLAG_BINARYMASK) > Type) ||
|
|
(((dataStruct->DataFlags & DATAFLAG_BINARYMASK) == Type) &&
|
|
((dataStruct->DataFlags & DATAFLAG_INSTANCEMASK) > Instance)
|
|
)
|
|
) {
|
|
break;
|
|
}
|
|
dataIndex = dataStruct->DataStructIndex;
|
|
}
|
|
|
|
if ((dataIndex == INVALID_OFFSET) || (!found)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (DataSize) {
|
|
*DataSize = dataStruct->DataSize;
|
|
}
|
|
|
|
if (DataIndex) {
|
|
*DataIndex = dataIndex;
|
|
}
|
|
|
|
return dataStruct->Data;
|
|
}
|
|
//lint -restore
|
|
|
|
PBYTE
|
|
KeyStructGetBinaryDataByIndex (
|
|
IN UINT DataIndex,
|
|
OUT PUINT DataSize
|
|
)
|
|
{
|
|
PKEYSTRUCT dataStruct;
|
|
|
|
dataStruct = GetKeyStruct (DataIndex);
|
|
MYASSERT (dataStruct);
|
|
|
|
if (DataSize) {
|
|
*DataSize = dataStruct->DataSize;
|
|
}
|
|
|
|
return dataStruct->Data;
|
|
}
|
|
|
|
UINT
|
|
KeyStructGetDataIndex (
|
|
IN UINT KeyIndex,
|
|
IN BYTE Type,
|
|
IN BYTE Instance
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
KeyStructGetDataIndex looks for a certain type of data and returns it's index
|
|
if it exists. If it doesn't, the function will simply return INVALID_OFFSET.
|
|
|
|
Arguments:
|
|
|
|
KeyIndex - index of key
|
|
Type - type of data
|
|
Instance - instance of data
|
|
|
|
Return Value:
|
|
|
|
A data index if successfull, INVALID_OFFSET if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
PKEYSTRUCT keyStruct, dataStruct;
|
|
UINT dataIndex;
|
|
BOOL found = FALSE;
|
|
|
|
keyStruct = GetKeyStruct (KeyIndex);
|
|
MYASSERT (keyStruct);
|
|
|
|
if (!(keyStruct->DataFlags & Type)) {
|
|
return INVALID_OFFSET;
|
|
}
|
|
|
|
// check to see if we have the data there
|
|
dataIndex = keyStruct->DataStructIndex;
|
|
|
|
while (dataIndex != INVALID_OFFSET) {
|
|
|
|
dataStruct = GetKeyStruct (dataIndex);
|
|
MYASSERT (dataStruct);
|
|
|
|
if (((dataStruct->DataFlags & DATAFLAG_BINARYMASK)== Type) &&
|
|
((dataStruct->DataFlags & DATAFLAG_INSTANCEMASK) == Instance)
|
|
) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
if (((dataStruct->DataFlags & DATAFLAG_BINARYMASK) > Type) ||
|
|
(((dataStruct->DataFlags & DATAFLAG_BINARYMASK) == Type) &&
|
|
((dataStruct->DataFlags & DATAFLAG_INSTANCEMASK) > Instance)
|
|
)
|
|
) {
|
|
break;
|
|
}
|
|
dataIndex = dataStruct->DataStructIndex;
|
|
}
|
|
if (!found) {
|
|
return INVALID_OFFSET;
|
|
}
|
|
return dataIndex;
|
|
}
|
|
|
|
DATAHANDLE
|
|
KeyStructAddLinkage (
|
|
IN UINT KeyIndex,
|
|
IN BYTE Type,
|
|
IN BYTE Instance,
|
|
IN UINT Linkage,
|
|
IN BOOL AllowDuplicates
|
|
)
|
|
{
|
|
BOOL toBeAdded = TRUE;
|
|
UINT result = INVALID_OFFSET;
|
|
PUINT linkArray;
|
|
UINT linkSize;
|
|
|
|
if (!AllowDuplicates) {
|
|
//
|
|
// check to see if we already have this linkage added
|
|
//
|
|
linkArray = (PUINT)KeyStructGetBinaryData (KeyIndex, Type, Instance, &linkSize, &result);
|
|
|
|
if (linkArray) {
|
|
|
|
while (linkSize >= SIZEOF (UINT)) {
|
|
|
|
if (*linkArray == Linkage) {
|
|
toBeAdded = FALSE;
|
|
break;
|
|
}
|
|
|
|
linkArray ++;
|
|
linkSize -= SIZEOF (UINT);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (toBeAdded) {
|
|
if (result != INVALID_OFFSET) {
|
|
result = KeyStructGrowBinaryDataByIndex (result, (PBYTE)(&Linkage), SIZEOF (UINT));
|
|
} else {
|
|
result = KeyStructGrowBinaryData (KeyIndex, Type, Instance, (PBYTE)(&Linkage), SIZEOF (UINT));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
DATAHANDLE
|
|
KeyStructAddLinkageByIndex (
|
|
IN UINT DataIndex,
|
|
IN UINT Linkage,
|
|
IN BOOL AllowDuplicates
|
|
)
|
|
{
|
|
BOOL toBeAdded = TRUE;
|
|
UINT result = INVALID_OFFSET;
|
|
PUINT linkArray;
|
|
UINT linkSize;
|
|
|
|
if (!AllowDuplicates) {
|
|
//
|
|
// check to see if we already have this linkage added
|
|
//
|
|
linkArray = (PUINT)KeyStructGetBinaryDataByIndex (DataIndex, &linkSize);
|
|
|
|
if (linkArray) {
|
|
|
|
while (linkSize >= SIZEOF (UINT)) {
|
|
|
|
if (*linkArray == Linkage) {
|
|
toBeAdded = FALSE;
|
|
break;
|
|
}
|
|
|
|
linkArray ++;
|
|
linkSize -= SIZEOF (UINT);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (toBeAdded) {
|
|
result = KeyStructGrowBinaryDataByIndex (DataIndex, (PBYTE)(&Linkage), SIZEOF (UINT));
|
|
} else {
|
|
result = DataIndex;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
KeyStructDeleteLinkage (
|
|
IN UINT KeyIndex,
|
|
IN BYTE Type,
|
|
IN BYTE Instance,
|
|
IN UINT Linkage,
|
|
IN BOOL FirstOnly
|
|
)
|
|
{
|
|
BOOL checking = TRUE;
|
|
BOOL result = FALSE;
|
|
PUINT srcArray, destArray, newArray;
|
|
UINT srcSize, newSize;
|
|
UINT dataIndex;
|
|
|
|
srcArray = (PUINT)KeyStructGetBinaryData (KeyIndex, Type, Instance, &srcSize, &dataIndex);
|
|
|
|
if (srcArray) {
|
|
newArray = MemDbGetMemory (srcSize);
|
|
|
|
if (newArray) {
|
|
|
|
destArray = newArray;
|
|
newSize = 0;
|
|
|
|
while (srcSize >= SIZEOF (UINT)) {
|
|
if ((*srcArray == Linkage) &&
|
|
(checking)
|
|
) {
|
|
if (FirstOnly) {
|
|
checking = FALSE;
|
|
}
|
|
} else {
|
|
*destArray = *srcArray;
|
|
newSize += SIZEOF (UINT);
|
|
destArray ++;
|
|
}
|
|
srcArray ++;
|
|
srcSize -= SIZEOF (UINT);
|
|
}
|
|
|
|
if (newSize) {
|
|
result = (KeyStructReplaceBinaryDataByIndex (dataIndex, (PBYTE)newArray, newSize) != INVALID_OFFSET);
|
|
} else {
|
|
result = KeyStructDeleteBinaryDataByIndex (dataIndex);
|
|
}
|
|
|
|
MemDbReleaseMemory (newArray);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
KeyStructDeleteLinkageByIndex (
|
|
IN UINT DataIndex,
|
|
IN UINT Linkage,
|
|
IN BOOL FirstOnly
|
|
)
|
|
{
|
|
BOOL checking = TRUE;
|
|
BOOL result = FALSE;
|
|
PUINT srcArray, destArray, newArray;
|
|
UINT srcSize, newSize;
|
|
|
|
srcArray = (PUINT)KeyStructGetBinaryDataByIndex (DataIndex, &srcSize);
|
|
|
|
if (srcArray) {
|
|
newArray = MemDbGetMemory (srcSize);
|
|
|
|
if (newArray) {
|
|
|
|
destArray = newArray;
|
|
newSize = 0;
|
|
|
|
while (srcSize >= SIZEOF (UINT)) {
|
|
if ((*srcArray == Linkage) &&
|
|
(checking)
|
|
) {
|
|
if (FirstOnly) {
|
|
checking = FALSE;
|
|
}
|
|
} else {
|
|
*destArray = *srcArray;
|
|
newSize += SIZEOF (UINT);
|
|
destArray ++;
|
|
}
|
|
srcArray ++;
|
|
srcSize -= SIZEOF (UINT);
|
|
}
|
|
|
|
if (newSize) {
|
|
result = (KeyStructReplaceBinaryDataByIndex (DataIndex, (PBYTE)newArray, newSize) != INVALID_OFFSET);
|
|
} else {
|
|
result = KeyStructDeleteBinaryDataByIndex (DataIndex);
|
|
}
|
|
|
|
MemDbReleaseMemory (newArray);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
KeyStructTestLinkage (
|
|
IN UINT KeyIndex,
|
|
IN BYTE Type,
|
|
IN BYTE Instance,
|
|
IN KEYHANDLE Linkage
|
|
)
|
|
{
|
|
BOOL result = FALSE;
|
|
PUINT srcArray;
|
|
UINT srcSize = 0;
|
|
|
|
srcArray = (PUINT)KeyStructGetBinaryData (KeyIndex, Type, Instance, &srcSize, NULL);
|
|
|
|
while (srcSize >= SIZEOF (KEYHANDLE)) {
|
|
if (*srcArray == Linkage) {
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
srcSize -= SIZEOF (KEYHANDLE);
|
|
srcArray++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
KeyStructTestLinkageByIndex (
|
|
IN UINT DataIndex,
|
|
IN UINT Linkage
|
|
)
|
|
{
|
|
BOOL result = FALSE;
|
|
PUINT srcArray;
|
|
UINT srcSize;
|
|
|
|
srcArray = (PUINT)KeyStructGetBinaryDataByIndex (DataIndex, &srcSize);
|
|
|
|
while (srcSize >= SIZEOF (UINT)) {
|
|
if (*srcArray == Linkage) {
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
srcSize -= SIZEOF (UINT);
|
|
srcArray++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
KeyStructGetValue (
|
|
IN PKEYSTRUCT KeyStruct,
|
|
OUT PUINT Value
|
|
)
|
|
{
|
|
if (!Value) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (!(KeyStruct->DataFlags & DATAFLAG_VALUE)) {
|
|
//
|
|
// there is no value, but we still set output to
|
|
// zero and return TRUE
|
|
//
|
|
*Value = 0;
|
|
return TRUE;
|
|
}
|
|
*Value = KeyStruct->Value;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
KeyStructGetFlags (
|
|
IN PKEYSTRUCT KeyStruct,
|
|
OUT PUINT Flags
|
|
)
|
|
{
|
|
if (!Flags) {
|
|
return TRUE;
|
|
}
|
|
if (!(KeyStruct->DataFlags & DATAFLAG_FLAGS)) {
|
|
//
|
|
// there are no flags, but we still set output to
|
|
// zero and return TRUE
|
|
//
|
|
*Flags = 0;
|
|
return TRUE;
|
|
}
|
|
*Flags = KeyStruct->Flags;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
KeyStructFreeAllData (
|
|
PKEYSTRUCT KeyStruct
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
KeyStructFreeDataBlock frees a data block and resets the
|
|
the KSF data flags, if the key struct has a data block allocated.
|
|
|
|
--*/
|
|
|
|
{
|
|
// NTRAID#NTBUG9-153308-2000/08/01-jimschm Reimplement free routine
|
|
//KeyStructFreeData (KeyStruct);
|
|
KeyStruct->Value = 0;
|
|
KeyStruct->Flags = 0;
|
|
KeyStruct->DataFlags &= ~DATAFLAG_VALUE;
|
|
KeyStruct->DataFlags &= ~DATAFLAG_FLAGS;
|
|
}
|
|
|
|
|
|
|