551 lines
17 KiB
C++
551 lines
17 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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 <pch.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <proprec.hxx>
|
|
#include <propdesc.hxx>
|
|
|
|
|
|
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;
|
|
}
|