mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
330 lines
7.8 KiB
330 lines
7.8 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
offsetbuf.c
|
|
|
|
Abstract:
|
|
|
|
Routines that manage the keystruct offsetbuffer
|
|
|
|
Author:
|
|
|
|
Matthew Vanderzee (mvander) 13-Aug-1999
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#include "memdbp.h"
|
|
|
|
|
|
|
|
//
|
|
// we store index flags in the top two bits of the UINT offsets in
|
|
// the buffer, because offsets never have a top two bits set
|
|
//
|
|
// if the user links a key, we want to mark that index, so we
|
|
// dont add it to the deleted index list. if a key is linked,
|
|
// and then deleted, we want to keep that key's index pointing
|
|
// to INVALID_OFFSET, instead of reusing the index.
|
|
//
|
|
// if a key is moved, we replace the key's original offset with
|
|
// the index of the new key's offset. then we flag that the
|
|
// offset has been redirected.
|
|
//
|
|
// if an index is marked or redirected, when that key is deleted,
|
|
// we just set the true index (the index that any redirected indices
|
|
// point to) to INVALID_OFFSET.
|
|
//
|
|
|
|
#define INDEX_FLAG_BITS 2
|
|
#define INDEX_MOVE_BITS_TO_POS(bits) (((UINT)(bits)) << (8*sizeof(UINT)-INDEX_FLAG_BITS))
|
|
#define INDEX_MARKED_FLAG INDEX_MOVE_BITS_TO_POS(0x01)
|
|
#define INDEX_REDIRECTED_FLAG INDEX_MOVE_BITS_TO_POS(0x02)
|
|
#define INDEX_FLAG_MASK INDEX_MOVE_BITS_TO_POS(0x03)
|
|
|
|
#define GET_UINT_AT_INDEX(index) (*(PUINT)(g_CurrentDatabase->OffsetBuffer.Buf + (index)))
|
|
#define SET_UINT_AT_INDEX(index, offset) ((*(PUINT)(g_CurrentDatabase->OffsetBuffer.Buf + (index)))=(offset))
|
|
|
|
#define MARK_INDEX(Index) (GET_UINT_AT_INDEX(Index) |= INDEX_MARKED_FLAG)
|
|
#define IS_INDEX_MARKED(Index) ((BOOL)(GET_UINT_AT_INDEX(Index) & INDEX_FLAG_MASK))
|
|
|
|
|
|
VOID
|
|
MarkIndexList (
|
|
IN PUINT IndexList,
|
|
IN UINT IndexListSize
|
|
)
|
|
{
|
|
BYTE CurrentDatabase;
|
|
UINT i;
|
|
|
|
CurrentDatabase = g_CurrentDatabaseIndex;
|
|
|
|
//
|
|
// iterate through whole list, switch to correct
|
|
// database, and mark list as linked.
|
|
//
|
|
for (i = 0; i < IndexListSize; i++) {
|
|
SelectDatabase (GET_DATABASE (IndexList[i]));
|
|
MARK_INDEX (GET_INDEX (IndexList[i]));
|
|
#ifdef _DEBUG
|
|
if (GET_UINT_AT_INDEX (GET_INDEX (IndexList[i])) != INVALID_OFFSET) {
|
|
MYASSERT (GetKeyStruct (GET_INDEX (IndexList[i])));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
SelectDatabase (CurrentDatabase);
|
|
}
|
|
|
|
VOID
|
|
RedirectKeyIndex (
|
|
IN UINT Index,
|
|
IN UINT TargetIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
sets the offset at Index to TargetIndex, with INDEX_REDIRECTED_FLAG
|
|
set in the top byte. also, we mark TargetIndex, indicating it has
|
|
something redirected to it.
|
|
|
|
--*/
|
|
{
|
|
MYASSERT(!(Index & INDEX_FLAG_MASK));
|
|
MYASSERT(!(TargetIndex & INDEX_FLAG_MASK));
|
|
MYASSERT(!(GET_UINT_AT_INDEX(Index) & INDEX_REDIRECTED_FLAG));
|
|
MYASSERT(!(GET_UINT_AT_INDEX(TargetIndex) & INDEX_REDIRECTED_FLAG));
|
|
SET_UINT_AT_INDEX(Index, TargetIndex | INDEX_REDIRECTED_FLAG);
|
|
MARK_INDEX(TargetIndex);
|
|
}
|
|
|
|
UINT
|
|
pGetTrueIndex (
|
|
IN UINT Index
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
takes and index and returns the true index, which is the index that
|
|
actually holds the offset of the keystruct. indexes with the
|
|
redirected flag hold the index they are redirected to.
|
|
|
|
--*/
|
|
{
|
|
MYASSERT(!(Index & INDEX_FLAG_MASK));
|
|
while (GET_UINT_AT_INDEX(Index) & INDEX_REDIRECTED_FLAG) {
|
|
Index = GET_UINT_AT_INDEX(Index) & ~INDEX_FLAG_MASK;
|
|
}
|
|
return Index;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UINT
|
|
KeyIndexToOffset (
|
|
IN UINT Index
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
KeyIndexToOffset converts an index of a Keystruct
|
|
(in g_CurrentDatabase->OffsetBuffer) to the Keystruct's offset in the database.
|
|
|
|
Arguments:
|
|
Index - index in OffsetBuffer. must be valid
|
|
|
|
Return Value:
|
|
Offset of Keystruct.
|
|
|
|
--*/
|
|
{
|
|
MYASSERT(!(Index & INDEX_FLAG_MASK));
|
|
MYASSERT (Index <= g_CurrentDatabase->OffsetBuffer.End-sizeof(UINT));
|
|
MYASSERT (g_CurrentDatabase);
|
|
|
|
if (!g_CurrentDatabase->OffsetBuffer.Buf) {
|
|
return INVALID_OFFSET;
|
|
}
|
|
|
|
do {
|
|
Index = GET_UINT_AT_INDEX(Index);
|
|
if (Index == INVALID_OFFSET) {
|
|
return INVALID_OFFSET;
|
|
}
|
|
if (!(Index & INDEX_REDIRECTED_FLAG)) {
|
|
//
|
|
// we have found a non-redirected index, so check
|
|
// that this points to a real keystruct, and return it.
|
|
//
|
|
MYASSERT(GetKeyStructFromOffset(Index & ~INDEX_FLAG_MASK));
|
|
return Index & ~INDEX_FLAG_MASK;
|
|
}
|
|
Index &= ~INDEX_FLAG_MASK;
|
|
MYASSERT (Index <= g_CurrentDatabase->OffsetBuffer.End-sizeof(UINT));
|
|
} while (TRUE); //lint !e506
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UINT
|
|
AddKeyOffsetToBuffer (
|
|
IN UINT Offset
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
gets a space in g_CurrentDatabase->OffsetBuffer and sets it to Offset
|
|
|
|
Arguments:
|
|
Offset - value to put in buffer space
|
|
|
|
Return Value:
|
|
Index of space in g_CurrentDatabase->OffsetBuffer
|
|
|
|
--*/
|
|
{
|
|
PUINT Ptr;
|
|
|
|
MYASSERT (g_CurrentDatabase);
|
|
|
|
if (Offset & INDEX_FLAG_MASK) {
|
|
DEBUGMSG ((DBG_ERROR, "Offset to be put in list is too big, 0x%08lX", Offset));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// this will check that Offset is valid and points to Keystruct
|
|
//
|
|
MYASSERT(GetKeyStructFromOffset(Offset));
|
|
|
|
if (g_CurrentDatabase->OffsetBufferFirstDeletedIndex != INVALID_OFFSET)
|
|
{
|
|
//
|
|
// if we have deleted offsets from offset list, we
|
|
// find an open index, the first of which is stored
|
|
// in g_CurrentDatabase->OffsetBufferFirstDeletedIndex. the value at
|
|
// this index in the buffer is the next open index,
|
|
// and the value at that index is the next one, etc.
|
|
//
|
|
Ptr = &GET_UINT_AT_INDEX(g_CurrentDatabase->OffsetBufferFirstDeletedIndex);
|
|
g_CurrentDatabase->OffsetBufferFirstDeletedIndex = *Ptr;
|
|
} else {
|
|
//
|
|
// otherwise, make g_CurrentDatabase->OffsetBuffer bigger to hold new offset.
|
|
//
|
|
Ptr = (PUINT) GbGrow (&g_CurrentDatabase->OffsetBuffer, sizeof(UINT));
|
|
}
|
|
|
|
*Ptr = Offset;
|
|
|
|
return (UINT)((UBINT)Ptr - (UBINT)g_CurrentDatabase->OffsetBuffer.Buf);
|
|
}
|
|
|
|
|
|
VOID
|
|
RemoveKeyOffsetFromBuffer(
|
|
IN UINT Index
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
frees a space in g_CurrentDatabase->OffsetBuffer (adds to deleted index list)
|
|
|
|
Arguments:
|
|
Index - position of space to free
|
|
|
|
--*/
|
|
{
|
|
if (Index == INVALID_OFFSET) {
|
|
return;
|
|
}
|
|
|
|
MYASSERT (g_CurrentDatabase);
|
|
|
|
if (IS_INDEX_MARKED(Index)) {
|
|
//
|
|
// if index is marked, either it is redirected or something
|
|
// is linked to this index. either way, we do not want to
|
|
// reuse the index, so just set true index (not a redirected
|
|
// one) to INVALID_OFFSET.
|
|
//
|
|
SET_UINT_AT_INDEX(pGetTrueIndex(Index), INVALID_OFFSET);
|
|
} else {
|
|
//
|
|
// index not marked, so we can reuse this index by
|
|
// putting it in the deleted index list.
|
|
//
|
|
SET_UINT_AT_INDEX(Index, g_CurrentDatabase->OffsetBufferFirstDeletedIndex);
|
|
g_CurrentDatabase->OffsetBufferFirstDeletedIndex = Index;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
WriteOffsetBlock (
|
|
IN PGROWBUFFER pOffsetBuffer,
|
|
IN OUT PBYTE *Buf
|
|
)
|
|
{
|
|
MYASSERT(pOffsetBuffer);
|
|
|
|
*(((PUINT)*Buf)++) = pOffsetBuffer->End;
|
|
CopyMemory (*Buf, pOffsetBuffer->Buf, pOffsetBuffer->End);
|
|
|
|
*Buf += pOffsetBuffer->End;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ReadOffsetBlock (
|
|
OUT PGROWBUFFER pOffsetBuffer,
|
|
IN OUT PBYTE *Buf
|
|
)
|
|
{
|
|
UINT OffsetBufferSize;
|
|
|
|
MYASSERT(pOffsetBuffer);
|
|
|
|
ZeroMemory (pOffsetBuffer, sizeof (GROWBUFFER));
|
|
|
|
OffsetBufferSize = *(((PUINT)*Buf)++);
|
|
|
|
if (OffsetBufferSize > 0) {
|
|
if (!GbGrow(pOffsetBuffer, OffsetBufferSize)) {
|
|
return FALSE;
|
|
}
|
|
CopyMemory (pOffsetBuffer->Buf, *Buf, OffsetBufferSize);
|
|
*Buf += OffsetBufferSize;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
UINT GetOffsetBufferBlockSize (
|
|
IN PGROWBUFFER pOffsetBuffer
|
|
)
|
|
{
|
|
return sizeof (UINT) + pOffsetBuffer->End;
|
|
}
|
|
|
|
|