Files
mars-flaim/xflaim/src/flchktr.cpp
ahodgkinson 12a621dc04 Changed license to LGPL.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@1010 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2007-01-23 11:22:22 +00:00

276 lines
6.5 KiB
C++

//------------------------------------------------------------------------------
// Desc: Check b-trees for physical integrity.
// Tabs: 3
//
// Copyright (c) 1991-1992, 1995-2007 Novell, Inc. All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version 2.1
// of the License.
//
// This library 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
// Library Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; 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$
//------------------------------------------------------------------------------
#include "flaimsys.h"
FSTATIC RCODE chkReadBlkFromDisk(
F_Db * pDb,
F_Database * pDatabase,
XFLM_DB_HDR * pDbHdr,
F_SuperFileHdl * pSFileHdl,
FLMUINT uiFilePos,
F_BLK_HDR * pBlkHdr);
/********************************************************************
Desc: Read a block - try cache first, then disk if not in cache.
*********************************************************************/
RCODE F_DbCheck::blkRead(
FLMUINT uiBlkAddress,
F_BLK_HDR ** ppBlkHdr,
F_CachedBlock ** ppSCache,
FLMINT32 * pi32BlkErrCodeRV)
{
RCODE rc = NE_XFLM_OK;
if (*ppSCache)
{
ScaReleaseCache( *ppSCache, FALSE);
*ppSCache = NULL;
*ppBlkHdr = NULL;
}
else if (*ppBlkHdr)
{
f_free( ppBlkHdr);
*ppBlkHdr = NULL;
}
if (m_pDb->m_uiKilledTime)
{
rc = RC_SET( NE_XFLM_OLD_VIEW);
goto Exit;
}
// Get the block from cache.
if (RC_OK( rc = m_pDb->m_pDatabase->getBlock( m_pDb, NULL,
uiBlkAddress, NULL, ppSCache)))
{
*ppBlkHdr = (*ppSCache)->getBlockPtr();
}
else
{
// Try to read the block directly from disk.
FLMUINT uiBlkSize = m_pDb->m_pDatabase->m_uiBlockSize;
FLMUINT64 ui64TransID;
F_BLK_HDR * pBlkHdr;
FLMUINT64 ui64LastReadTransID;
FLMUINT uiPrevBlkAddr;
FLMUINT uiFilePos;
// If we didn't get a corruption error, jump to exit.
if( !gv_pXFlmDbSystem->errorIsFileCorrupt( rc))
{
goto Exit;
}
// Allocate memory for the block.
if( RC_BAD( rc = f_calloc( uiBlkSize, ppBlkHdr)))
{
goto Exit;
}
pBlkHdr = *ppBlkHdr;
uiFilePos = uiBlkAddress;
ui64TransID = m_pDb->m_ui64CurrTransID;
ui64LastReadTransID = ~((FLMUINT64)0);
// Follow version chain until we find version we need.
for (;;)
{
if (RC_BAD( rc = chkReadBlkFromDisk(
m_pDb,
m_pDb->m_pDatabase,
&m_pDb->m_pDatabase->m_lastCommittedDbHdr,
m_pDb->m_pSFileHdl,
uiFilePos, pBlkHdr)))
{
goto Exit;
}
// See if we can use the current version of the block, or if we
// must go get a previous version.
if (pBlkHdr->ui64TransID <= ui64TransID)
{
break;
}
// If the transaction ID is greater than or equal to the last
// one we read, we have a corruption. This test will keep us
// from looping around forever.
if (pBlkHdr->ui64TransID >= ui64LastReadTransID)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
ui64LastReadTransID = pBlkHdr->ui64TransID;
// Block is too new, go for next older version.
// If previous block address is same as current file position or
// zero, we have a problem.
uiPrevBlkAddr = (FLMUINT)pBlkHdr->ui32PriorBlkImgAddr;
if (uiPrevBlkAddr == uiFilePos || !uiPrevBlkAddr)
{
rc = (m_pDb->m_uiKilledTime)
? RC_SET( NE_XFLM_OLD_VIEW)
: RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
uiFilePos = uiPrevBlkAddr;
}
// See if we even got the block we thought we wanted.
if ((FLMUINT)pBlkHdr->ui32BlkAddr != uiBlkAddress)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
}
Exit:
*pi32BlkErrCodeRV = 0;
if (RC_BAD( rc))
{
switch (rc)
{
case NE_XFLM_DATA_ERROR:
*pi32BlkErrCodeRV = FLM_COULD_NOT_SYNC_BLK;
break;
case NE_XFLM_BLOCK_CRC:
*pi32BlkErrCodeRV = FLM_BAD_BLK_CHECKSUM;
break;
}
}
return( rc);
}
/************************************************************************
Desc: Read a block from disk
*************************************************************************/
FSTATIC RCODE chkReadBlkFromDisk(
F_Db * pDb,
F_Database * pDatabase,
XFLM_DB_HDR * pDbHdr,
F_SuperFileHdl * pSFileHdl,
FLMUINT uiFilePos,
F_BLK_HDR * pBlkHdr
)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiBytesRead;
FLMUINT uiBlkSize = (FLMUINT)pDbHdr->ui16BlockSize;
F_Dict * pDict;
if (RC_BAD( rc = pSFileHdl->readBlock( uiFilePos, uiBlkSize,
(FLMBYTE *)pBlkHdr, &uiBytesRead)))
{
if (rc == NE_FLM_IO_END_OF_FILE)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
if (uiBytesRead < uiBlkSize)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
if (RC_BAD( rc = flmPrepareBlockForUse( uiBlkSize, pBlkHdr)))
{
goto Exit;
}
// Decrypt the block if encrypted
if (RC_BAD( rc = pDb->getDictionary( &pDict)))
{
goto Exit;
}
if (RC_BAD( rc = pDatabase->decryptBlock( pDict, (FLMBYTE *)pBlkHdr)))
{
goto Exit;
}
Exit:
return( rc);
}
/********************************************************************
Desc: Report an error
*********************************************************************/
RCODE F_DbCheck::chkReportError(
FLMINT32 i32ErrCode,
FLMUINT32 ui32ErrLocale,
FLMUINT32 ui32ErrLfNumber,
FLMUINT32 ui32ErrLfType,
FLMUINT32 ui32ErrBTreeLevel,
FLMUINT32 ui32ErrBlkAddress,
FLMUINT32 ui32ErrParentBlkAddress,
FLMUINT32 ui32ErrElmOffset,
FLMUINT64 ui64ErrNodeId)
{
XFLM_CORRUPT_INFO CorruptInfo;
FLMBOOL bFixErr;
CorruptInfo.i32ErrCode = i32ErrCode;
CorruptInfo.ui32ErrLocale = ui32ErrLocale;
CorruptInfo.ui32ErrLfNumber = ui32ErrLfNumber;
CorruptInfo.ui32ErrLfType = ui32ErrLfType;
CorruptInfo.ui32ErrBTreeLevel = ui32ErrBTreeLevel;
CorruptInfo.ui32ErrBlkAddress = ui32ErrBlkAddress;
CorruptInfo.ui32ErrParentBlkAddress = ui32ErrParentBlkAddress;
CorruptInfo.ui32ErrElmOffset = ui32ErrElmOffset;
CorruptInfo.ui64ErrNodeId = ui64ErrNodeId;
CorruptInfo.ifpErrIxKey = NULL;
if (m_pDbCheckStatus && RC_OK( m_LastStatusRc))
{
bFixErr = FALSE;
m_LastStatusRc = m_pDbCheckStatus->reportCheckErr( &CorruptInfo, &bFixErr);
}
if (i32ErrCode != FLM_OLD_VIEW)
{
m_bPhysicalCorrupt = TRUE;
m_uiFlags &= ~XFLM_DO_LOGICAL_CHECK;
}
return( m_LastStatusRc);
}