2025-04-27 07:49:33 -04:00

299 lines
7.7 KiB
C++

#include <windows.h>
#include <stdio.h>
#include <wbemcomn.h>
#include <absfile.h>
#include <objheap.h>
#include <index.h>
bool g_bPause = false;
bool g_bPrintAllKeys = true;
bool g_bPrintAllBlocks = true;
void Pause()
{
if(g_bPause)
{
char ch = (char)getchar();
if(ch == 'n')
g_bPause = false;
}
}
long ParseInfoFromIndexFile(LPCSTR wszIndexFileName,
DWORD* pnOffset, DWORD* pdwLength)
{
CHAR* pDot = strchr(wszIndexFileName, L'.');
if(pDot == NULL)
return ERROR_INVALID_PARAMETER;
CHAR* pwc = pDot+1;
*pnOffset = 0;
while(*pwc && *pwc != '.')
{
*pnOffset = (*pnOffset * 10) + (*pwc - '0');
pwc++;
}
if(*pwc != '.')
return ERROR_INVALID_PARAMETER;
pwc++;
*pdwLength = 0;
while(*pwc && *pwc != '.')
{
*pdwLength = (*pdwLength * 10) + (*pwc - '0');
pwc++;
}
return ERROR_SUCCESS;
}
void __cdecl wmain(int argc, wchar_t** argv)
{
long lRes;
if(argc < 2)
{
wprintf(L"Usage: %s <repository directory>\n", argv[0]);
return;
}
CFileName wszBaseName;
wcscpy(wszBaseName, argv[1]);
wcscat(wszBaseName, L"\\");
DWORD dwBaseNameLen = wcslen(wszBaseName);
CFileName wszStagingName;
swprintf(wszStagingName, L"%sLowStage.dat", wszBaseName);
CAbstractFileSource AbstractSource;
lRes = AbstractSource.Create(wszStagingName, 0x7FFFFFFF, 0x7FFFFFFF);
if(lRes != ERROR_SUCCESS)
{
printf("Unable to create staging file: %d\n", lRes);
return;
}
CFileName wszObjHeapName;
swprintf(wszObjHeapName, L"%sObjHeap", wszBaseName);
CObjectHeap ObjectHeap;
lRes = ObjectHeap.Initialize(&AbstractSource, wszObjHeapName, argv[1], dwBaseNameLen);
if(lRes != ERROR_SUCCESS)
{
printf("Unable to initialize ObjectHeap: %d\n", lRes);
return;
}
lRes = AbstractSource.Start();
if(lRes != ERROR_SUCCESS)
{
printf("Unable to start staging file: %d\n", lRes);
return;
}
AbstractSource.Dump(stdout);
CBTree& BTree = ObjectHeap.GetIndex()->GetTree();
CBTreeIterator* pIt = NULL;
lRes = BTree.BeginEnum(NULL, &pIt);
if(lRes != ERROR_SUCCESS)
{
printf("Unable to enumerate btree: %d\n", lRes);
return;
}
std::map<DWORD, DWORD> mymap;
char* szKey = NULL;
DWORD dwTotalKeys = 0;
while(pIt->Next(&szKey) == 0)
{
dwTotalKeys++;
DWORD nStart, nLen;
lRes = ParseInfoFromIndexFile(szKey, &nStart, &nLen);
if(lRes != ERROR_SUCCESS)
{
if(strstr(szKey, "\\IL_") == NULL &&
strstr(szKey, "\\R_") == NULL &&
strstr(szKey, "\\C_") == NULL)
{
printf("Invalid key: %s\n", szKey);
Pause();
}
}
else
{
if(mymap.find(nStart) != mymap.end())
{
printf("Offset %d found twice: length %d and %d\n",
nStart, mymap[nStart], nLen);
Pause();
}
mymap[nStart] = nLen;
}
pIt->FreeString(szKey);
}
printf("%d keys in tree, %d pointers\n", dwTotalKeys, (int)mymap.size());
pIt->Release();
std::map<DWORD, DWORD>::iterator itKeys;
std::map<DWORD, DWORD> mapBadOffsets;
itKeys = mymap.begin();
CFileHeap::TFreeOffsetMap& freemap = ObjectHeap.GetFileHeap()->GetFreeOffsetMap();
CFileHeap::TFreeOffsetIterator itFree = freemap.begin();
int nCurrent = 0;
bool bLastFree = false;
DWORD dwMissingFreeCount = 0;
while(itKeys != mymap.end() && itFree != freemap.end())
{
if(itKeys->first == itFree->first)
{
printf("Offset %d is both free and used!\n", itKeys->first);
mapBadOffsets[itKeys->first] = 1;
Pause();
}
if(itKeys->first <= itFree->first)
{
if(nCurrent != 0 && itKeys->first != nCurrent)
{
printf("Hole at offset %d: key at %d, free at %d\n",
nCurrent, itKeys->first, itFree->first);
Pause();
nCurrent = itKeys->first;
}
DWORD adw[2];
ObjectHeap.GetFileHeap()->ReadBytes(itKeys->first, (BYTE*)adw, 8);
if(adw[0] != itKeys->second)
{
printf("Mismatched length at %d: index has %d, "
"heap has %d\n", itKeys->first, itKeys->second,
adw[0]);
mapBadOffsets[itKeys->first] = 1;
Pause();
}
else if(adw[1] != 0xA51A51A5)
{
printf("Missing signature from block %d: %d\n",
itKeys->first, adw[1]);
mapBadOffsets[itKeys->first] = 1;
Pause();
}
else if(g_bPrintAllBlocks)
{
printf("Used: %d (%d)\n", itKeys->first, itKeys->second);
}
nCurrent += itKeys->second + 8;
itKeys++;
bLastFree = false;
}
else
{
if(nCurrent != 0 && itFree->first != nCurrent)
{
printf("Hole at offset %d: key at %d, free at %d\n",
nCurrent, itKeys->first, itFree->first);
Pause();
nCurrent = itFree->first;
}
if(bLastFree)
{
printf("Two free blocks in a row: %d (%d)\n",
itFree->first, itFree->second);
Pause();
}
if(itFree->second >= 4)
{
DWORD dwSig;
ObjectHeap.GetFileHeap()->ReadBytes(itFree->first, (BYTE*)&dwSig, 4);
if(dwSig != 0x51515151)
{
printf("Missing free signature from block %d: %d\n",
itFree->first, dwSig);
Pause();
dwMissingFreeCount++;
}
}
if(g_bPrintAllBlocks)
printf("Free: %d (%d)\n", itFree->first, itFree->second);
nCurrent += itFree->second;
itFree++;
bLastFree = true;
}
}
if(itKeys != mymap.end())
{
printf("Last block is used!\n");
return;
}
if(itFree == freemap.end())
{
printf("Missing last free block\n");
return;
}
if(g_bPrintAllBlocks)
printf("Free: %d (%d)\n", itFree->first, itFree->second);
itFree++;
if(itFree != freemap.end())
{
printf("Two free blocks in the end!");
return;
}
printf("%d missing free signatures out of %d\n", dwMissingFreeCount,
freemap.size());
lRes = BTree.BeginEnum(NULL, &pIt);
if(lRes != ERROR_SUCCESS)
{
printf("Unable to enumerate btree: %d\n", lRes);
return;
}
while(pIt->Next(&szKey) == 0)
{
DWORD nStart, nLen;
bool bPrint = false;
lRes = ParseInfoFromIndexFile(szKey, &nStart, &nLen);
if(lRes == ERROR_SUCCESS)
{
if(mapBadOffsets.find(nStart) != mapBadOffsets.end())
{
printf("* ");
bPrint = true;
}
}
if(bPrint || g_bPrintAllKeys)
printf("%s\n", szKey);
pIt->FreeString(szKey);
}
pIt->Release();
}