//------------------------------------------------------------------------- // 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] : "", 0, TRUE); OutLabel( LABEL_COLUMN, RFL_DIR_ROW, "RFL Files Dir.", gv_szRflDir [0] ? &gv_szRflDir [0] : "", 0, TRUE); OutLabel( LABEL_COLUMN, LOG_FILE_ROW, "Log File", (gv_pucLogFileName[ 0]) ? &gv_pucLogFileName[ 0] : "", 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 [Options]\n"); } else { f_conStrOut( "Parameters: [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 = RFL directory.\n"); f_conStrOut( " -dd = Data directory.\n"); f_conStrOut( " -i = Perform a logical (index) check.\n"); f_conStrOut( " -l = Log detailed information to .\n"); f_conStrOut( " -m = Multiple passes (continuous check).\n"); f_conStrOut( " -o = Output binary log information to .\n"); f_conStrOut( " -p = Pause before exiting.\n"); f_conStrOut( " -pw= Open database with password.\n"); f_conStrOut( " -t = Temporary directory.\n"); f_conStrOut( " -u = Run check in an update transaction.\n"); f_conStrOut( " -v = Verify binary log information in . 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); } }