Files
mars-flaim/flaim/src/fsconvrt.cpp
ahodgkinson 7de8b6be39 Ported FLAIM to FTK.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@509 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-06-05 22:59:36 +00:00

366 lines
9.9 KiB
C++

//-------------------------------------------------------------------------
// Desc: Database format conversion routines.
// Tabs: 3
//
// Copyright (c) 1999-2001,2003-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: fsconvrt.cpp 12320 2006-01-19 15:53:51 -0700 (Thu, 19 Jan 2006) dsanders $
//-------------------------------------------------------------------------
#include "flaimsys.h"
FSTATIC RCODE FSConvertNonLeafTree(
FDB * pDb,
LFILE * pLFile,
BTSK * pOldStack,
BTSK * pOldStackBase,
FLMUINT uiNewVersion,
STATUS_HOOK fnStatusCallback,
void * UserData,
DB_UPGRADE_INFO * pDbConvertInfo);
FSTATIC void FSBuildNonLeafDataElement(
BTSK * pStack,
FLMBYTE * pElement,
FLMUINT * puiElmLen,
FLMUINT uiNewElmOvhd,
FLMBYTE ** ppKey);
/***************************************************************************
Desc: File system conversions from one version to another.
*****************************************************************************/
RCODE FSVersionConversion40(
FDB * pDb,
FLMUINT uiNewVersion,
STATUS_HOOK fnStatusCallback,
void * UserData)
{
RCODE rc = FERR_OK;
FFILE * pFile = pDb->pFile;
LFILE * pLFileTbl;
FLMUINT uiPos, uiTblSize;
FLMUINT uiCurrentVersion;
BTSK * pStack;
BTSK stackBuf[ BH_MAX_LEVELS ];
FLMBYTE pKeyBuf[ DIN_KEY_SIZ + 4 ];
FLMBYTE pDrnKey[ DIN_KEY_SIZ];
DB_UPGRADE_INFO DbConvertInfo;
f_memset( &DbConvertInfo, 0, sizeof( DB_UPGRADE_INFO));
// Supported conversions...
uiCurrentVersion = pFile->FileHdr.uiVersionNum;
// Loop through all of the data blocks in the lfile.
pLFileTbl = pDb->pDict->pLFileTbl;
uiTblSize = pDb->pDict->uiLFileCnt;
FSInitStackCache( &stackBuf [0], BH_MAX_LEVELS);
for( uiPos = 0; uiPos < uiTblSize; uiPos++)
{
LFILE * pLFile;
pLFile = &pLFileTbl [uiPos];
if( pLFile->uiLfType == LF_CONTAINER)
{
if( fnStatusCallback)
{
DbConvertInfo.uiLastDrn = 0;
if( RC_BAD( rc = FSGetNextDrn( pDb, pLFile, FALSE,
&DbConvertInfo.uiLastDrn)))
goto Exit;
}
// Set up the stack
FSInitStackCache( &stackBuf [0], BH_MAX_LEVELS);
pStack = stackBuf;
pStack->pKeyBuf = pKeyBuf;
f_UINT32ToBigEndian( 0, pDrnKey);
if( RC_BAD(rc = FSBtSearch( pDb, pLFile, &pStack,
pDrnKey, DIN_KEY_SIZ,0)))
goto Exit;
// If pStack isn't at stackBuf[] we have a b-tree of 2 or more levels.
// VISIT: the change may not be necessary - may be new version.
// Look at the root block type.
if( pStack != stackBuf) // && ? Need to look at real block type?
{
DbConvertInfo.uiContainer = pLFile->uiLfNum;
if( RC_BAD( rc = FSConvertNonLeafTree( pDb, pLFile, pStack - 1,
stackBuf, uiNewVersion,
fnStatusCallback, UserData, &DbConvertInfo)))
goto Exit;
}
FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE);
}
}
// Loop through all of the data b-trees and look for non-leaf blocks.
Exit:
FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE);
return( rc);
}
/***************************************************************************
Desc: Convert the non-leaf data blocks from one version to another version.
pOldStack points to the level 1 non-leaf data blocks.
Read all of the elements and build a new non-leaf b-tree
and make this the new tree while freeing up the old non-leaf blocks.
*****************************************************************************/
FSTATIC RCODE FSConvertNonLeafTree(
FDB * pDb,
LFILE * pLFile,
BTSK * pOldStack,
BTSK * pOldStackBase,
FLMUINT uiNewVersion,
STATUS_HOOK fnStatusCallback,
void * UserData,
DB_UPGRADE_INFO * pDbConvertInfo)
{
RCODE rc = FERR_OK;
BTSK stackBuf[ BH_MAX_LEVELS ];
BTSK * pStack;
FLMBYTE pKeyBuf[ DIN_KEY_SIZ + 4 ];
FLMBYTE pDrnKey[ DIN_KEY_SIZ];
FLMBYTE pElement[ DIN_KEY_SIZ + 16]; // Enough bytes for either format
SCACHE * pTempSCache;
FLMUINT uiBlkAddr;
FSInitStackCache( &stackBuf [0], BH_MAX_LEVELS);
f_UINT32ToBigEndian( 0, pDrnKey);
/*
Free the b-tree blocks that are above this lowest non-leaf level.
This will reuse the blocks instead of allocating from the avail list or end
of file.
*/
pOldStack->uiFlags &= ~FULL_STACK;
for( ; pOldStackBase != pOldStack; pOldStackBase++ )
{
uiBlkAddr = pOldStackBase->uiBlkAddr;
// Release block so that caller doesn't release an avail block.
FSReleaseBlock( pOldStackBase, FALSE);
while( uiBlkAddr != BT_END)
{
if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF,
uiBlkAddr, NULL, &pTempSCache)))
goto Exit;
uiBlkAddr = FB2UD( &pTempSCache->pucBlk[ BH_NEXT_BLK ]);
if( RC_BAD( FSBlockFree( pDb, pTempSCache)))
goto Exit;
}
}
// Allocate a new root block in the new NON-LEAF format.
pStack = stackBuf;
pStack->pKeyBuf = pKeyBuf;
pLFile->uiRootBlk = BT_END;
if( RC_BAD( flmLFileWrite( pDb, pLFile)))
{
goto Exit;
}
if( RC_BAD( rc = flmLFileInit( pDb, pLFile)))
{
goto Exit;
}
if( RC_BAD(rc = FSGetBlock( pDb, pLFile, pLFile->uiRootBlk, pStack)))
{
goto Exit;
}
if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack)))
{
goto Exit;
}
// Remove both leading elements in the block and setup as a non-leaf block.
UW2FBA( BH_OVHD, &pStack->pBlk[ BH_BLK_END]);
if( uiNewVersion >= FLM_FILE_FORMAT_VER_4_0)
{
pStack->pBlk[ BH_TYPE ] = BHT_NON_LEAF_DATA + BHT_ROOT_BLK;
}
else
{
pStack->pBlk[ BH_TYPE ] = BHT_NON_LEAF + BHT_ROOT_BLK;
}
pStack->pBlk[ BH_LEVEL ] = 1;
pStack->uiKeyBufSize = DIN_KEY_SIZ;
FSBlkToStack( pStack);
pStack->uiFlags = FULL_STACK;
// Build the key for the first element in the old stack.
if( RC_BAD( rc = FSBtScanTo( pOldStack, NULL, 0, 0)))
{
goto Exit;
}
// Start inserting from pOldStack to pStack until pOldStack is done.
for(;;)
{
FLMUINT uiElmLen;
FLMBYTE * pKey;
FSBuildNonLeafDataElement( pOldStack, pElement,
&uiElmLen, pStack->uiElmOvhd, &pKey);
if( uiNewVersion <= FLM_FILE_FORMAT_VER_3_02)
{
flmAssert( pStack->uiCurElm == pStack->uiBlkEnd);
if( pStack != stackBuf)
{
flmAssert( stackBuf[0].uiCurElm + 6 == stackBuf[0].uiBlkEnd);
}
pStack->uiCurElm = pStack->uiBlkEnd;
// Call scanto to place the last element's key in keybuf.
if( RC_BAD( rc = FSBtScanTo( pStack, NULL, 0, 0)))
goto Exit;
if( pStack->uiBlkEnd > BH_OVHD)
{
if( uiElmLen > BNE_KEY_START)
{
pStack->uiPrevElmPKC =
FSElmComparePKC( pKeyBuf, DIN_KEY_SIZ, pKey, DIN_KEY_SIZ);
}
}
}
if( RC_BAD( rc = FSBtInsert( pDb, pLFile, &pStack, pElement, uiElmLen)))
goto Exit;
// Go to next element so we always insert at the end.
(void) FSBtNextElm( pDb, pLFile, pStack );
uiBlkAddr = pOldStack->uiBlkAddr;
if( RC_BAD( rc = FSBtNextElm( pDb, pLFile, pOldStack )))
{
// All done? Free the last block in the old b-tree.
if( rc == FERR_BT_END_OF_DATA)
{
if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF,
uiBlkAddr, NULL, &pTempSCache)))
goto Exit;
// No need to release pTempSCache. FSBlockFree does it.
if( RC_BAD( FSBlockFree( pDb, pTempSCache)))
goto Exit;
rc = FERR_OK;
break;
}
goto Exit;
}
// Did next element position to a new block?
if( uiBlkAddr != pOldStack->uiBlkAddr)
{
// Do callback to report progress.
if (fnStatusCallback)
{
pDbConvertInfo->uiDrn = f_bigEndianToUINT32( pOldStack->pKeyBuf);
if (RC_BAD( rc = (*fnStatusCallback)( FLM_DB_UPGRADE_STATUS,
(void *) pDbConvertInfo,
(void *)0, UserData)))
{
goto Exit;
}
}
// Free the previous block back into the avail list.
if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF,
uiBlkAddr, NULL, &pTempSCache)))
goto Exit;
if( RC_BAD( FSBlockFree( pDb, pTempSCache)))
goto Exit;
// No need to release pTempSCache. FSBlockFree does it.
}
}
Exit:
FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE);
return( rc);
}
/***************************************************************************
Desc: Build a non-leaf data element from the current stack position.
*****************************************************************************/
FSTATIC void FSBuildNonLeafDataElement(
BTSK * pStack,
FLMBYTE * pElement,
FLMUINT * puiElmLen,
FLMUINT uiNewElmOvhd,
FLMBYTE ** ppKey)
{
FLMUINT uiElmLen;
// Grab the key from the key buffer,
if( uiNewElmOvhd == BNE_DATA_OVHD) // New fixed length 4.0 format.
{
FLMBYTE * pOldElm = CURRENT_ELM( pStack);
uiElmLen = BNE_DATA_OVHD;
*ppKey = pElement;
// Check for last element marker.
if( pOldElm[ BBE_PKC ] == 0 && pOldElm[ BBE_KL] == 0)
{
f_UINT32ToBigEndian( (FLMUINT32)DRN_LAST_MARKER, pElement);
}
else
{
f_memcpy( pElement, pStack->pKeyBuf, DIN_KEY_SIZ);
}
}
else // Old variable length 3.x format.
{
pElement [ BBE_PKC ] = 0; // Set PKC, DOMAIN to zero
if( FB2UD( pStack->pKeyBuf) == DRN_LAST_MARKER)
{
pElement [ BBE_KL ] = 0;
uiElmLen = BNE_KEY_START;
}
else
{
pElement [ BBE_PKC ] = 0; // Set PKC, DOMAIN to zero
pElement [ BBE_KL ] = DIN_KEY_SIZ; // sizeof( FLMUINT32) or 4
uiElmLen = BNE_KEY_START + DIN_KEY_SIZ;
f_memcpy( pElement + BNE_KEY_START, pStack->pKeyBuf, DIN_KEY_SIZ);
}
*ppKey = pElement + BNE_KEY_START;
}
// Set the child block address.
FSSetChildBlkAddr( pElement, FSChildBlkAddr( pStack), uiNewElmOvhd);
*puiElmLen = uiElmLen;
return;
}