//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1998 // // File: main.cxx // // Contents: Index Server V1.x property file dumper. // // History: 29 Oct 1996 KyleP Created // //-------------------------------------------------------------------------- #include #pragma hdrstop #include #include DECLARE_INFOLEVEL(ci) unsigned const SixtyFourK = 1024 * 64; unsigned const cMaxFields = 10; unsigned fVerbose = 0; enum eRecType { Virgin, Top, Overflow, Free }; struct SmallInfo { ULONG Type; ULONG Length; ULONG ulPrev; ULONG ulNext; ULONG ulChainLength; }; int __cdecl main( int argc, char * argv[] ) { char * pszFile = argv[1]; BOOL fReadMetadata = 0; unsigned cField = 0; int aiField[cMaxFields]; for ( int i = 1; i < argc; i++ ) { if ( argv[i][0] == '-' ) { switch ( argv[i][1] ) { case 'v': case 'V': fVerbose = 1; break; case 'm': case 'M': fReadMetadata = TRUE; break; case 'f': case 'F': i++; if ( cField < cMaxFields ) aiField[cField++] = strtol( argv[i], 0, 10 ); break; } } else pszFile = argv[i]; } BYTE abTemp[SixtyFourK]; // // First, read out the metadata // unsigned cFixed = 0; unsigned cTotal = 0; unsigned culFixed = 0; CPropDesc aFieldRec[cMaxFields]; if ( fReadMetadata || cField != 0 ) { // // Build path. // char szPath[MAX_PATH]; strcpy( szPath, pszFile ); char * pLastSlash = strrchr( szPath, '\\' ); pLastSlash++; strcpy( pLastSlash, "CIPS0000.001" ); HANDLE h = CreateFileA( szPath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0 ); if ( INVALID_HANDLE_VALUE == h ) { printf( "Can't open file %s. Error %u\n", szPath, GetLastError() ); return 0; } ULONG cbRead; if ( ReadFile( h, abTemp, sizeof(abTemp), &cbRead, 0 ) ) { // // Loop through records // CPropDesc * pPropDesc = (CPropDesc *)abTemp; if ( fReadMetadata ) printf( "Record\tPid\t\tType\t\tOffset\tSize\tOrdinal\tMask\n" ); for ( unsigned i = 0; i < cbRead/sizeof(CPropDesc); i++, pPropDesc++ ) { if ( pPropDesc->Pid() != 0 ) { if ( fReadMetadata ) printf( "%u:\t%u (0x%x)%s\t%u (0x%x)\t%d\t%u\t%u\t0x%x\n", pPropDesc->Record(), pPropDesc->Pid(), pPropDesc->Pid(), (pPropDesc->Pid() > 10) ? "" : "\t", pPropDesc->Type(), pPropDesc->Type(), pPropDesc->Offset(), pPropDesc->Size(), pPropDesc->Ordinal(), pPropDesc->Mask() ); cTotal++; if ( pPropDesc->Offset() != -1 ) { cFixed++; culFixed += (pPropDesc->Size() / sizeof(DWORD)); } for ( unsigned j = 0; j < cField; j++ ) { if ( aiField[j] == (int)pPropDesc->Record() ) memcpy( &aFieldRec[j], pPropDesc, sizeof(aFieldRec[0]) ); } } } printf( "\n%u Properties, %u Fixed totaling %u bytes\n\n", cTotal, cFixed, culFixed * sizeof(DWORD) ); } else { printf( "Can't read file %s. Error %u\n", szPath, GetLastError() ); return 0; } } HANDLE h = CreateFileA( pszFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0 ); if ( INVALID_HANDLE_VALUE == h ) { printf( "Can't open file %s. Error %u\n", pszFile, GetLastError() ); return 0; } BY_HANDLE_FILE_INFORMATION fi; if ( !GetFileInformationByHandle( h, &fi ) ) { printf( "Error %u getting size from handle\n", GetLastError() ); return 0; } ULONG oFile = 0; ULONG cbRec = 0; ULONG cRecPerBuf; ULONG cRecTotal; ULONG cTotalSections = 0; HANDLE hSmallInfo; SmallInfo * aSmallInfo = 0; ULONG iSection = 0; BOOL fFirst = TRUE; ULONG iCurrentPct = 0; for (;;) { ULONG cbRead; if ( ReadFile( h, abTemp, sizeof(abTemp), &cbRead, 0 ) ) { if (fVerbose) printf( "READ: 0x%x bytes, offset %0x%x\n", cbRead, oFile ); if ( 0 == cbRead ) break; if ( fFirst ) { // // Determine record size // if ( abTemp[0] != 0 || abTemp[1] != 0 ) { printf( "Record 0 not blank. File corrupt!\n" ); break; } for ( unsigned i = 0; i < cbRead && abTemp[i] == 0; i++ ) continue; if ( i == cbRead ) { printf( "First %uK segment all zero!. File corrupt!\n", sizeof(abTemp)/1024 ); break; } switch ( *(USHORT *)&abTemp[i] ) { case 0x5555: case 0xAAAA: case 0xBBBB: cbRec = i; if ( cbRec % 4 != 0 ) { printf( "Record size (%u bytes) not DWORD aligned!\n\n", cbRec ); return 0; } cRecPerBuf = sizeof(abTemp) / cbRec; printf( "Record size: %u bytes (%u / %uK)\n", i, cRecPerBuf, sizeof(abTemp)/1024 ); cTotalSections = (fi.nFileSizeLow + sizeof(abTemp) - 1)/ sizeof abTemp; hSmallInfo = LocalAlloc( LMEM_MOVEABLE, ((fi.nFileSizeLow / sizeof(abTemp)) + 1) * cRecPerBuf * sizeof(SmallInfo) ); aSmallInfo = (SmallInfo *)LocalLock( hSmallInfo ); break; default: printf( "First non-zero byte is not a proper signature (%u)!\n", *(SHORT *)&abTemp[i] ); return 0; } fFirst = FALSE; } ULONG iRec = 0; while ( iRec < cRecPerBuf ) { COnDiskPropertyRecord * pRec = new( iRec, abTemp, cbRec/4 ) COnDiskPropertyRecord; if ( !pRec->IsValidType() ) { printf( "Record 0x%x (%u:%u) (file offset 0x%x) is corrupt!\n", iSection * cRecPerBuf + iRec, iSection, iRec, iSection * sizeof(abTemp) + iRec * cbRec ); } if (fVerbose ) printf( "%u:%u, %s, length = %u record(s)", iSection, iRec, pRec->IsTopLevel() ? "Top Level" : pRec->IsOverflow() ? "Overflow" : pRec->IsFreeRecord() ? "Free" : "Virgin", pRec->CountRecords() ); aSmallInfo[iSection*cRecPerBuf + iRec].ulChainLength = 0; if ( pRec->IsOverflow() ) { aSmallInfo[iSection*cRecPerBuf + iRec].Type = Overflow; /* printf( ", Previous = %u:%u (file offset 0x%x)", pRec->PreviousBlock() / cRecPerBuf, pRec->PreviousBlock() % cRecPerBuf, (pRec->PreviousBlock() / cRecPerBuf) * sizeof(abTemp) + (pRec->PreviousBlock() % cRecPerBuf) * cbRec ); */ } else if ( pRec->IsTopLevel() ) { aSmallInfo[iSection*cRecPerBuf + iRec].Type = Top; aSmallInfo[iSection*cRecPerBuf + iRec].ulChainLength = pRec->GetOverflowChainLength(); for ( unsigned j = 0; j < cField; j++ ) { PROPVARIANT var; BYTE abExtra[MAX_PATH * 5]; unsigned cbExtra = sizeof(abExtra); if ( 0 == j ) printf( "%6u: ", iSection*cRecPerBuf + iRec ); if ( aFieldRec[j].IsFixedSize() ) { pRec->ReadFixed( aFieldRec[j].Ordinal(), aFieldRec[j].Mask(), aFieldRec[j].Offset(), cTotal, aFieldRec[j].Type(), var, abExtra, &cbExtra ); switch ( var.vt ) { case VT_EMPTY: printf( "n/a " ); break; case VT_I4: printf( "%8d ", var.iVal ); break; case VT_UI4: printf( "%8u ", var.uiVal ); break; case VT_FILETIME: printf( "%8u,%8u ", var.filetime.dwHighDateTime, var.filetime.dwLowDateTime ); break; case VT_I8: printf( "%12hu ", var.hVal ); break; } } else { BOOL fOk = pRec->ReadVariable( aFieldRec[j].Ordinal(), aFieldRec[j].Mask(), culFixed, cTotal, cFixed, var, abExtra, &cbExtra ); if ( fOk ) { switch ( var.vt ) { case VT_LPSTR: printf( "%s ", var.pszVal ); break; case VT_LPWSTR: printf( "%ws ", var.pwszVal ); break; } } } } if ( 0 != cField ) printf( "\n" ); } else if ( pRec->IsFreeRecord() ) { aSmallInfo[iSection*cRecPerBuf + iRec].Type = Free; } else { aSmallInfo[iSection*cRecPerBuf + iRec].Type = Virgin; } // 1.1 vs 2.0 change // aSmallInfo[iSection*cRecPerBuf + iRec].ulPrev = pRec->ToplevelBlock(); aSmallInfo[iSection*cRecPerBuf + iRec].ulNext = pRec->OverflowBlock(); aSmallInfo[iSection*cRecPerBuf + iRec].Length = pRec->CountRecords(); if ( pRec->CountRecords() == 0 ) { printf( "Record %u (file offset 0x%x) is zero length!\n", iSection * cRecPerBuf + iRec, iSection * sizeof(abTemp) + iRec * cbRec ); } if ( pRec->OverflowBlock() != 0 ) { /* printf( ", Overflow = %u:%u (file offset 0x%x)", pRec->OverflowBlock() / cRecPerBuf, pRec->OverflowBlock() % cRecPerBuf, (pRec->OverflowBlock() / cRecPerBuf) * sizeof(abTemp) + (pRec->OverflowBlock() % cRecPerBuf) * cbRec ); */ } if (fVerbose) printf( "\n" ); if ( pRec->IsValidType() ) iRec += pRec->CountRecords(); else iRec++; ULONG iPct = (iSection * (100/5) / cTotalSections) * 5; if (iPct != iCurrentPct) { iCurrentPct = iPct; printf( "Read %u%%\n", iCurrentPct ); } } iSection++; oFile += cbRead; } else { ULONG Status = GetLastError(); if ( Status == ERROR_HANDLE_EOF ) break; else { printf( "Error %u reading file.\n", Status ); } } } printf( "Read 100%%\n" ); CloseHandle( h ); // // Now check inter-record state // unsigned iRec = 0; unsigned iCurrentSection = 0; iCurrentPct = 0; while ( iRec < iSection * cRecPerBuf ) { if ( aSmallInfo[iRec].Type == Top ) { unsigned iOverflowRec = aSmallInfo[iRec].ulNext; unsigned cOverflowRec = 0; while ( 0 != iOverflowRec ) { if ( aSmallInfo[iOverflowRec].Type != Overflow ) { printf( "Record 0x%x (%u:%u) (file offset 0x%x) should be overflow and is not!\n Top level = 0x%x (%u:%u) (file offset 0x%x)\n", iOverflowRec, iOverflowRec / cRecPerBuf, iOverflowRec % cRecPerBuf, (iOverflowRec / cRecPerBuf) * sizeof(abTemp) + (iOverflowRec % cRecPerBuf) * cbRec, iRec, iRec / cRecPerBuf, iRec % cRecPerBuf, (iRec / cRecPerBuf) * sizeof(abTemp) + (iRec % cRecPerBuf) * cbRec ); break; } iOverflowRec = aSmallInfo[iOverflowRec].ulNext; cOverflowRec++; if ( cOverflowRec > aSmallInfo[iRec].ulChainLength ) break; } if ( aSmallInfo[iRec].ulChainLength != cOverflowRec ) { printf( "Record 0x%x (%u:%u) (file offset 0x%x) chain length mismatch %d,%d!\n", iRec, iRec / cRecPerBuf, iRec % cRecPerBuf, (iRec / cRecPerBuf) * sizeof(abTemp) + (iRec % cRecPerBuf) * cbRec, aSmallInfo[iRec].ulChainLength, cOverflowRec ); } } if (aSmallInfo[iRec].Length == 0) { printf( "%u:%u (file offset 0x%x) zero length record!\n", iRec / cRecPerBuf, iRec % cRecPerBuf, (iRec / cRecPerBuf) * sizeof(abTemp) + (iRec % cRecPerBuf) * cbRec ); iRec++; } else { iRec += aSmallInfo[iRec].Length; } if ( (iRec / cRecPerBuf) != iCurrentSection ) { if (fVerbose) printf( "Checked section %u\n", iCurrentSection ); ULONG iPct = (iCurrentSection * (100/5) / iSection) * 5; if (iPct != iCurrentPct) { iCurrentPct = iPct; printf( "Checked %u%%\n", iCurrentPct ); } iCurrentSection = (iRec / cRecPerBuf); } } printf( "Checked 100%%\n" ); LocalUnlock( hSmallInfo ); LocalFree( hSmallInfo ); return 0; }