Files
mars-flaim/flaim/util/checkdb.cpp
ahodgkinson f54e6ce080 Changed license to LGPL.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@1009 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2007-01-23 09:38:48 +00:00

2020 lines
46 KiB
C++

//-------------------------------------------------------------------------
// Desc: Check database for corruptions.
// Tabs: 3
//
// Copyright (c) 1992-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"
#include "sharutil.h"
#define UTIL_ID "CHECKDB"
#define MAX_LOG_BUF (16 * 1024)
#define LABEL_COLUMN 5
#define VALUE_COLUMN 30
#define LOG_FILE_ROW 1
#define SOURCE_ROW 2
#define DATA_DIR_ROW 3
#define RFL_DIR_ROW 4
#define CACHE_USED_ROW 5
#define DOING_ROW 7
#define DB_SIZE_ROW 8
#define AMOUNT_DONE_ROW 9
#define TOTAL_KEYS_ROW 10
#define TOTAL_KEYS_EXAM_ROW 11
#define BAD_IXREF_ROW 12
#define MISSING_IXREF_ROW 13
#define NONUNIQUE_ROW 14
#define CONFLICT_ROW 15
#define CORRUPT_ROW 16
#define TOTAL_CORRUPT_ROW 17
#define REPAIR_ROW 18
#define OLD_VIEW_ROW 19
#define MISMATCH_ROW 20
#define MAX_LOG_BUFF 2048
#define MISMATCH_READ_ERR 0
#define MISMATCH_ERROR_CODE 1
#define MISMATCH_ERR_LOCALE 2
#define MISMATCH_LF_NUMBER 3
#define MISMATCH_LF_NAME 4
#define MISMATCH_LF_TYPE 5
#define MISMATCH_LF_LEVEL 6
#define MISMATCH_BLK_ADDRESS 7
#define MISMATCH_PARENT_ADDRESS 8
#define MISMATCH_ELM_OFFSET 9
#define MISMATCH_DRN 10
#define MISMATCH_ELM_REC_OFFSET 11
#define MISMATCH_FIELD_NUM 12
#define MISMATCH_ERR_NOT_LOGGED 13
FSTATIC FLMBOOL CheckDatabase( void);
FSTATIC FLMBOOL DoCheck( void);
FSTATIC void CheckShowHelp(
FLMBOOL bShowFullUsage);
FSTATIC FLMBOOL GetParams(
FLMINT iArgC,
char ** ppucArgV);
FSTATIC void OutLabel(
FLMUINT uiCol,
FLMUINT uiRow,
const char * pucLabel,
const char * pucValue,
FLMUINT64 ui64NumValue,
FLMBOOL bLogIt);
FSTATIC void OutLine(
const char * pucString);
FSTATIC FLMBOOL GetDatabaseTags( void);
FSTATIC void LogFlush( void);
FSTATIC void LogString(
const char * pszString);
FSTATIC void DisplayValue(
FLMUINT uiRow,
const char * pucValue);
FSTATIC void DisplayNumValue(
FLMUINT uiRow,
FLMUINT64 ui64Number);
FSTATIC void OutValue(
const char * pucLabel,
const char * pucValue);
FSTATIC void OutUINT(
const char * pucLabel,
FLMUINT uiNum);
FSTATIC void OutUINT64(
const char * pucLabel,
FLMUINT64 ui64Num);
FSTATIC void OutBlkHeader( void);
FSTATIC void OutOneBlockStat(
const char * pucLabel,
FLMUINT uiBlockSize,
BLOCK_INFO * pBlockInfo,
FLMUINT64 ui64KeyCount,
FLMUINT64 ui64RefCount,
FLMUINT64 ui64FldCount);
FSTATIC void OutLogicalFile(
DB_CHECK_PROGRESS * pCheckProgress,
FLMUINT uiIndex);
FSTATIC void PrintInfo(
DB_CHECK_PROGRESS * pCheckProgress);
FSTATIC FLMUINT CheckShowError(
const char * pucMessage,
FLMBOOL bLogIt);
FSTATIC RCODE GetUserInput( void);
RCODE ProgFunc(
eStatusType eStatus,
void * pvParm1,
void * pvParm2,
void * pvAppData);
FSTATIC void LogStr(
FLMUINT uiIndent,
const char * pszStr);
FSTATIC void LogCorruptError(
CORRUPT_INFO * pCorrupt);
FSTATIC void LogKeyError(
CORRUPT_INFO * pCorrupt);
FSTATIC FLMBOOL DisplayField(
FlmRecord * pRecord,
void * pvField,
FLMUINT uiStartCol,
FLMUINT uiLevelOffset);
FSTATIC void NumToName(
FLMUINT uiNum,
char * pucBuf);
FLMBOOL gv_bShutdown = FALSE;
static F_Pool gv_pool;
static IF_FileHdl * gv_pLogFile = NULL;
static HFDB gv_hDb = HFDB_NULL;
static F_NameTable * gv_pNameTable = NULL;
static FLMUINT gv_uiMaxRow;
static FLMUINT gv_uiLineCount;
static char gv_pucLogFileName[ F_PATH_MAX_SIZE];
static char gv_pucTmpDir[ F_PATH_MAX_SIZE];
static char gv_pucLastError[ 256];
static char gv_pucDbFileName[ F_PATH_MAX_SIZE];
static char gv_szDataDir[ F_PATH_MAX_SIZE];
static char gv_szRflDir[ F_PATH_MAX_SIZE];
static char * gv_pucLogBuffer = NULL;
static FLMUINT64 gv_ui64DatabaseSize;
static FLMUINT64 gv_ui64BytesDone;
static FLMUINT gv_uiCorruptCount;
static FLMUINT gv_uiRepairCount;
static FLMUINT gv_uiTotalCorruptions;
static FLMUINT gv_uiOldViewCount;
static FLMUINT gv_uiMismatchCount;
static FLMUINT gv_uiLogBufferCount = 0;
static FLMBOOL gv_bMultiplePasses = FALSE;
static FLMBOOL gv_bBatchMode;
static FLMBOOL gv_bContinue;
static FLMBOOL gv_bStartUpdate = FALSE;
static FLMBOOL gv_bRepairCorruptions = FALSE;
static FLMBOOL gv_bDoLogicalCheck = FALSE;
static FLMBOOL gv_bLoggingEnabled;
static FLMBOOL gv_bShowStats;
static FLMBOOL gv_bRunning;
static FLMBOOL gv_bPauseBeforeExiting = FALSE;
static IF_FileSystem * gv_pFileSystem = NULL;
static char gv_szPassword[ 256];
/********************************************************************
Desc: ?
*********************************************************************/
#ifdef FLM_RING_ZERO_NLM
extern "C" int nlm_main(
#else
int main(
#endif
int iArgC,
char ** ppucArgV)
{
int iResCode = 0;
F_Pool * pLogPool = NULL;
gv_bBatchMode = FALSE;
gv_bShutdown = FALSE;
gv_bRunning = TRUE;
gv_pucLastError[ 0] = '\0';
if( RC_BAD( FlmStartup()))
{
f_conStrOut( "\nCould not initialize FLAIM.\n");
goto Exit;
}
f_conInit( 0xFFFF, 0xFFFF, "FLAIM Database Check");
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conDrawBorder();
f_conClearScreen( 0, 0);
f_conGetScreenSize( NULL, &gv_uiMaxRow);
if( RC_BAD( FlmGetFileSystem( &gv_pFileSystem)))
{
f_conStrOut( "\nCould not allocate a file system object.\n");
goto Exit;
}
if( (pLogPool = f_new F_Pool) == NULL)
{
f_conStrOut( "\nCould not allocate a pool object.\n");
goto Exit;
}
pLogPool->poolInit( 1024);
if( RC_BAD( pLogPool->poolAlloc( MAX_LOG_BUF, (void **)&gv_pucLogBuffer)))
{
f_conStrOut( "\nCould not allocat memory.\n");
goto Exit;
}
if( GetParams( iArgC, ppucArgV))
{
if (!DoCheck())
{
iResCode = 1;
}
}
if( gv_pucTmpDir[ 0] != '\0')
{
(void)FlmConfig( FLM_TMPDIR, (void *)(&gv_pucTmpDir [0]), 0);
}
if( (gv_bPauseBeforeExiting) && (!gv_bShutdown))
{
f_conSetCursorPos( 0, (FLMUINT)(gv_uiMaxRow - 2));
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conClearScreen( 0, (FLMBYTE)(gv_uiMaxRow - 2));
f_conSetBackFore( FLM_RED, FLM_WHITE);
if( gv_pucLastError[ 0] != '\0')
{
f_conStrOut( gv_pucLastError);
}
f_conSetCursorPos( 0, gv_uiMaxRow - 1);
f_conStrOut( "Press any character to exit CHECKDB: ");
for (;;)
{
if( gv_bShutdown)
{
break;
}
if( f_conHaveKey())
{
f_conGetKey();
break;
}
}
}
Exit:
if( gv_pFileSystem)
{
gv_pFileSystem->Release();
gv_pFileSystem = NULL;
}
if( pLogPool)
{
pLogPool->Release();
}
f_conExit();
FlmShutdown();
gv_bRunning = FALSE;
return( iResCode);
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC FLMBOOL CheckDatabase( void)
{
RCODE rc = FERR_OK;
FLMUINT uiStatus;
char pucTmpBuf[ 100];
FLMUINT uiCheckFlags;
FLMBOOL bOk = TRUE;
FLMBOOL bCheckDb = TRUE;
FLMBOOL bStartedTrans;
DB_CHECK_PROGRESS CheckProgress;
// Open the database - if not already open
if( gv_hDb == HFDB_NULL)
{
if( RC_BAD( rc = FlmDbOpen( gv_pucDbFileName, gv_szDataDir,
gv_szRflDir, 0, &gv_szPassword[ 0], &gv_hDb)))
{
f_strcpy( pucTmpBuf, "Error opening database: ");
f_strcpy( &pucTmpBuf[ f_strlen( pucTmpBuf)], FlmErrorString( rc));
CheckShowError( pucTmpBuf, TRUE);
bOk = FALSE;
goto Exit;
}
}
// Get the tag numbers for the database we are doing
if( !GetDatabaseTags())
{
bOk = FALSE;
goto Exit;
}
gv_uiCorruptCount = 0;
gv_ui64BytesDone = 0;
gv_ui64DatabaseSize = 0;
gv_uiOldViewCount = 0;
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
if( gv_bLoggingEnabled)
{
LogString( NULL);
LogString( NULL);
LogString( NULL);
LogString( "==========================================================================");
LogString( "CHECK PARAMETERS:");
}
OutLabel( LABEL_COLUMN, SOURCE_ROW, "Database", gv_pucDbFileName, 0, TRUE);
OutLabel( LABEL_COLUMN, DATA_DIR_ROW, "Data Files Dir.",
gv_szDataDir [0]
? &gv_szDataDir [0]
: "<Same as DB>", 0, TRUE);
OutLabel( LABEL_COLUMN, RFL_DIR_ROW, "RFL Files Dir.",
gv_szRflDir [0]
? &gv_szRflDir [0]
: "<Same as DB>", 0, TRUE);
OutLabel( LABEL_COLUMN, LOG_FILE_ROW, "Log File",
(gv_pucLogFileName[ 0])
? &gv_pucLogFileName[ 0]
: "<NONE>", 0, FALSE);
OutLabel( LABEL_COLUMN, CACHE_USED_ROW, "Cache Bytes Used", NULL, 0, FALSE);
OutLabel( LABEL_COLUMN, DOING_ROW, "Doing", "Opening Database", 0, FALSE);
OutLabel( LABEL_COLUMN, DB_SIZE_ROW, "DB Size", NULL, (FLMUINT)gv_ui64DatabaseSize, FALSE);
OutLabel( LABEL_COLUMN, CORRUPT_ROW, "Database Corruptions", NULL, gv_uiCorruptCount, FALSE);
OutLabel( LABEL_COLUMN, TOTAL_CORRUPT_ROW, "Total Corruptions", NULL, gv_uiTotalCorruptions, FALSE);
OutLabel( LABEL_COLUMN, OLD_VIEW_ROW, "Old View Count", NULL, gv_uiOldViewCount, FALSE);
OutLabel( LABEL_COLUMN, MISMATCH_ROW, "Mismatch Count", NULL, gv_uiMismatchCount, FALSE);
OutLabel( LABEL_COLUMN, REPAIR_ROW, "Problems Repaired", NULL, gv_uiRepairCount, FALSE);
OutLabel( LABEL_COLUMN, TOTAL_KEYS_ROW, "Total Index Keys", NULL, 0, FALSE);
OutLabel( LABEL_COLUMN, CONFLICT_ROW, "Key Conflicts", NULL, 0, FALSE);
OutLabel( LABEL_COLUMN, TOTAL_KEYS_EXAM_ROW, "Num. Keys Checked", NULL, 0, FALSE);
OutLabel( LABEL_COLUMN, BAD_IXREF_ROW, "Invalid Index Keys", NULL, 0, FALSE);
OutLabel( LABEL_COLUMN, MISSING_IXREF_ROW, "Missing Index Keys", NULL, 0, FALSE);
OutLabel( LABEL_COLUMN, NONUNIQUE_ROW, "Non-unique Index Keys", NULL, 0, FALSE);
if( gv_bLoggingEnabled)
{
LogString( NULL);
LogString( "CHECK DETAILED RESULTS:");
LogString( NULL);
}
uiCheckFlags = FLM_CHK_FIELDS;
if( gv_bDoLogicalCheck)
{
uiCheckFlags |= FLM_CHK_INDEX_REFERENCING;
}
if( RC_OK( rc))
{
// Start an update transaction for the duration of the check.
bStartedTrans = FALSE;
if( gv_bStartUpdate)
{
if( RC_BAD( rc = FlmDbTransBegin( gv_hDb,
FLM_UPDATE_TRANS, 15)))
{
bCheckDb = FALSE;
}
bStartedTrans = TRUE;
}
if( bCheckDb)
{
rc = FlmDbCheck( gv_hDb, NULL, NULL, NULL,
uiCheckFlags, &gv_pool, &CheckProgress, ProgFunc, (void *)0);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
(void)FlmDbTransAbort( gv_hDb);
}
else
{
rc = FlmDbTransCommit( gv_hDb);
}
}
}
if( rc == FERR_FAILURE)
{
f_sprintf( pucTmpBuf, "User pressed ESCAPE, check halted");
gv_bShutdown = TRUE;
}
else
{
f_strcpy( pucTmpBuf, "RETURN CODE: ");
f_strcpy( &pucTmpBuf[ f_strlen( pucTmpBuf)], FlmErrorString( rc));
}
uiStatus = CheckShowError( pucTmpBuf, TRUE);
if( ((uiStatus != FKB_ESCAPE) || (gv_bLoggingEnabled)) &&
(gv_bShowStats) &&
((rc == FERR_OK) ||
(rc == FERR_DATA_ERROR) ||
(rc == FERR_TRANS_ACTIVE)))
{
PrintInfo( &CheckProgress);
}
if( gv_bLoggingEnabled)
{
LogString( NULL);
LogFlush();
}
Exit:
if( gv_pNameTable)
{
gv_pNameTable->Release();
gv_pNameTable = NULL;
}
if( gv_hDb != HFDB_NULL)
{
FlmDbClose( &gv_hDb);
}
gv_pool.poolReset();
return( bOk);
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC FLMBOOL DoCheck( void)
{
RCODE rc = FERR_OK;
FLMBOOL bOk = TRUE;
char pucTmpBuf[ 100];
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conClearScreen( 0, 0);
gv_bContinue = TRUE;
gv_uiLineCount = 0;
gv_bLoggingEnabled = FALSE;
gv_uiCorruptCount = 0;
gv_uiTotalCorruptions = 0;
gv_uiRepairCount = 0;
gv_uiMismatchCount = 0;
gv_uiLogBufferCount = 0;
gv_pool.poolInit( 1024);
if( gv_pucLogFileName[ 0])
{
gv_pFileSystem->deleteFile( gv_pucLogFileName);
if( RC_OK( rc = gv_pFileSystem->createFile( gv_pucLogFileName,
FLM_IO_RDWR | FLM_IO_SH_DENYNONE, &gv_pLogFile)))
{
gv_bLoggingEnabled = TRUE;
}
else
{
f_strcpy( pucTmpBuf, "Error creating log file: ");
f_strcpy( &pucTmpBuf[ f_strlen( pucTmpBuf)], FlmErrorString( rc));
CheckShowError( pucTmpBuf, FALSE);
bOk = FALSE;
goto Exit;
}
}
f_conSetCursorType( FLM_CURSOR_INVISIBLE);
for( ;;)
{
if( !CheckDatabase())
{
bOk = FALSE;
break;
}
if( (!gv_bMultiplePasses) || (gv_bShutdown))
{
break;
}
}
f_conSetCursorType( FLM_CURSOR_UNDERLINE);
if( gv_bLoggingEnabled)
{
LogFlush();
gv_pLogFile->Release();
gv_pLogFile = NULL;
}
Exit:
gv_pool.poolFree();
return( bOk);
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void CheckShowHelp(
FLMBOOL bShowFullUsage)
{
f_conStrOut( "\n");
if( bShowFullUsage)
{
f_conStrOut( "Usage: checkdb <FileName> [Options]\n");
}
else
{
f_conStrOut( "Parameters: <FileName> [Options]\n\n");
}
f_conStrOut( " FileName = Name of database to check.\n");
f_conStrOut( " Options\n");
f_conStrOut( " -b = Run in Batch Mode.\n");
f_conStrOut( " -c = Repair logical corruptions.\n");
f_conStrOut( " -d = Display/log detailed statistics.\n");
f_conStrOut( " -dr<Dir> = RFL directory.\n");
f_conStrOut( " -dd<Dir> = Data directory.\n");
f_conStrOut( " -i = Perform a logical (index) check.\n");
f_conStrOut( " -l<FileName> = Log detailed information to <FileName>.\n");
f_conStrOut( " -m = Multiple passes (continuous check).\n");
f_conStrOut( " -o<FileName> = Output binary log information to <FileName>.\n");
f_conStrOut( " -p = Pause before exiting.\n");
f_conStrOut( " -pw<password>= Open database with password.\n");
f_conStrOut( " -t<Path> = Temporary directory.\n");
f_conStrOut( " -u = Run check in an update transaction.\n");
f_conStrOut( " -v<FileName> = Verify binary log information in <FileName>. NOTE:\n");
f_conStrOut( " The -v and -o options cannot both be specified.\n");
f_conStrOut( " -? = A '?' anywhere in the command line will cause this\n");
f_conStrOut( " screen to be displayed.\n");
f_conStrOut( "Options may be specified anywhere in the command line.\n");
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC FLMBOOL GetParams(
FLMINT iArgC,
char ** ppucArgV)
{
#define MAX_ARGS 30
FLMUINT uiLoop;
char pucTmpBuf[ 100];
char * pucTmp;
char * ppArgs[ MAX_ARGS];
char pucCommandBuffer[ 300];
gv_pucDbFileName[ 0] = '\0';
gv_szDataDir[ 0] = '\0';
gv_szRflDir[ 0] = '\0';
gv_pucLogFileName[ 0] = '\0';
gv_pucTmpDir[ 0] = '\0';
gv_szPassword[ 0] = '\0';
gv_bShowStats = FALSE;
// Ask the user to enter parameters if none were entered on the command
// line.
if( iArgC < 2)
{
for( ;;)
{
f_conStrOut( "CheckDB Params (enter ? for help): ");
pucCommandBuffer[ 0] = '\0';
f_conLineEdit( pucCommandBuffer, sizeof( pucCommandBuffer) - 1);
if( gv_bShutdown)
{
return( FALSE);
}
if( f_stricmp( pucCommandBuffer, "?") == 0)
{
CheckShowHelp( FALSE);
}
else
{
break;
}
}
flmUtilParseParams( pucCommandBuffer, MAX_ARGS, &iArgC,
(const char **)&ppArgs [1]);
ppArgs[ 0] = ppucArgV [0];
iArgC++;
ppucArgV = &ppArgs[ 0];
}
uiLoop = 1;
while( uiLoop < (FLMUINT)iArgC)
{
pucTmp = ppucArgV[ uiLoop];
// See if they specified an option
#ifdef FLM_UNIX
if( *pucTmp == '-')
#else
if( (*pucTmp == '-') || (*pucTmp == '/'))
#endif
{
pucTmp++;
if( (*pucTmp == 'l') || (*pucTmp == 'L'))
{
pucTmp++;
if( *pucTmp)
{
f_strcpy( gv_pucLogFileName, pucTmp);
}
else
{
if( CheckShowError( "Log file name not specified in parameter", FALSE) == FKB_ESCAPE)
{
return( FALSE);
}
}
}
else if( (*pucTmp == 't') || (*pucTmp == 'T'))
{
pucTmp++;
if( *pucTmp)
{
f_strcpy( gv_pucTmpDir, pucTmp);
}
else
{
if( CheckShowError( "Temporary directory not specified in parameter", FALSE) == FKB_ESCAPE)
{
return( FALSE);
}
}
}
else if( (*pucTmp == 'd') || (*pucTmp == 'D'))
{
pucTmp++;
if (!(*pucTmp))
{
gv_bShowStats = TRUE;
}
else if (*pucTmp == 'r' || *pucTmp == 'R')
{
f_strcpy( gv_szRflDir, pucTmp + 1);
}
else if (*pucTmp == 'd' || *pucTmp == 'D')
{
f_strcpy( gv_szDataDir, pucTmp + 1);
}
else
{
f_sprintf( pucTmpBuf, "Invalid option %s", pucTmp - 1);
if( CheckShowError( pucTmpBuf, FALSE) == FKB_ESCAPE)
{
return( FALSE);
}
}
}
else if (f_stricmp( pucTmp, "B") == 0)
{
gv_bBatchMode = TRUE;
}
else if (f_stricmp( pucTmp, "C") == 0)
{
gv_bRepairCorruptions = TRUE;
}
else if (f_stricmp( pucTmp, "I") == 0)
{
gv_bDoLogicalCheck = TRUE;
}
else if (f_stricmp( pucTmp, "M") == 0)
{
gv_bMultiplePasses = TRUE;
}
else if ((*pucTmp == 'p') || (*pucTmp == 'P'))
{
pucTmp++;
if (!(*pucTmp))
{
gv_bPauseBeforeExiting = TRUE;
}
else if (*pucTmp == 'w' || *pucTmp == 'W')
{
f_strcpy( gv_szPassword, pucTmp + 1);
}
}
else if (f_stricmp( pucTmp, "U") == 0)
{
gv_bStartUpdate = TRUE;
}
else if (f_stricmp( pucTmp, "?") == 0 ||
f_stricmp( pucTmp, "HELP") == 0)
{
CheckShowHelp( TRUE);
gv_bPauseBeforeExiting = TRUE;
return( FALSE);
}
else
{
f_sprintf( pucTmpBuf, "Invalid option %s", pucTmp);
if( CheckShowError( pucTmpBuf, FALSE) == FKB_ESCAPE)
{
return( FALSE);
}
}
}
else if( f_stricmp( pucTmp, "?") == 0)
{
Show_Help:
CheckShowHelp( TRUE);
gv_bPauseBeforeExiting = TRUE;
return( FALSE);
}
else if( !gv_pucDbFileName[ 0])
{
f_strcpy( gv_pucDbFileName, pucTmp);
}
uiLoop++;
}
if( !gv_pucDbFileName[ 0])
{
goto Show_Help;
}
else
{
return( TRUE);
}
}
/***************************************************************************
Desc: This routine gets the tag names for the store we are checking
*****************************************************************************/
FSTATIC FLMBOOL GetDatabaseTags( void)
{
FLMBOOL bOk = TRUE;
RCODE rc = FERR_OK;
// Build the path and open the database
f_conSetBackFore( FLM_BLUE, FLM_LIGHTGRAY);
f_conClearScreen( 0, (FLMUINT)(gv_uiMaxRow - 1));
f_conSetCursorPos( 0, (FLMUINT)(gv_uiMaxRow - 1));
if( gv_pNameTable)
{
gv_pNameTable->Release();
gv_pNameTable = NULL;
}
f_conStrOut( "Initializing tag table ...");
if ((gv_pNameTable = f_new F_NameTable) == NULL)
{
CheckShowError( "Error creating tag table.", TRUE);
goto Exit;
}
if( RC_BAD( rc = gv_pNameTable->setupFromDb( gv_hDb)))
{
CheckShowError( "Error initializing tag table.", TRUE);
goto Exit;
}
Exit:
f_conSetBackFore( FLM_BLUE, FLM_LIGHTGRAY);
f_conClearScreen( 0, (FLMUINT)(gv_uiMaxRow - 1));
return( bOk);
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void LogFlush( void)
{
FLMUINT uiBytesWritten;
if( gv_uiLogBufferCount)
{
gv_pLogFile->write( FLM_IO_CURRENT_POS,
gv_uiLogBufferCount, gv_pucLogBuffer, &uiBytesWritten);
gv_uiLogBufferCount = 0;
}
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void LogString(
const char * pucString)
{
FLMUINT uiLen;
FLMUINT uiLoop;
if( (gv_bLoggingEnabled) && (gv_pucLogBuffer != NULL))
{
uiLen = (FLMUINT)((pucString != NULL)
? (FLMUINT)(f_strlen( pucString))
: 0);
for( uiLoop = 0; uiLoop < uiLen; uiLoop++)
{
gv_pucLogBuffer[ gv_uiLogBufferCount++] = *pucString++;
if( gv_uiLogBufferCount == MAX_LOG_BUFF)
{
LogFlush();
}
}
gv_pucLogBuffer[ gv_uiLogBufferCount++] = '\r';
if( gv_uiLogBufferCount == MAX_LOG_BUFF)
{
LogFlush();
}
gv_pucLogBuffer[ gv_uiLogBufferCount++] = '\n';
if( gv_uiLogBufferCount == MAX_LOG_BUFF)
{
LogFlush();
}
}
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void OutLine(
const char * pucBuf)
{
FLMUINT uiChar;
if( gv_bLoggingEnabled)
{
LogString( pucBuf);
}
if( !gv_bBatchMode)
{
if( gv_bContinue)
{
if( gv_uiLineCount == 20)
{
f_conSetCursorPos( 0, (FLMUINT)(gv_uiMaxRow - 1));
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conClearScreen( 0, (FLMUINT)(gv_uiMaxRow - 1));
f_conSetBackFore( FLM_RED, FLM_WHITE);
f_conStrOut( "Press: ESC to quit, anything else to continue");
for( ;;)
{
if( gv_bShutdown)
{
uiChar = FKB_ESCAPE;
break;
}
else if( f_conHaveKey())
{
uiChar = f_conGetKey();
break;
}
}
if( uiChar == FKB_ESCAPE)
{
gv_bContinue = FALSE;
}
else
{
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conClearScreen( 0, 0);
}
gv_uiLineCount = 0;
}
}
if( gv_bContinue)
{
f_conStrOutXY( pucBuf, 0, gv_uiLineCount);
gv_uiLineCount++;
}
}
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void OutValue(
const char * pucLabel,
const char * pucValue)
{
char pucTmpBuf[ 100];
f_strcpy( pucTmpBuf, "...................................... ");
f_strcpy( &pucTmpBuf[ f_strlen( pucTmpBuf)], pucValue);
f_memcpy( pucTmpBuf, pucLabel, f_strlen( pucLabel));
OutLine( pucTmpBuf);
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void OutUINT(
const char * pucLabel,
FLMUINT uiNum)
{
char pucValue[ 12];
if( uiNum == 0xFFFFFFFF)
{
f_strcpy( pucValue, "0xFFFFFFFF");
}
else
{
f_sprintf( pucValue, "%u", (unsigned)uiNum);
}
OutValue( pucLabel, pucValue);
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void OutUINT64(
const char * pucLabel,
FLMUINT64 ui64Num)
{
char pucValue [24];
if( ui64Num == (FLMUINT64)-1)
{
f_strcpy( pucValue, "0xFFFFFFFFFFFFFFFF");
}
else
{
f_sprintf( pucValue, "%u", (unsigned)ui64Num);
}
OutValue( pucLabel, pucValue);
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void OutBlkHeader( void)
{
OutLine( " Blk Type Blk Count Total Bytes Bytes Used Prcnt Element Cnt Avg Elem");
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void OutOneBlockStat(
const char * pucLabel,
FLMUINT uiBlockSize,
BLOCK_INFO * pBlockInfo,
FLMUINT64 ui64KeyCount,
FLMUINT64 ui64RefCount,
FLMUINT64 ui64FldCount)
{
char pucTmpBuf[ 100];
FLMUINT64 ui64TotalBytes;
FLMUINT uiPercent;
FLMUINT uiAvgElementSize;
ui64TotalBytes = (FLMUINT64)pBlockInfo->uiBlockCount *
(FLMUINT64)uiBlockSize;
if( pBlockInfo->ui64ElementCount)
{
uiAvgElementSize = (FLMUINT)( pBlockInfo->ui64BytesUsed /
pBlockInfo->ui64ElementCount);
}
else
{
uiAvgElementSize = 0;
}
if( pBlockInfo->ui64BytesUsed > (FLMUINT64)40000000)
{
uiPercent = (FLMUINT)( pBlockInfo->ui64BytesUsed /
(ui64TotalBytes / (FLMUINT64)100));
}
else if( ui64TotalBytes)
{
uiPercent = (FLMUINT)(( pBlockInfo->ui64BytesUsed *
(FLMUINT64)100) / ui64TotalBytes);
}
else
{
uiPercent = 0;
}
f_sprintf( pucTmpBuf, "%-12s %10u %11u %10u %5u %11u %8u",
pucLabel, (unsigned)pBlockInfo->uiBlockCount, (unsigned)ui64TotalBytes,
(unsigned)pBlockInfo->ui64BytesUsed,
(unsigned)uiPercent, (unsigned)pBlockInfo->ui64ElementCount,
(unsigned)uiAvgElementSize);
OutLine( pucTmpBuf);
if( pBlockInfo->ui64ContElementCount)
{
uiAvgElementSize = (FLMUINT)( pBlockInfo->ui64ContElmBytes /
pBlockInfo->ui64ContElementCount);
if( pBlockInfo->ui64ContElmBytes > (FLMUINT64)40000000)
{
uiPercent =
(FLMUINT)( pBlockInfo->ui64ContElmBytes /
(ui64TotalBytes / (FLMUINT64)100));
}
else if( ui64TotalBytes)
{
uiPercent =
(FLMUINT)(( pBlockInfo->ui64ContElmBytes * (FLMUINT64)100) /
ui64TotalBytes);
}
else
{
uiPercent = 0;
}
f_sprintf( pucTmpBuf, "%-12s "
"%10u %5u %11u %8u", " ContElm",
(unsigned)pBlockInfo->ui64ContElmBytes,
(unsigned)uiPercent, (unsigned)pBlockInfo->ui64ContElementCount,
(unsigned)uiAvgElementSize);
OutLine( pucTmpBuf);
}
if( ui64KeyCount)
{
f_sprintf( pucTmpBuf, "%-12s %10u",
" KeyCnt", (unsigned)ui64KeyCount);
OutLine( pucTmpBuf);
}
if( ui64RefCount)
{
f_sprintf( pucTmpBuf, "%-12s %10u",
" RefCnt", (unsigned)ui64RefCount);
OutLine( pucTmpBuf);
}
if( ui64FldCount)
{
f_sprintf( pucTmpBuf, "%-12s %10u",
" FldCnt", (unsigned)ui64FldCount);
OutLine( pucTmpBuf);
}
if( pBlockInfo->uiNumErrors)
{
f_strcpy( pucTmpBuf, " LAST ERROR: ");
f_strcpy( &pucTmpBuf[ f_strlen( pucTmpBuf)],
FlmVerifyErrToStr( pBlockInfo->eCorruption));
OutLine( pucTmpBuf);
f_sprintf( pucTmpBuf,
" TOTAL ERRORS: %u", (unsigned)pBlockInfo->uiNumErrors);
OutLine( pucTmpBuf);
}
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void OutLogicalFile(
DB_CHECK_PROGRESS * pCheckProgress,
FLMUINT uiIndex)
{
char pucTmpBuf[ 100];
LF_STATS * pLfStats;
FLMUINT uiLoop;
pLfStats = &pCheckProgress->pLfStats[ uiIndex];
switch( pLfStats->uiLfType)
{
case LF_CONTAINER:
OutUINT( "CONTAINER", pLfStats->uiContainerNum);
break;
case LF_INDEX:
OutUINT( "INDEX", pLfStats->uiIndexNum);
OutUINT( " Index Container Number", pLfStats->uiContainerNum);
break;
}
if( !pLfStats->uiNumLevels)
{
OutUINT( " Levels", pLfStats->uiNumLevels);
}
else
{
OutBlkHeader();
for( uiLoop = 0; uiLoop < pLfStats->uiNumLevels; uiLoop++)
{
f_sprintf( pucTmpBuf, " Level %u", (unsigned)uiLoop);
if( !uiLoop)
{
OutOneBlockStat( pucTmpBuf,
pCheckProgress->uiBlockSize,
&pLfStats->pLevelInfo[ uiLoop].BlockInfo,
pLfStats->pLevelInfo[ uiLoop].ui64KeyCount,
(FLMUINT64)((pLfStats->uiLfType == LF_INDEX)
? pLfStats->ui64FldRefCount
: (FLMUINT64)0),
(FLMUINT64)((pLfStats->uiLfType == LF_INDEX)
? (FLMUINT64)0
: pLfStats->ui64FldRefCount));
}
else
{
OutOneBlockStat( pucTmpBuf,
pCheckProgress->uiBlockSize,
&pLfStats->pLevelInfo[ uiLoop].BlockInfo,
pLfStats->pLevelInfo[ uiLoop].ui64KeyCount,
(FLMUINT64)0, (FLMUINT64)0);
}
}
}
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void PrintInfo(
DB_CHECK_PROGRESS * pCheckProgress)
{
FLMUINT uiLoop;
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conClearScreen( 0, 0);
OutUINT( "Default Language", pCheckProgress->uiDefaultLanguage);
OutUINT64( "DB Size", pCheckProgress->ui64DatabaseSize);
OutUINT( "Field Count", pCheckProgress->uiNumFields);
OutUINT( "Index Count", pCheckProgress->uiNumIndexes);
OutUINT( "Non-Default Container Count", pCheckProgress->uiNumContainers);
OutUINT( "Block Size", pCheckProgress->uiBlockSize);
if( (pCheckProgress->AvailBlocks.uiBlockCount) ||
(pCheckProgress->LFHBlocks.uiBlockCount))
{
OutLine( "MISCELLANEOUS BLOCK STATISTICS");
OutBlkHeader();
if( pCheckProgress->AvailBlocks.uiBlockCount)
{
OutOneBlockStat( " Avail", pCheckProgress->uiBlockSize,
&pCheckProgress->AvailBlocks, 0, 0, 0);
}
if( pCheckProgress->LFHBlocks.uiBlockCount)
{
OutOneBlockStat( " LFH", pCheckProgress->uiBlockSize,
&pCheckProgress->LFHBlocks, 0, 0, 0);
}
}
for( uiLoop = 0; uiLoop < pCheckProgress->uiNumLogicalFiles; uiLoop++)
{
OutLogicalFile( pCheckProgress, uiLoop);
}
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC FLMUINT CheckShowError(
const char * pucMessage,
FLMBOOL bLogIt)
{
FLMUINT uiResKey;
f_sprintf( gv_pucLastError, "%s", pucMessage);
if( bLogIt)
{
LogString( pucMessage);
}
if( gv_bBatchMode)
{
uiResKey = 0;
}
else
{
f_conSetCursorPos( 0, (FLMUINT)(gv_uiMaxRow - 2));
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conClearScreen( 0, (FLMUINT)(gv_uiMaxRow - 2));
f_conSetBackFore( FLM_RED, FLM_WHITE);
f_conStrOut( pucMessage);
f_conSetCursorPos( 0, (FLMUINT)(gv_uiMaxRow - 1));
f_conStrOut( "Press ENTER to continue, ESC to quit");
for( ;;)
{
if( gv_bShutdown)
{
uiResKey = FKB_ESCAPE;
break;
}
else if( f_conHaveKey())
{
uiResKey = f_conGetKey();
if( (uiResKey == FKB_ENTER) || (uiResKey == FKB_ESCAPE))
{
break;
}
}
}
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conClearScreen( 0, (FLMUINT)(gv_uiMaxRow - 2));
}
return( uiResKey);
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void OutLabel(
FLMUINT uiCol,
FLMUINT uiRow,
const char * pucLabel,
const char * pucValue,
FLMUINT64 ui64NumValue,
FLMBOOL bLogIt)
{
char pucTmpBuf[ 100];
FLMUINT uiLoop;
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conStrOutXY( pucLabel, uiCol, uiRow);
for( uiLoop = f_conGetCursorColumn(); uiLoop < VALUE_COLUMN - 1; uiLoop++)
{
f_conStrOut( ".");
}
if( pucValue != NULL)
{
DisplayValue( uiRow, pucValue);
}
else
{
DisplayNumValue( uiRow, ui64NumValue);
}
if( (bLogIt) && (gv_bLoggingEnabled))
{
f_strcpy( pucTmpBuf, pucLabel);
f_strcpy( &pucTmpBuf[ f_strlen( pucTmpBuf)], ": ");
if( pucValue != NULL)
{
f_strcpy( &pucTmpBuf[ f_strlen( pucTmpBuf)], pucValue);
}
else
{
f_sprintf( (&pucTmpBuf[ f_strlen( pucTmpBuf)]),
"%u", (unsigned)ui64NumValue);
}
LogString( pucTmpBuf);
}
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void DisplayValue(
FLMUINT uiRow,
const char * pucValue)
{
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conStrOutXY( pucValue, VALUE_COLUMN, uiRow);
f_conClearLine( 255, 255);
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void DisplayNumValue(
FLMUINT uiRow,
FLMUINT64 ui64Number)
{
FLMUINT uiDigit;
char pucTmpBuf[ 80];
char pucDisplayBuf[ 80];
FLMUINT uiOffset;
FLMUINT64 ui64Tmp;
FLMUINT uiLen;
ui64Tmp = ui64Number;
uiOffset = 0;
do
{
uiDigit = (FLMUINT)(ui64Tmp % (FLMUINT64)10);
ui64Tmp /= (FLMUINT64)10;
pucTmpBuf[ uiOffset++] = (FLMBYTE)(uiDigit + NATIVE_ZERO);
} while( ui64Tmp);
pucTmpBuf[ uiOffset] = 0;
uiLen = uiOffset;
f_memset( pucDisplayBuf, NATIVE_SPACE, sizeof( pucDisplayBuf));
uiOffset = 0;
while( uiLen)
{
pucDisplayBuf[ uiOffset++] = pucTmpBuf[ --uiLen];
}
pucDisplayBuf[ 16] = 0;
f_sprintf( pucTmpBuf, " 0x%08X%08X",
(unsigned)(ui64Number >> 32),
(unsigned)(ui64Number & (FLMUINT64)0xFFFFFFFF));
f_strcat( &pucDisplayBuf[ 16], pucTmpBuf);
DisplayValue( uiRow, pucDisplayBuf);
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC RCODE GetUserInput( void)
{
FLMUINT uiChar;
f_conSetCursorPos( 0, (FLMUINT)(gv_uiMaxRow - 1));
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conClearScreen( 0, (FLMUINT)(gv_uiMaxRow - 1));
f_conSetBackFore( FLM_RED, FLM_WHITE);
f_conStrOut( "Q,ESC=Quit, Other=Continue");
for( ;;)
{
if( gv_bShutdown)
{
uiChar = FKB_ESCAPE;
break;
}
else if( f_conHaveKey())
{
uiChar = f_conGetKey();
break;
}
}
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conClearScreen( 0, (FLMUINT)(gv_uiMaxRow - 1));
switch( uiChar)
{
case 'q':
case 'Q':
case FKB_ESCAPE:
return( RC_SET( FERR_FAILURE));
default:
break;
}
return( FERR_OK);
}
/********************************************************************
Desc:
*********************************************************************/
RCODE ProgFunc(
eStatusType eStatus,
void * Parm1,
void * Parm2,
void * pvAppData)
{
RCODE rc = FERR_OK;
DB_CHECK_PROGRESS * pProgress;
DB_COPY_INFO * pDbCopyInfo;
CORRUPT_INFO * pCorrupt;
FLM_MEM_INFO memInfo;
char pucWhat[ 256];
char pucLfName[ 128];
F_UNREFERENCED_PARM( pvAppData);
FlmGetMemoryInfo( &memInfo);
DisplayNumValue( CACHE_USED_ROW, memInfo.BlockCache.uiTotalBytesAllocated +
memInfo.RecordCache.uiTotalBytesAllocated);
if (eStatus == FLM_DB_COPY_STATUS)
{
if( gv_bShutdown)
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
pDbCopyInfo = (DB_COPY_INFO *)Parm1;
if (pDbCopyInfo->bNewSrcFile)
{
gv_ui64DatabaseSize = pDbCopyInfo->ui64BytesToCopy;
DisplayNumValue( DB_SIZE_ROW, (FLMUINT)gv_ui64DatabaseSize);
f_sprintf( pucWhat, "SAVING FILE: %s",
pDbCopyInfo->szSrcFileName);
DisplayValue( DOING_ROW, pucWhat);
}
OutLabel( LABEL_COLUMN, AMOUNT_DONE_ROW, "Bytes Saved",
NULL, pDbCopyInfo->ui64BytesCopied, FALSE);
goto Exit;
}
else if (eStatus == FLM_PROBLEM_STATUS)
{
FLMBOOL * pbFixCorruptions = (FLMBOOL *)Parm2;
pCorrupt = (CORRUPT_INFO *)Parm1;
if( (gv_bLoggingEnabled) &&
((gv_bShowStats) ||
(pCorrupt->eCorruption != FLM_OLD_VIEW)))
{
LogCorruptError( pCorrupt);
}
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
if( pCorrupt->eCorruption == FLM_OLD_VIEW)
{
gv_uiOldViewCount++;
DisplayNumValue( OLD_VIEW_ROW, gv_uiOldViewCount);
}
else
{
gv_uiCorruptCount++;
gv_uiTotalCorruptions++;
DisplayNumValue( CORRUPT_ROW, gv_uiCorruptCount);
DisplayNumValue( TOTAL_CORRUPT_ROW, gv_uiTotalCorruptions);
}
if (pbFixCorruptions)
{
*pbFixCorruptions = gv_bRepairCorruptions;
}
}
else if (eStatus == FLM_CHECK_STATUS)
{
pProgress = (DB_CHECK_PROGRESS *)Parm1;
if( gv_bShutdown)
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
// Update the display first
gv_ui64BytesDone = pProgress->ui64BytesExamined;
DisplayNumValue( TOTAL_KEYS_ROW, pProgress->ui64NumKeys);
DisplayNumValue( TOTAL_KEYS_EXAM_ROW, pProgress->ui64NumKeysExamined);
DisplayNumValue( CONFLICT_ROW, pProgress->ui64NumConflicts);
DisplayNumValue( BAD_IXREF_ROW, pProgress->ui64NumKeysNotFound);
DisplayNumValue( MISSING_IXREF_ROW, pProgress->ui64NumRecKeysNotFound);
DisplayNumValue( NONUNIQUE_ROW, pProgress->ui64NumNonUniqueKeys);
DisplayNumValue( REPAIR_ROW, pProgress->uiNumProblemsFixed);
gv_uiRepairCount = pProgress->uiNumProblemsFixed;
if( pProgress->iCheckPhase == CHECK_RS_SORT)
{
FLMUINT uiPercent = 0;
if( pProgress->ui64NumRSUnits > (FLMUINT64)0)
{
uiPercent =
(FLMUINT)((pProgress->ui64NumRSUnitsDone * (FLMUINT64)100) /
pProgress->ui64NumRSUnits);
}
OutLabel( LABEL_COLUMN, AMOUNT_DONE_ROW, "Percent Sorted",
NULL, uiPercent, FALSE);
}
else
{
OutLabel( LABEL_COLUMN, AMOUNT_DONE_ROW, "Bytes Checked",
NULL, gv_ui64BytesDone, FALSE);
}
if( pProgress->bStartFlag)
{
gv_ui64DatabaseSize = pProgress->ui64DatabaseSize;
DisplayNumValue( DB_SIZE_ROW, gv_ui64DatabaseSize);
switch( pProgress->iCheckPhase)
{
case CHECK_LFH_BLOCKS:
f_strcpy( pucWhat, "LFH BLOCKS");
break;
case CHECK_B_TREE:
*pucLfName = '\0';
if( pProgress->uiLfType == LF_INDEX)
{
if( pProgress->bUniqueIndex)
{
f_strcpy( pucWhat, "UNIQUE INDEX: ");
}
else
{
f_strcpy( pucWhat, "INDEX: ");
}
NumToName( pProgress->uiLfNumber, pucLfName);
}
else if( pProgress->uiLfType == LF_CONTAINER)
{
f_strcpy( pucWhat, "CONTAINER: ");
NumToName( pProgress->uiLfNumber, pucLfName);
}
else
{
f_strcpy( pucWhat, "DICT CONTAINER: ");
NumToName( pProgress->uiLfNumber, pucLfName);
}
f_strcpy( &pucWhat[ f_strlen( pucWhat)], pucLfName);
f_sprintf( (&pucWhat[ f_strlen( pucWhat)]), " (%u)",
(unsigned)pProgress->uiLfNumber);
pucWhat[ 50] = '\0';
break;
case CHECK_AVAIL_BLOCKS:
f_strcpy( pucWhat, "AVAIL BLOCKS");
break;
case CHECK_RS_SORT:
f_sprintf( pucWhat, "SORTING INDEX KEYS");
break;
default:
break;
}
pucWhat[ 45] = '\0';
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
DisplayValue( DOING_ROW, pucWhat);
}
else if( (f_conHaveKey()) && (f_conGetKey() == FKB_ESCAPE))
{
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
f_conSetCursorPos( 0, (FLMUINT)(gv_uiMaxRow - 2));
f_conClearScreen( 0, (FLMUINT)(gv_uiMaxRow - 2));
f_conSetBackFore( FLM_RED, FLM_WHITE);
f_conStrOut( "ESCAPE key pressed.\n");
rc = GetUserInput();
f_conClearScreen( 0, (FLMUINT)(gv_uiMaxRow - 2));
f_conSetBackFore( FLM_BLUE, FLM_WHITE);
goto Exit;
}
}
Exit:
return( rc);
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void LogStr(
FLMUINT uiIndent,
const char * pucStr)
{
FLMUINT uiLoop;
if( gv_bLoggingEnabled)
{
for( uiLoop = 0; uiLoop < uiIndent; uiLoop++)
{
gv_pucLogBuffer[ gv_uiLogBufferCount++] = ' ';
if( gv_uiLogBufferCount == MAX_LOG_BUFF)
{
LogFlush();
}
}
LogString( pucStr);
}
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void LogCorruptError(
CORRUPT_INFO * pCorrupt)
{
char pucWhat[ 20];
char pucTmpBuf[ 100];
switch( pCorrupt->eErrLocale)
{
case LOCALE_LFH_LIST:
LogStr( 0, "ERROR IN LFH LINKED LIST:");
break;
case LOCALE_AVAIL_LIST:
LogStr( 0, "ERROR IN AVAIL LINKED LIST:");
break;
case LOCALE_B_TREE:
if( pCorrupt->eCorruption == FLM_OLD_VIEW)
{
LogStr( 0, "OLD VIEW");
}
else
{
if( pCorrupt->uiErrFieldNum)
{
f_strcpy( pucWhat, "FIELD");
}
else if( pCorrupt->uiErrElmOffset)
{
f_strcpy( pucWhat, "ELEMENT");
}
else if( pCorrupt->uiErrBlkAddress)
{
f_strcpy( pucWhat, "BLOCK");
}
else
{
f_strcpy( pucWhat, "LAST BLOCK");
}
f_sprintf( pucTmpBuf, "BAD %s", pucWhat);
LogStr( 0, pucTmpBuf);
}
// Log the logical file number, name, and type
f_sprintf( pucTmpBuf, "Logical File Number: %u",
(unsigned)pCorrupt->uiErrLfNumber);
LogStr( 2, pucTmpBuf);
switch( pCorrupt->uiErrLfType)
{
case LF_CONTAINER:
f_strcpy( pucWhat, "Container");
break;
case LF_INDEX:
f_strcpy( pucWhat, "Index");
break;
default:
f_sprintf( pucWhat, "?%u", (unsigned)pCorrupt->uiErrLfType);
break;
}
f_sprintf( pucTmpBuf, "Logical File Type: %s", pucWhat);
LogStr( 2, pucTmpBuf);
// Log the level in the B-Tree, if known
if( pCorrupt->uiErrBTreeLevel != 0xFF)
{
f_sprintf( pucTmpBuf, "Level in B-Tree: %u",
(unsigned)pCorrupt->uiErrBTreeLevel);
LogStr( 2, pucTmpBuf);
}
break;
case LOCALE_IXD_TBL:
f_sprintf( pucTmpBuf, "ERROR IN IXD TABLE, Index Number: %u",
(unsigned)pCorrupt->uiErrLfNumber);
LogStr( 0, pucTmpBuf);
break;
case LOCALE_INDEX:
f_strcpy( pucWhat, "Index");
LogKeyError( pCorrupt);
break;
default:
pCorrupt->eErrLocale = LOCALE_NONE;
break;
}
// Log the block address, if known
if( pCorrupt->uiErrBlkAddress)
{
f_sprintf( pucTmpBuf, "Block Address: 0x%08X (%u)",
(unsigned)pCorrupt->uiErrBlkAddress,
(unsigned)pCorrupt->uiErrBlkAddress);
LogStr( 2, pucTmpBuf);
}
// Log the parent block address, if known
if( pCorrupt->uiErrParentBlkAddress)
{
if( pCorrupt->uiErrParentBlkAddress != 0xFFFFFFFF)
{
f_sprintf( pucTmpBuf, "Parent Block Address: 0x%08X (%u)",
(unsigned)pCorrupt->uiErrParentBlkAddress,
(unsigned)pCorrupt->uiErrParentBlkAddress);
}
else
{
f_sprintf( pucTmpBuf,
"Parent Block Address: NONE, Root Block");
}
LogStr( 2, pucTmpBuf);
}
// Log the element offset, if known
if( pCorrupt->uiErrElmOffset)
{
f_sprintf( pucTmpBuf, "Element Offset: %u",
(unsigned)pCorrupt->uiErrElmOffset);
}
// Log the record number, if known
if( pCorrupt->uiErrDrn)
{
f_sprintf( pucTmpBuf,
"Record Number: %u", (unsigned)pCorrupt->uiErrDrn);
LogStr( 2, pucTmpBuf);
}
// Log the offset within the element record, if known
if( pCorrupt->uiErrElmRecOffset != 0xFFFF)
{
f_sprintf( pucTmpBuf, "Offset Within Element: %u",
(unsigned)pCorrupt->uiErrElmRecOffset);
LogStr( 2, pucTmpBuf);
}
// Log the field number, if known
if( pCorrupt->uiErrFieldNum)
{
f_sprintf( pucTmpBuf,
"Field Number: %u", (unsigned)pCorrupt->uiErrFieldNum);
LogStr( 2, pucTmpBuf);
}
f_strcpy( pucTmpBuf, FlmVerifyErrToStr( pCorrupt->eCorruption));
f_sprintf( (&pucTmpBuf[ f_strlen( pucTmpBuf)]), " (%d)",
(int)pCorrupt->eCorruption);
LogStr( 2, pucTmpBuf);
LogStr( 0, NULL);
if( gv_bLoggingEnabled)
{
gv_pLogFile->flush();
}
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void LogKeyError(
CORRUPT_INFO * pCorrupt
)
{
FLMUINT uiLogItem;
FlmRecord * pRecord = NULL;
void * pvField;
REC_KEY * pTempKeyList = NULL;
FLMUINT uiIndent;
FLMUINT uiLevelOffset;
char pucNameBuf[ 200];
char pucTmpBuf[ 200];
NumToName( pCorrupt->uiErrLfNumber, pucNameBuf);
LogString( NULL);
LogString( NULL);
f_sprintf( pucTmpBuf, "ERROR IN INDEX: %s", pucNameBuf);
LogString( pucTmpBuf);
uiLogItem = 'R';
uiLevelOffset = 0;
for( ;;)
{
uiIndent = 2;
if( uiLogItem == 'K')
{
if( (pRecord = pCorrupt->pErrIxKey) == NULL)
{
uiLogItem = 'L';
continue;
}
LogString( NULL);
LogString( " PROBLEM KEY");
}
else if( uiLogItem == 'R')
{
if( (pRecord = pCorrupt->pErrRecord) == NULL)
{
uiLogItem = 'K';
continue;
}
LogString( NULL);
LogString( " RECORD");
}
else if( uiLogItem == 'L')
{
if( (pTempKeyList =
pCorrupt->pErrRecordKeyList) == NULL)
{
break;
}
pRecord = pTempKeyList->pKey;
LogString( NULL);
LogString( " RECORD KEYS");
LogString( " 0 Key");
uiLevelOffset = 1;
}
for ( pvField = pRecord->root();;)
{
if (!pvField)
{
if (uiLogItem != 'L')
break;
if ((pTempKeyList = pTempKeyList->pNextKey) == NULL)
break;
pRecord = pTempKeyList->pKey;
pvField = pRecord->root();
LogString( " 0 Key");
continue;
}
else
{
DisplayField( pRecord, pvField, uiIndent, uiLevelOffset);
}
pvField = pRecord->next( pvField);
}
if( uiLogItem == 'L')
{
break;
}
else if( uiLogItem == 'R')
{
uiLogItem = 'K';
}
else
{
uiLogItem = 'L';
}
}
}
/***************************************************************************
Desc: This routine displays a field to the screen.
*****************************************************************************/
FSTATIC FLMBOOL DisplayField(
FlmRecord * pRecord,
void * pvField,
FLMUINT uiStartCol,
FLMUINT uiLevelOffset)
{
char pucTmpBuf[ 200];
FLMUINT uiLoop;
FLMUINT uiLen;
FLMUINT uiBinLen;
FLMUINT uiTmpLen;
char * pucTmp;
char ucTmpBin [80];
FLMUINT uiNum;
FLMUINT uiLevel = pRecord->getLevel( pvField) + uiLevelOffset;
FLMUINT uiIndent = (uiLevel * 2) + uiStartCol;
// Insert leading spaces to indent for level
for( uiLoop = 0; uiLoop < uiIndent; uiLoop++)
{
pucTmpBuf[ uiLoop] = ' ';
}
// Output level and tag
f_sprintf( (&pucTmpBuf[ uiIndent]), "%u ", (unsigned)uiLevel);
NumToName( pRecord->getFieldID( pvField), &pucTmpBuf[ f_strlen( pucTmpBuf)]);
// Output what will fit of the value on the rest of the line
uiLen = f_strlen( pucTmpBuf);
pucTmpBuf[ uiLen++] = ' ';
pucTmpBuf[ uiLen] = 0;
if (!pRecord->getDataLength( pvField))
{
goto Exit;
}
switch( pRecord->getDataType( pvField))
{
case FLM_TEXT_TYPE:
pucTmp = &pucTmpBuf[ uiLen];
uiLen = 80 - uiLen;
pRecord->getNative( pvField, pucTmp, &uiLen);
break;
case FLM_NUMBER_TYPE:
pRecord->getUINT( pvField, &uiNum);
f_sprintf( (&pucTmpBuf [uiLen]), "%u", (unsigned)uiNum);
break;
case FLM_BINARY_TYPE:
pRecord->getBinaryLength( pvField, &uiBinLen);
uiTmpLen = sizeof( ucTmpBin);
pRecord->getBinary( pvField, ucTmpBin, &uiTmpLen);
pucTmp = &ucTmpBin [0];
while (uiBinLen && uiLen < 77)
{
f_sprintf( &pucTmpBuf [uiLen], "%02X ", (unsigned)*pucTmp);
uiBinLen--;
pucTmp++;
uiLen += 3;
}
pucTmpBuf [uiLen - 1] = 0;
break;
case FLM_CONTEXT_TYPE:
pRecord->getUINT( pvField, &uiNum);
f_sprintf( (&pucTmpBuf[ uiLen]), "@%u@", (unsigned)uiNum);
break;
}
Exit:
LogString( pucTmpBuf);
return( TRUE);
}
/********************************************************************
Desc:
*********************************************************************/
FSTATIC void NumToName(
FLMUINT uiNum,
char * pucBuf)
{
if( !gv_pNameTable ||
!gv_pNameTable->getFromTagNum( uiNum, NULL, pucBuf, 128))
{
f_sprintf( pucBuf, "#%u", (unsigned)uiNum);
}
}