You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1904 lines
54 KiB
1904 lines
54 KiB
#include <assert.h>
|
|
#include <SymCommon.h>
|
|
|
|
#include "symutil.h"
|
|
#include "symutil_c.h"
|
|
|
|
#include "share.h"
|
|
#include "winbase.h"
|
|
#include "symsrv.h"
|
|
#include "output.hpp"
|
|
#include "PEWhack.h"
|
|
#include <string.h>
|
|
|
|
#include "strsafe.h"
|
|
|
|
|
|
|
|
// SymOutput *so;
|
|
extern pSymOutput so;
|
|
extern BOOL MSArchive;
|
|
TCHAR szPriPubBin[4] = "";
|
|
BOOL PrivateStripped=FALSE;
|
|
|
|
|
|
// Stuff for Checking symbols
|
|
|
|
// Typedefs
|
|
typedef struct _FILE_INFO {
|
|
DWORD TimeDateStamp;
|
|
DWORD CheckSum;
|
|
TCHAR szName[MAX_PATH];
|
|
} FILE_INFO, *PFILE_INFO;
|
|
|
|
BOOL
|
|
AddToReferenceCount(
|
|
LPTSTR szDir, // Directory where refs.ptr belongs
|
|
LPTSTR szFileName, // Full path and name of the file that is referenced.
|
|
LPTSTR szPtrOrFile, // Was a file or a pointer written
|
|
BOOL DeleteRefsPtr // Flag to delete current refs.ptr and start over
|
|
);
|
|
|
|
BOOL
|
|
DecidePriority(
|
|
LPTSTR szCurrentFilePtr,
|
|
LPTSTR szCandidateFilePtr,
|
|
LPTSTR szRefsDir,
|
|
PUINT choice
|
|
);
|
|
|
|
BOOL
|
|
CheckPriPub(
|
|
LPTSTR szDir,
|
|
LPTSTR szFilePtr, // Current string that is in file.ptr
|
|
LPTSTR szPubPriType // Return value - whether file.ptr is
|
|
); // a pri, pub, bin, or unknown
|
|
|
|
PCHAR
|
|
GetFileNameStart(
|
|
LPTSTR FileName
|
|
);
|
|
|
|
PIMAGE_NT_HEADERS
|
|
GetNtHeader (
|
|
PIMAGE_DOS_HEADER pDosHeader,
|
|
HANDLE hDosFile
|
|
);
|
|
|
|
BOOL
|
|
GetSymbolServerDirs(
|
|
LPTSTR szFileName,
|
|
GUID *guid,
|
|
DWORD dwNum1,
|
|
DWORD dwNum2,
|
|
LPTSTR szDirName
|
|
);
|
|
|
|
BOOL
|
|
ReadFilePtr(
|
|
LPTSTR szContents,
|
|
HANDLE hFile
|
|
);
|
|
|
|
BOOL
|
|
StoreFile(
|
|
LPTSTR szDestDir,
|
|
LPTSTR szFileName,
|
|
LPTSTR szString2,
|
|
LPTSTR szPtrFileName
|
|
);
|
|
|
|
BOOL
|
|
StoreFilePtr(
|
|
LPTSTR szDestDir,
|
|
LPTSTR szString2,
|
|
LPTSTR szPtrFileName
|
|
);
|
|
|
|
_TCHAR* _tcsistr(_TCHAR *s1, _TCHAR *s2) {
|
|
|
|
/* Do case insensitve search for string 2 in string 1.
|
|
|
|
*/
|
|
LONG i,j,k;
|
|
k = _tcslen(s2);
|
|
j = _tcslen(s1) - k + 1;
|
|
|
|
// it is not fast way, but works
|
|
|
|
for (i=0; i<j; i++)
|
|
{
|
|
if (_tcsnicmp( &s1[i], s2, k) == NULL)
|
|
{
|
|
return &s1[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOL
|
|
AddToReferenceCount(
|
|
LPTSTR szDir, // Directory where refs.ptr belongs
|
|
LPTSTR szFileName, // Full path and name of the file that is referenced.
|
|
LPTSTR szPtrOrFile, // Was a file or a pointer written
|
|
BOOL DeleteRefsPtr // Should we delete the current refs.ptr?
|
|
)
|
|
{
|
|
|
|
HANDLE hFile;
|
|
TCHAR szRefsEntry[_MAX_PATH * 3];
|
|
TCHAR szRefsFileName[_MAX_PATH + 1];
|
|
DWORD dwPtr=0;
|
|
DWORD dwError=0;
|
|
DWORD dwNumBytesToWrite=0;
|
|
DWORD dwNumBytesWritten=0;
|
|
BOOL FirstEntry = FALSE;
|
|
DWORD First;
|
|
|
|
StringCbPrintf( szRefsFileName, sizeof(szRefsFileName), "%s\\%s", szDir, _T("refs.ptr") );
|
|
|
|
// Find out if this is the first entry in the file or not
|
|
// First, try opening an existing file. If that doesn't work
|
|
// then create a new one.
|
|
|
|
First=1;
|
|
do {
|
|
FirstEntry = FALSE;
|
|
hFile = CreateFile( szRefsFileName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
if ( hFile == INVALID_HANDLE_VALUE ) {
|
|
FirstEntry = TRUE;
|
|
hFile = CreateFile( szRefsFileName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
}
|
|
|
|
// Only print a message the first time through
|
|
|
|
if ( First && hFile == INVALID_HANDLE_VALUE ) {
|
|
First = 0;
|
|
so->printf( "Trying to get write access to %s ...\n", szRefsFileName);
|
|
}
|
|
} while ( hFile == INVALID_HANDLE_VALUE);
|
|
|
|
|
|
if (DeleteRefsPtr) {
|
|
FirstEntry = TRUE;
|
|
dwPtr = SetFilePointer ( hFile,
|
|
0,
|
|
NULL,
|
|
FILE_BEGIN );
|
|
|
|
} else {
|
|
|
|
dwPtr = SetFilePointer( hFile,
|
|
0,
|
|
NULL,
|
|
FILE_END );
|
|
}
|
|
|
|
if (dwPtr == INVALID_SET_FILE_POINTER) {
|
|
// Obtain the error code.
|
|
dwError = GetLastError() ;
|
|
so->printf("Failed to set end of the file %s with GetLastError = %d\n",
|
|
szRefsFileName, dwError);
|
|
|
|
SetEndOfFile(hFile);
|
|
CloseHandle(hFile);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Put in a '\n' if this isn't the first entry
|
|
//
|
|
|
|
if ( FirstEntry ) {
|
|
StringCbPrintf( szRefsEntry,
|
|
sizeof(szRefsEntry),
|
|
"%s,%s,%s,%s,,,,",
|
|
pTrans->szId,
|
|
szPtrOrFile,
|
|
szFileName,
|
|
szPriPubBin
|
|
);
|
|
} else {
|
|
StringCbPrintf( szRefsEntry, sizeof(szRefsEntry), "\n%s,%s,%s,%s,,,,",
|
|
pTrans->szId, szPtrOrFile, szFileName, szPriPubBin
|
|
);
|
|
}
|
|
|
|
|
|
dwNumBytesToWrite = (_tcslen(szRefsEntry) ) * sizeof(TCHAR);
|
|
|
|
WriteFile( hFile,
|
|
(LPCVOID) szRefsEntry,
|
|
dwNumBytesToWrite,
|
|
&dwNumBytesWritten,
|
|
NULL
|
|
);
|
|
|
|
if ( dwNumBytesToWrite != dwNumBytesWritten ) {
|
|
so->printf( "FAILED to write %s, with GetLastError = %d\n",
|
|
szRefsEntry,
|
|
GetLastError()
|
|
);
|
|
SetEndOfFile(hFile);
|
|
CloseHandle(hFile);
|
|
return (FALSE);
|
|
}
|
|
|
|
SetEndOfFile(hFile);
|
|
CloseHandle(hFile);
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CheckPriPub(
|
|
LPTSTR szDir,
|
|
LPTSTR szFilePtr, // Current string that is in file.ptr
|
|
LPTSTR szPubPriType // Return value - whether file.ptr is
|
|
// a pri, pub, bin, or unknown
|
|
)
|
|
/*++ Figure out if the current entry is a public or private symbol
|
|
|
|
IN szDir Directory where refs.ptr should be
|
|
In szFilePtr Contents of current file.ptr
|
|
OUT szPubPriType Result equal to "pub", "pri", or "bin", according
|
|
to the pub/pri/bin field for this entry in refs.ptr.
|
|
If the entry isn't found or the entry does not have
|
|
the type of file filled in, this is the empty string.
|
|
|
|
Return value: This returns TRUE, if the file.ptr contents were found
|
|
in refs.ptr. It returns FALSE otherwise.
|
|
|
|
-- */
|
|
|
|
{
|
|
TCHAR szRefsFile[_MAX_PATH]; // Full path and name of the refs.ptr file
|
|
FILE *fRefsFile;
|
|
|
|
LPTSTR szBuf; // Used to process entries in the refs file
|
|
|
|
|
|
TCHAR *token;
|
|
TCHAR seps[] = _T(",");
|
|
|
|
BOOL rc = FALSE;
|
|
ULONG MaxLine; // Maximim length of a record in refs.ptr
|
|
DWORD len;
|
|
|
|
StringCbCopy( szPubPriType, sizeof(szPubPriType), _T("") );
|
|
|
|
StringCbPrintf(szRefsFile, sizeof(szRefsFile), "%srefs.ptr", szDir );
|
|
|
|
MaxLine = GetMaxLineOfRefsPtrFile();
|
|
szBuf = (LPTSTR) malloc( MaxLine * sizeof(TCHAR) );
|
|
if ( !szBuf ) MallocFailed();
|
|
ZeroMemory(szBuf,MaxLine*sizeof(TCHAR));
|
|
|
|
fRefsFile = _tfopen(szRefsFile, _T("r+") );
|
|
if ( fRefsFile == NULL ) {
|
|
// BARB - Check for corruption -- if the file doesn't exist,
|
|
// verify that the parent directory structure doesn't exist either
|
|
goto finish_CheckPriPub;
|
|
}
|
|
|
|
//
|
|
// Read through the refs.ptr file and gather information
|
|
//
|
|
|
|
while ( _fgetts( szBuf, MaxLine, fRefsFile) != NULL ) {
|
|
|
|
len=_tcslen(szBuf);
|
|
if ( len > 3 ) {
|
|
|
|
// See if this has a match with the current value in file.ptr
|
|
|
|
if ( _tcsistr( szBuf, szFilePtr ) != NULL ) {
|
|
rc = TRUE;
|
|
token = _tcstok(szBuf, seps); // Look at the ID
|
|
if (token) {
|
|
token = _tcstok(NULL, seps); // "file" or "ptr"
|
|
}
|
|
if (token) {
|
|
token = _tcstok(NULL, seps); // value of file.ptr
|
|
}
|
|
if (token) {
|
|
token = _tcstok(NULL, seps); // bin, pri, pub
|
|
}
|
|
if (token) {
|
|
if ( _tcsicmp( token, _T("pri"))== 0 ||
|
|
_tcsicmp( token, _T("pub"))== 0 ||
|
|
_tcsicmp( token, _T("bin"))== 0 ) {
|
|
|
|
StringCbCopy( szPubPriType, sizeof(szPubPriType), token);
|
|
goto finish_CheckPriPub;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ZeroMemory(szBuf, MaxLine*sizeof(TCHAR));
|
|
}
|
|
|
|
finish_CheckPriPub:
|
|
|
|
if ( fRefsFile != NULL)
|
|
{
|
|
fclose(fRefsFile);
|
|
}
|
|
free (szBuf);
|
|
return (rc);
|
|
}
|
|
|
|
/* Decides if the current string has priority over the
|
|
new string. This is used for deciding whether or not to add
|
|
the new string to file.ptr and refs.ptr.
|
|
|
|
There are 3 choices:
|
|
1. Add it to file.ptr and refs.ptr
|
|
2. Add it to refs.ptr, but not file.ptr
|
|
3. Don't add it at all.
|
|
|
|
IN LPTSTR current -- The current string in file.ptr
|
|
IN LPTSTR new -- The new replacement candidate for file.ptr
|
|
IN LPTSTR szRefsDir The directory where refs.ptr is
|
|
OUT choice -- SKIP_ENTIRE_ENTRY, ADD_ENTIRE_ENTRY, or ADD_ONLY_REFSPTR
|
|
|
|
*/
|
|
|
|
BOOL
|
|
DecidePriority(
|
|
LPTSTR szCurrentFilePtr,
|
|
LPTSTR szCandidateFilePtr,
|
|
LPTSTR szRefsDir,
|
|
PUINT choice
|
|
)
|
|
{
|
|
|
|
BOOL CurrentIsArch=FALSE;
|
|
BOOL NewIsArch=FALSE;
|
|
BOOL UpdateFilePtr=TRUE;
|
|
BOOL CurrentIsEnglish=FALSE;
|
|
BOOL NewIsEnglish=FALSE;
|
|
TCHAR szPubPriType[4] = "";
|
|
|
|
*choice = 0;
|
|
|
|
CurrentIsArch=(_tcsnicmp( szCurrentFilePtr, "\\\\arch\\", 7) == 0 );
|
|
NewIsArch=(_tcsnicmp( szCandidateFilePtr, "\\\\arch\\", 7) == 0 );
|
|
|
|
if ( CurrentIsArch && !NewIsArch)
|
|
{
|
|
// Don't store it
|
|
*choice = SKIP_ENTIRE_ENTRY;
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( NewIsArch && !CurrentIsArch)
|
|
{
|
|
*choice = ADD_ENTIRE_ENTRY | DELETE_REFSPTR; // Overwrite file.ptr no matter what
|
|
return(TRUE);
|
|
}
|
|
|
|
// Look at private versus public priority
|
|
|
|
if ( PubPriPriority > 0 && // We're checking private and
|
|
// public priority
|
|
CheckPriPub( szRefsDir, szCurrentFilePtr, szPubPriType ) && // There is something in current
|
|
_tcsicmp( szPubPriType, szPriPubBin ) != 0 ) // Current and candidate are not
|
|
// the same. Note: they can be
|
|
// "pub", "pri", "bin", or "null"
|
|
// because earlier index files didn't
|
|
// have a type in pub, pri, bin.
|
|
{
|
|
|
|
if ( _tcsicmp( szPubPriType, _T("")) == 0 ) // Current doesn't have types defined
|
|
{
|
|
*choice = ADD_ENTIRE_ENTRY;
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( _tcsicmp( szPriPubBin, _T("")) == 0 ) // Candidate doesn't have types defined
|
|
{
|
|
*choice = ADD_ONLY_REFSPTR;
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( ( PubPriPriority == 1 && // Give priority to public files
|
|
_tcsicmp( szPubPriType, _T("pub")) == 0 ) || // and current is a public, or
|
|
|
|
( PubPriPriority == 2 && // Give priority to private files
|
|
_tcsicmp( szPubPriType, _T("pri")) == 0 ) ) // and current is a private
|
|
{
|
|
|
|
*choice = ADD_ONLY_REFSPTR;
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( ( PubPriPriority == 1 && // Give priority to public files
|
|
_tcsicmp( szPubPriType, _T("pri")) == 0 ) || // and current is a private
|
|
|
|
( PubPriPriority == 2 && // Give priority to private files
|
|
_tcsicmp( szPubPriType, _T("pub")) == 0 ) ) // and current is a public
|
|
{
|
|
*choice = ADD_ENTIRE_ENTRY;
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
// At this point both are on the archive or both are not on the archive.
|
|
// Next, give priority to English vs. non-English. If this is non-English,
|
|
// then put it in refs.ptr, but don't update file.ptr.
|
|
|
|
|
|
if ( _tcsistr(szCurrentFilePtr,_T("\\enu\\")) != NULL ||
|
|
_tcsistr(szCurrentFilePtr,_T("\\en\\")) != NULL ||
|
|
_tcsistr(szCurrentFilePtr,_T("\\usa\\")) != NULL )
|
|
{
|
|
CurrentIsEnglish=TRUE;
|
|
}
|
|
|
|
if ( _tcsistr(szCandidateFilePtr,_T("\\enu\\")) != NULL ||
|
|
_tcsistr(szCandidateFilePtr,_T("\\en\\")) != NULL ||
|
|
_tcsistr(szCandidateFilePtr,_T("\\usa\\")) != NULL )
|
|
{
|
|
NewIsEnglish=TRUE;
|
|
}
|
|
|
|
if ( CurrentIsEnglish == TRUE && NewIsEnglish == FALSE )
|
|
{
|
|
*choice = ADD_ONLY_REFSPTR;
|
|
return(TRUE);
|
|
}
|
|
|
|
*choice = ADD_ENTIRE_ENTRY;
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL
|
|
DeleteAllFilesInDirectory(
|
|
LPTSTR szDir
|
|
)
|
|
{
|
|
|
|
HANDLE hFindFile;
|
|
BOOL Found = FALSE;
|
|
BOOL rc = TRUE;
|
|
TCHAR szBuf[_MAX_PATH];
|
|
TCHAR szDir2[_MAX_PATH];
|
|
WIN32_FIND_DATA FindFileData;
|
|
|
|
StringCbCopy( szDir2, sizeof(szDir2), szDir);
|
|
StringCbCat( szDir2, sizeof(szDir2), _T("*.*") );
|
|
|
|
Found = TRUE;
|
|
hFindFile = FindFirstFile((LPCTSTR)szDir2, &FindFileData);
|
|
if ( hFindFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
Found = FALSE;
|
|
}
|
|
|
|
while ( Found )
|
|
{
|
|
if ( !(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
|
|
StringCbPrintf(szBuf, sizeof(szBuf), "%s%s", szDir, FindFileData.cFileName);
|
|
if (!DeleteFile(szBuf))
|
|
{
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
Found = FindNextFile(hFindFile, &FindFileData);
|
|
}
|
|
FindClose(hFindFile);
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// Filename is expected to point to the complete path+filename (relative or absolute)
|
|
// returns TRUE if Filename matches the regexp /.*~\d+\..{0,3}/
|
|
//
|
|
BOOL DoesThisLookLikeAShortFilenameHack(char *Filename) {
|
|
BOOL bReturnValue = FALSE;
|
|
|
|
CHAR FilenameOnly[_MAX_FNAME+1];
|
|
CHAR FileExtOnly[ _MAX_EXT+1];
|
|
|
|
CHAR* Temp;
|
|
CHAR* chTilde = NULL;
|
|
|
|
if (Filename != NULL) {
|
|
|
|
_splitpath(Filename, NULL, NULL, FilenameOnly, FileExtOnly);
|
|
|
|
if ( strlen(FileExtOnly) > 4 || strlen(FilenameOnly) > 8) {
|
|
// a short filename will never be generated that is bigger than 8.3
|
|
// but FileExtOnly will also contain the '.', so account for it
|
|
bReturnValue = FALSE;
|
|
} else {
|
|
if ( (chTilde = strrchr(FilenameOnly, '~')) == NULL ) {
|
|
// generated short filenames always contain a '~'
|
|
bReturnValue = FALSE;
|
|
|
|
} else {
|
|
// point to the end of the filename
|
|
Temp = (CHAR*)FilenameOnly + strlen(FilenameOnly);
|
|
bReturnValue = TRUE; // start with true
|
|
|
|
while (++chTilde < Temp) {
|
|
// only stay true if all characters past the '~' are digits
|
|
bReturnValue = bReturnValue && isdigit(*chTilde);
|
|
}
|
|
}
|
|
}
|
|
} else { // if (Filename != NULL) {
|
|
bReturnValue = FALSE;
|
|
}
|
|
|
|
return(bReturnValue);
|
|
}
|
|
|
|
BOOL FileExists(IN LPCSTR FileName,
|
|
OUT PWIN32_FIND_DATA FindData) {
|
|
|
|
UINT OldMode;
|
|
BOOL Found;
|
|
HANDLE FindHandle;
|
|
|
|
OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
|
FindHandle = FindFirstFile(FileName,FindData);
|
|
if (FindHandle == INVALID_HANDLE_VALUE) {
|
|
Found = FALSE;
|
|
} else {
|
|
FindClose(FindHandle);
|
|
Found = TRUE;
|
|
}
|
|
|
|
SetErrorMode(OldMode);
|
|
return(Found);
|
|
}
|
|
|
|
/* GetFileNameStart This returns the address of the first character of the file name */
|
|
PCHAR GetFileNameStart(LPTSTR FileName) {
|
|
LPTSTR c_ptr;
|
|
|
|
c_ptr = FileName + _tcslen(FileName) - 1;
|
|
|
|
while ( c_ptr > FileName ) {
|
|
if ( *c_ptr == _T('\\') ) {
|
|
return (++c_ptr);
|
|
} else {
|
|
c_ptr--;
|
|
}
|
|
}
|
|
return(FileName);
|
|
}
|
|
|
|
|
|
P_LIST GetList(LPTSTR szFileName) {
|
|
|
|
/* GetList gets the list and keeps the original file name which could
|
|
* have included the path to the file
|
|
* Note, it can be merged with GetExcludeList. I first created it for
|
|
* use in creating the symbols CD, and didn't want to risk entering a
|
|
* bug into symchk
|
|
*/
|
|
|
|
P_LIST pList;
|
|
|
|
FILE *fFile;
|
|
TCHAR szCurFile[_MAX_FNAME+1], *c;
|
|
TCHAR fname[_MAX_FNAME+1], ext[_MAX_EXT+1];
|
|
DWORD i, rc;
|
|
LPTSTR szEndName;
|
|
ULONG RetVal = FALSE;
|
|
|
|
|
|
pList = (P_LIST)malloc(sizeof(LIST));
|
|
if (pList)
|
|
{
|
|
pList->dNumFiles = 0;
|
|
if ( (fFile = _tfopen(szFileName,_T("r") )) == NULL )
|
|
{
|
|
// printf( "Cannot open the exclude file %s\n",szFileName );
|
|
}
|
|
else
|
|
{
|
|
while ( _fgetts(szCurFile,_MAX_FNAME,fFile) ) {
|
|
if ( szCurFile[0] == ';' ) continue;
|
|
(pList->dNumFiles)++;
|
|
}
|
|
|
|
// Go back to the beginning of the file
|
|
rc = fseek(fFile,0,0);
|
|
if ( rc != 0 )
|
|
{
|
|
free(pList);
|
|
fclose(fFile);
|
|
return(NULL);
|
|
}
|
|
pList->List = (LIST_ELEM*)malloc( sizeof(LIST_ELEM) *
|
|
(pList->dNumFiles));
|
|
if (pList->List)
|
|
{
|
|
i = 0;
|
|
while ( i < pList->dNumFiles )
|
|
{
|
|
memset(szCurFile,'\0',sizeof(TCHAR) * (_MAX_FNAME+1) );
|
|
if ( _fgetts(szCurFile,_MAX_FNAME,fFile) == NULL )
|
|
{
|
|
fclose(fFile);
|
|
return(NULL);
|
|
}
|
|
|
|
// Replace the \n with \0
|
|
c = NULL;
|
|
c = _tcschr(szCurFile, '\n');
|
|
if ( c != NULL) *c='\0';
|
|
|
|
if ( szCurFile[0] == ';' ) continue;
|
|
|
|
if ( _tcslen(szCurFile) > _MAX_FNAME ) {
|
|
so->printf("File %s has a string that is too large\n",szFileName);
|
|
break;
|
|
}
|
|
|
|
// Allow for spaces and a ; after the file name
|
|
// Move the '\0' back until it has erased the ';' and any
|
|
// tabs and spaces that might come before it
|
|
szEndName = _tcschr(szCurFile, ';');
|
|
if (szEndName != NULL ) {
|
|
while ( *szEndName == ';' || *szEndName == ' '
|
|
|| *szEndName == '\t' ){
|
|
*szEndName = '\0';
|
|
if ( szEndName > szCurFile ) szEndName--;
|
|
}
|
|
}
|
|
|
|
StringCbCopy(pList->List[i].Path, sizeof(pList->List[i].Path), szCurFile);
|
|
|
|
_tsplitpath(szCurFile,NULL,NULL,fname,ext);
|
|
|
|
StringCbCopy(pList->List[i].FName,sizeof(pList->List[i].FName), fname);
|
|
StringCbCat( pList->List[i].FName,sizeof(pList->List[i].FName), ext);
|
|
i++;
|
|
}
|
|
|
|
if (i == pList->dNumFiles)
|
|
{
|
|
RetVal = TRUE;
|
|
}
|
|
else
|
|
{
|
|
free(pList->List);
|
|
}
|
|
}
|
|
|
|
fclose(fFile);
|
|
}
|
|
|
|
if (!RetVal)
|
|
{
|
|
free(pList);
|
|
pList = NULL;
|
|
}
|
|
}
|
|
|
|
// Sort the List
|
|
// qsort( (void*)pList->List, (size_t)pList->dNumFiles,
|
|
// (size_t)sizeof(LIST_ELEM), SymComp2 );
|
|
|
|
|
|
return (pList);
|
|
|
|
}
|
|
|
|
PIMAGE_NT_HEADERS
|
|
GetNtHeader ( PIMAGE_DOS_HEADER pDosHeader,
|
|
HANDLE hDosFile
|
|
)
|
|
{
|
|
|
|
/*
|
|
Returns the pointer the address of the NT Header. If there isn't
|
|
an NT header, it returns NULL
|
|
*/
|
|
PIMAGE_NT_HEADERS pNtHeader = NULL;
|
|
BY_HANDLE_FILE_INFORMATION FileInfo;
|
|
|
|
|
|
//
|
|
// If the image header is not aligned on a long boundary.
|
|
// Report this as an invalid protect mode image.
|
|
//
|
|
if ( ((ULONG)(pDosHeader->e_lfanew) & 3) == 0)
|
|
{
|
|
if (GetFileInformationByHandle( hDosFile, &FileInfo) &&
|
|
((ULONG)(pDosHeader->e_lfanew) <= FileInfo.nFileSizeLow))
|
|
{
|
|
pNtHeader = (PIMAGE_NT_HEADERS)((PCHAR)pDosHeader +
|
|
(ULONG)pDosHeader->e_lfanew);
|
|
|
|
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
|
|
{
|
|
pNtHeader = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pNtHeader;
|
|
}
|
|
|
|
/***********************************************************************************
|
|
Function: GetSymbolServerDirs
|
|
|
|
Purpose:
|
|
To get the directory structure on the symbol server for the file passed in.
|
|
|
|
Parameters:
|
|
IN szFileName File name that is being stored on the symbol server.
|
|
If it has path information, that will get stripped off.
|
|
|
|
IN guid This is a Guid for the PDB that is being stored.
|
|
|
|
IN dwNum1 This is a timedatestamp for exe's or dbg's that are being stored.
|
|
Note: Either guid must be null or dwNum1 must be 0.
|
|
IN dwNum2 SizeOfImage for exe's and dbg's. Age for PDb's.
|
|
|
|
|
|
OUT szString String with the two directories on the symbol server that this
|
|
file is stored under.
|
|
Return value:
|
|
Returns TRUE is the function succeeds. Returns FALSE if it fails.
|
|
|
|
************************************************************************************/
|
|
BOOL GetSymbolServerDirs(
|
|
LPTSTR szFileName,
|
|
GUID *guid,
|
|
DWORD dwNum1,
|
|
DWORD dwNum2,
|
|
LPTSTR szString
|
|
)
|
|
{
|
|
|
|
BOOL rc;
|
|
GUID MyGuid;
|
|
PCHAR FileNameStart;
|
|
CHAR Buf[_MAX_PATH] = _T("");
|
|
|
|
FileNameStart = GetFileNameStart(szFileName);
|
|
|
|
if (guid != NULL)
|
|
{
|
|
rc = SymbolServer( _T("X"), FileNameStart, guid, dwNum2, 0, Buf );
|
|
|
|
} else {
|
|
|
|
// Turn this into a GUID so that we don't have to reset the SymbolServerOptions
|
|
// SymbolServerSetOptions was set in main.
|
|
|
|
memset( &MyGuid, 0, sizeof(MyGuid) );
|
|
MyGuid.Data1 = dwNum1;
|
|
rc = SymbolServer( _T("X"), FileNameStart, &MyGuid, dwNum2, 0, Buf );
|
|
}
|
|
|
|
// Remove the X\ that comes back at the beginning of Buf
|
|
StringCchCopy(szString, _MAX_PATH, Buf+2 );
|
|
|
|
// Remove the "\filename" that is at the end of Buf
|
|
|
|
FileNameStart = GetFileNameStart( szString );
|
|
*(FileNameStart-1) = _T('\0');
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
BOOL
|
|
MyCopyFile(
|
|
LPCTSTR lpExistingFileName,
|
|
LPCTSTR lpNewFileName
|
|
)
|
|
/*++
|
|
|
|
Routine description:
|
|
This handles whether the file is a compressed file or not. First it
|
|
tries to copy in the compressed version of the file. If that works,
|
|
then it will delete the uncompressed file if it exists in the target.
|
|
|
|
If the compressed file is not there, then it copies in the
|
|
uncompressed file.
|
|
|
|
--*/
|
|
{
|
|
|
|
TCHAR ExistingFileName_C[_MAX_PATH]; // Compressed version name
|
|
TCHAR NewFileName_C[_MAX_PATH]; // Compressed version
|
|
DWORD dw;
|
|
BOOL rc;
|
|
|
|
|
|
// Put a _ at the end of the compressed names
|
|
|
|
StringCbCopy( ExistingFileName_C, sizeof(ExistingFileName_C), lpExistingFileName );
|
|
ExistingFileName_C[ _tcslen(ExistingFileName_C) - 1 ] = _T('_');
|
|
|
|
StringCbCopy( NewFileName_C, sizeof(NewFileName_C), lpNewFileName );
|
|
NewFileName_C[ _tcslen( NewFileName_C ) - 1 ] = _T('_');
|
|
|
|
// If the compressed file exists, copy it instead of the uncompressed file
|
|
|
|
dw = GetFileAttributes( ExistingFileName_C );
|
|
if ( dw != 0xffffffff) {
|
|
rc = CopyFile( ExistingFileName_C, NewFileName_C, TRUE );
|
|
if ( !rc && GetLastError() != ERROR_FILE_EXISTS ) {
|
|
so->printf("CopyFile failed to copy %s to %s - GetLastError() = %d\n",
|
|
ExistingFileName_C, NewFileName_C, GetLastError() );
|
|
return (FALSE);
|
|
}
|
|
SetFileAttributes( NewFileName_C, FILE_ATTRIBUTE_NORMAL );
|
|
|
|
// If the uncompressed file exists, delete it
|
|
dw = GetFileAttributes( lpNewFileName );
|
|
if ( dw != 0xffffffff ) {
|
|
rc = DeleteFile( lpNewFileName );
|
|
if (!rc) {
|
|
so->printf("Keeping %s, but could not delete %s\n",
|
|
NewFileName_C, lpNewFileName );
|
|
}
|
|
}
|
|
} else {
|
|
// Compressed file doesn't exist, try the uncompressed
|
|
dw = GetFileAttributes( lpExistingFileName );
|
|
if ( dw != 0xffffffff ) {
|
|
rc = CopyFile( lpExistingFileName, lpNewFileName, TRUE );
|
|
if ( !rc && GetLastError() != ERROR_FILE_EXISTS ) {
|
|
so->printf("CopyFile failed to copy %s to %s - GetLastError() = %d\n",
|
|
lpExistingFileName, lpNewFileName, GetLastError() );
|
|
return (FALSE);
|
|
}
|
|
SetFileAttributes( lpNewFileName, FILE_ATTRIBUTE_NORMAL );
|
|
}
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
void MyEnsureTrailingBackslash(char *sz) {
|
|
return MyEnsureTrailingChar(sz, '\\');
|
|
}
|
|
|
|
void MyEnsureTrailingChar(char *sz, char c) {
|
|
int i;
|
|
|
|
assert(sz);
|
|
|
|
i = strlen(sz);
|
|
if (!i)
|
|
return;
|
|
|
|
if (sz[i - 1] == c)
|
|
return;
|
|
|
|
sz[i] = c;
|
|
sz[i + 1] = '\0';
|
|
}
|
|
|
|
void MyEnsureTrailingCR(char *sz) {
|
|
return MyEnsureTrailingChar(sz, '\n');
|
|
}
|
|
|
|
void MyEnsureTrailingSlash(char *sz) {
|
|
return MyEnsureTrailingChar(sz, '/');
|
|
}
|
|
|
|
BOOL
|
|
ReadFilePtr(
|
|
LPTSTR szContents,
|
|
HANDLE hFile
|
|
)
|
|
{
|
|
BOOL rc;
|
|
DWORD size;
|
|
DWORD cb;
|
|
LPTSTR p;
|
|
DWORD high;
|
|
|
|
|
|
size = GetFileSize(hFile, NULL);
|
|
if (!size || size > _MAX_PATH) {
|
|
return FALSE;
|
|
}
|
|
|
|
// read it
|
|
|
|
if (!ReadFile(hFile, szContents, size, &cb, 0)) {
|
|
rc=FALSE;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (cb != size) {
|
|
rc=FALSE;
|
|
goto cleanup;
|
|
}
|
|
|
|
rc = true;
|
|
|
|
// trim string down to the CR
|
|
|
|
for (p = szContents; *p; p++) {
|
|
if (*p == 10 || *p == 13)
|
|
{
|
|
*p = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
// done
|
|
SetFilePointer( hFile, 0, NULL, FILE_BEGIN);
|
|
return rc;
|
|
}
|
|
|
|
BOOL
|
|
StoreDbg(
|
|
LPTSTR szDestDir,
|
|
LPTSTR szFileName,
|
|
LPTSTR szPtrFileName,
|
|
USHORT *rc_flag
|
|
)
|
|
|
|
/* ++
|
|
|
|
Routine Description:
|
|
Stores this file as "szDestDir\szFileName\Checksum"
|
|
|
|
Return Value:
|
|
TRUE - file was stored successfully
|
|
FALSE - file was not stored successfully
|
|
|
|
-- */
|
|
{
|
|
|
|
PIMAGE_SEPARATE_DEBUG_HEADER pDbgHeader;
|
|
HANDLE hFile;
|
|
BOOL rc;
|
|
TCHAR szString[_MAX_PATH];
|
|
UINT i;
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *DebugDirectory, *pDbgDir;
|
|
ULONG NumberOfDebugDirectories;
|
|
|
|
|
|
ZeroMemory(szString, _MAX_PATH * sizeof(TCHAR) );
|
|
|
|
pDbgHeader = SymCommonMapDbgHeader ( szFileName, &hFile );
|
|
|
|
if (pDbgHeader == NULL) {
|
|
so->printf("ERROR: StoreDbg(), %s was not opened successfully\n",szFileName);
|
|
SymCommonUnmapFile((LPCVOID)pDbgHeader, hFile);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
DebugDirectory = NULL;
|
|
DebugDirectory = GetDebugDirectoryInDbg(
|
|
pDbgHeader,
|
|
&NumberOfDebugDirectories
|
|
);
|
|
PrivateStripped = TRUE;
|
|
|
|
if (DebugDirectory != NULL) {
|
|
|
|
for ( i=0; i< NumberOfDebugDirectories; i++ ) {
|
|
pDbgDir = DebugDirectory + i;
|
|
__try
|
|
{
|
|
switch (pDbgDir->Type) {
|
|
case IMAGE_DEBUG_TYPE_MISC:
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_CODEVIEW:
|
|
if ( !DBGPrivateStripped(
|
|
DebugDirectory->PointerToRawData + (PCHAR)pDbgHeader,
|
|
DebugDirectory->SizeOfData
|
|
) ) {
|
|
PrivateStripped = FALSE;
|
|
}
|
|
if (PrivateStripped) {
|
|
StringCbCopy(szPriPubBin, sizeof(szPriPubBin), _T("pub") );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// Nothing except the CV entry should point to raw data
|
|
if ( pDbgDir->SizeOfData != 0 ) {
|
|
PrivateStripped = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
SymCommonUnmapFile((LPCVOID)pDbgHeader, hFile);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Something is wrong with how we are figuring out what has private info stripped.
|
|
// Go back to saying that every DBG is public until we get it figured out.
|
|
|
|
PrivateStripped = TRUE;
|
|
|
|
if (PrivateStripped) {
|
|
StringCbCopy(szPriPubBin, sizeof(szPriPubBin), _T("pub") );
|
|
} else {
|
|
StringCbCopy(szPriPubBin, sizeof(szPriPubBin), _T("pri") );
|
|
}
|
|
|
|
if ( ( (pArgs->Filter == 2) && PrivateStripped ) ||
|
|
( (pArgs->Filter == 1) && !PrivateStripped ) ) {
|
|
SymCommonUnmapFile((LPCVOID)pDbgHeader, hFile);
|
|
*rc_flag = FILE_SKIPPED;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
GetSymbolServerDirs( szFileName,
|
|
NULL,
|
|
(DWORD) pDbgHeader->TimeDateStamp,
|
|
(DWORD) pDbgHeader->SizeOfImage,
|
|
szString
|
|
);
|
|
|
|
rc = StoreFile( szDestDir,
|
|
szFileName,
|
|
szString,
|
|
szPtrFileName );
|
|
|
|
SymCommonUnmapFile((LPCVOID)pDbgHeader, hFile);
|
|
return rc;
|
|
}
|
|
|
|
BOOL
|
|
StoreFile(
|
|
LPTSTR szDestDir,
|
|
LPTSTR szFileName,
|
|
LPTSTR szString2,
|
|
LPTSTR szPtrFileName
|
|
)
|
|
{
|
|
TCHAR szPathName[_MAX_PATH + _MAX_FNAME + 2];
|
|
TCHAR szFileNameOnly[_MAX_FNAME + _MAX_EXT];
|
|
TCHAR szExt[_MAX_EXT];
|
|
TCHAR szBuf[_MAX_PATH * 3];
|
|
TCHAR szRefsDir[_MAX_PATH * 3];
|
|
|
|
DWORD dwNumBytesToWrite;
|
|
DWORD dwNumBytesWritten;
|
|
BOOL rc;
|
|
DWORD dwSizeDestDir;
|
|
|
|
DWORD dwFileSizeLow;
|
|
DWORD dwFileSizeHigh;
|
|
|
|
|
|
if (DoesThisLookLikeAShortFilenameHack(szFileName)) {
|
|
fprintf(stderr, "SYMSTORE: Skipping bad filename: %s\n", szFileName);
|
|
return(FILE_SKIPPED);
|
|
}
|
|
|
|
// If ADD_DONT_STORE, then write the function parameters
|
|
// to a file so we can call this function exactly when
|
|
// running ADD_STORE_FROM_FILE
|
|
|
|
if ( StoreFlags == ADD_DONT_STORE ) {
|
|
|
|
// Don't need to store szDestDir because it will
|
|
// be given when adding from file
|
|
|
|
dwFileSizeLow = GetFileSize(hTransFile, &dwFileSizeHigh);
|
|
|
|
StringCbPrintf( szBuf,
|
|
sizeof(szBuf),
|
|
"%s,%s,",
|
|
szFileName+pArgs->ShareNameLength,
|
|
szString2
|
|
);
|
|
|
|
if ( szPtrFileName != NULL ) {
|
|
StringCbCat(szBuf, sizeof(szBuf), szPtrFileName+pArgs->ShareNameLength);
|
|
}
|
|
|
|
StringCbCat(szBuf, sizeof(szBuf), _T(",") );
|
|
StringCbCat(szBuf, sizeof(szBuf), szPriPubBin);
|
|
StringCbCat(szBuf, sizeof(szBuf), _T(",,,,\r\n") );
|
|
|
|
dwNumBytesToWrite = _tcslen(szBuf) * sizeof(TCHAR);
|
|
WriteFile( hTransFile,
|
|
(LPCVOID)szBuf,
|
|
dwNumBytesToWrite,
|
|
&dwNumBytesWritten,
|
|
NULL
|
|
);
|
|
|
|
if ( dwNumBytesToWrite != dwNumBytesWritten ) {
|
|
so->printf( "FAILED to write to %s, with GetLastError = %d\n",
|
|
szPathName,
|
|
GetLastError()
|
|
);
|
|
return (FALSE);
|
|
} else {
|
|
return (TRUE);
|
|
|
|
}
|
|
}
|
|
|
|
if ( szPtrFileName != NULL ) {
|
|
rc = StoreFilePtr ( szDestDir,
|
|
szString2,
|
|
szPtrFileName
|
|
);
|
|
return (rc);
|
|
}
|
|
|
|
_tsplitpath(szFileName, NULL, NULL, szFileNameOnly, szExt);
|
|
StringCbCat(szFileNameOnly, sizeof(szFileNameOnly), szExt);
|
|
|
|
StringCbPrintf( szPathName,
|
|
sizeof(szPathName),
|
|
"%s%s",
|
|
szDestDir,
|
|
szString2
|
|
);
|
|
|
|
// Save a copy for writing refs.ptr
|
|
StringCbCopy(szRefsDir, sizeof(szRefsDir), szPathName);
|
|
|
|
// Create the directory to store the file if its not already there
|
|
MyEnsureTrailingBackslash(szPathName);
|
|
|
|
if ( pArgs->TransState != TRANSACTION_QUERY ) {
|
|
if ( !MakeSureDirectoryPathExists( szPathName ) ) {
|
|
so->printf("Could not create %s\n", szPathName);
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
StringCbCat( szPathName, sizeof(szPathName), szFileNameOnly );
|
|
|
|
// Enter this into the log, skipping the Destination directory
|
|
// at the beginning of szPathName
|
|
//
|
|
dwSizeDestDir = _tcslen(szDestDir);
|
|
|
|
dwFileSizeLow = GetFileSize(hTransFile, &dwFileSizeHigh);
|
|
|
|
if ( dwFileSizeLow == 0 && dwFileSizeHigh == 0 ) {
|
|
StringCbPrintf( szBuf, sizeof(szBuf), "%s,%s", szRefsDir+dwSizeDestDir, szFileName );
|
|
} else {
|
|
StringCbPrintf( szBuf, sizeof(szBuf), "\n%s,%s", szRefsDir+dwSizeDestDir, szFileName );
|
|
}
|
|
|
|
if ( pArgs->TransState == TRANSACTION_QUERY ) {
|
|
WIN32_FIND_DATA FindData;
|
|
|
|
if ( FileExists(szPathName, &FindData) ) {
|
|
if ( !(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
|
|
printf("SYMSTORE: \"%s\"\t\"%s\"\n", szFileName, szPathName);
|
|
} else {
|
|
// handle the case of it being a directory
|
|
printf("SYMSTORE: ERROR: %s is a directory!\n", szPathName);
|
|
}
|
|
} else {
|
|
// handle the case of file.ptr
|
|
CHAR drive[_MAX_DRIVE];
|
|
CHAR dir[ _MAX_DIR];
|
|
CHAR file[ _MAX_FNAME];
|
|
CHAR ext[ _MAX_EXT];
|
|
CHAR NewFilename[MAX_PATH];
|
|
|
|
_splitpath(szPathName, drive, dir, file, ext);
|
|
|
|
//
|
|
// 'Magic' to handle the fact that splitpath() doesn't do the
|
|
// Right Thing(tm) with UNC paths.
|
|
//
|
|
if ( drive[0] != '\0') {
|
|
StringCbCopy(NewFilename, sizeof(NewFilename), drive);
|
|
StringCbCat( NewFilename, sizeof(NewFilename), "\\");
|
|
} else {
|
|
NewFilename[0] = '\0';
|
|
}
|
|
StringCbCat( NewFilename, sizeof(NewFilename), dir);
|
|
StringCbCat( NewFilename, sizeof(NewFilename), "file.ptr");
|
|
|
|
if ( FileExists(NewFilename, &FindData) ) {
|
|
if ( !(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
|
|
HANDLE hFile = CreateFile( NewFilename,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
if ( ReadFilePtr(szBuf, hFile) ) {
|
|
if ( FileExists(szBuf, &FindData) ) {
|
|
printf("SYMSTORE: \"%s\"\t\"%s\"\n", szFileName, szBuf);
|
|
} else {
|
|
if(pArgs->VerboseOutput) {
|
|
printf("SYMSTORE: Skipped \"%s\" - doesn't exist!\n", szBuf);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
printf("SYMSTORE: ERROR: Couldn't read %s!\n", NewFilename);
|
|
}
|
|
} else {
|
|
printf("SYMSTORE: ERROR: %s is a directory!\n", NewFilename);
|
|
}
|
|
} else {
|
|
if(pArgs->VerboseOutput) {
|
|
printf("SYMSTORE: Skipped \"%s\" - doesn't exist!\n", szPathName);
|
|
}
|
|
}
|
|
}
|
|
return(1); // so we don't get a failed store message
|
|
|
|
}
|
|
|
|
if ( pArgs->TransState != TRANSACTION_QUERY ) {
|
|
dwNumBytesToWrite = _tcslen(szBuf) * sizeof(TCHAR);
|
|
WriteFile( hTransFile,
|
|
(LPCVOID)szBuf,
|
|
dwNumBytesToWrite,
|
|
&dwNumBytesWritten,
|
|
NULL
|
|
);
|
|
|
|
if ( dwNumBytesToWrite != dwNumBytesWritten ) {
|
|
so->printf( "FAILED to write to %s, with GetLastError = %d\n",
|
|
szPathName,
|
|
GetLastError()
|
|
);
|
|
return (FALSE);
|
|
}
|
|
|
|
rc = MyCopyFile(szFileName, szPathName);
|
|
|
|
if (!rc) return (FALSE);
|
|
|
|
MyEnsureTrailingBackslash(szRefsDir);
|
|
|
|
rc = AddToReferenceCount(szRefsDir, szFileName, _T("file"), FALSE );
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
BOOL
|
|
StoreFilePtr(
|
|
LPTSTR szDestDir,
|
|
LPTSTR szString2,
|
|
LPTSTR szPtrFileName
|
|
)
|
|
{
|
|
|
|
/*
|
|
szPathName The full path with "file.ptr" appended to it.
|
|
This is the path for storing file.ptr
|
|
|
|
*/
|
|
|
|
TCHAR szPathName[_MAX_PATH];
|
|
TCHAR szRefsDir[_MAX_PATH];
|
|
TCHAR szPubPriType[4]="";
|
|
|
|
HANDLE hFile;
|
|
DWORD dwNumBytesToWrite;
|
|
DWORD dwNumBytesWritten;
|
|
DWORD rc=1;
|
|
DWORD dwSizeDestDir;
|
|
|
|
DWORD dwFileSizeLow;
|
|
DWORD dwFileSizeHigh;
|
|
DWORD timeout;
|
|
TCHAR szCurrentFilePtr[_MAX_PATH]= "";
|
|
DWORD size=0;
|
|
DWORD highsize=0;
|
|
DWORD dwError;
|
|
BOOL UpdateRefsPtr=TRUE;
|
|
BOOL UpdateFilePtr=TRUE;
|
|
BOOL DeleteRefsPtr=FALSE;
|
|
UINT DecisionFlags;
|
|
|
|
StringCbPrintf( szPathName, sizeof(szPathName), "%s%s",
|
|
szDestDir,
|
|
szString2 );
|
|
|
|
MyEnsureTrailingBackslash( szPathName );
|
|
|
|
// Save this for passing in the refs.ptr directory
|
|
StringCbCopy(szRefsDir, sizeof(szRefsDir), szPathName);
|
|
StringCbPrintf( szPathName,
|
|
sizeof(szPathName),
|
|
"%s%s",
|
|
szPathName,
|
|
_T("file.ptr")
|
|
);
|
|
|
|
|
|
if ( !MakeSureDirectoryPathExists( szPathName ) ) {
|
|
so->printf("Could not create %s\n", szPathName);
|
|
return (FALSE);
|
|
}
|
|
|
|
// Put this file into file.ptr. If file.ptr is already there, then
|
|
// replace the contents with this pointer
|
|
|
|
// Wait for the file to become available
|
|
timeout=0;
|
|
|
|
do {
|
|
hFile = CreateFile( szPathName,
|
|
GENERIC_WRITE | GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
|
|
// Make sure that delete didn't come through and remove the directory
|
|
if ( !MakeSureDirectoryPathExists( szPathName ) ) {
|
|
so->printf("Could not create %s\n", szPathName);
|
|
return (FALSE);
|
|
}
|
|
|
|
if ( hFile == INVALID_HANDLE_VALUE ) {
|
|
SleepEx(1000,0);
|
|
timeout++;
|
|
}
|
|
|
|
} while ( hFile == INVALID_HANDLE_VALUE && timeout <= 50 ) ;
|
|
|
|
if ( (hFile == INVALID_HANDLE_VALUE) || (timeout > 50) ) {
|
|
so->printf( "Failed to open %s for writing, with GetLastError = %d\n", szPathName, GetLastError() );
|
|
return(FALSE);
|
|
}
|
|
|
|
// If the pointer we are adding points to \\arch\, then add it.
|
|
// If the pointer we are adding doesn't point to \\arch\, then
|
|
// don't overwrite a file.ptr that does point to \\arch\.
|
|
|
|
UpdateFilePtr = TRUE;
|
|
UpdateRefsPtr = TRUE;
|
|
DeleteRefsPtr = FALSE;
|
|
|
|
if ( MSArchive && ReadFilePtr( szCurrentFilePtr, hFile ) )
|
|
{
|
|
|
|
DecidePriority( szCurrentFilePtr,
|
|
szPtrFileName,
|
|
szRefsDir,
|
|
&DecisionFlags
|
|
);
|
|
|
|
if ( DecisionFlags & SKIP_ENTIRE_ENTRY )
|
|
{
|
|
UpdateFilePtr = FALSE;
|
|
UpdateRefsPtr = FALSE;
|
|
}
|
|
|
|
if ( DecisionFlags & ADD_ONLY_REFSPTR )
|
|
{
|
|
UpdateFilePtr = FALSE;
|
|
}
|
|
|
|
if ( DecisionFlags & DELETE_REFSPTR )
|
|
{
|
|
DeleteRefsPtr = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( UpdateFilePtr ) {
|
|
|
|
dwNumBytesToWrite = _tcslen(szPtrFileName) * sizeof(TCHAR);
|
|
|
|
WriteFile( hFile,
|
|
(LPCVOID)szPtrFileName,
|
|
dwNumBytesToWrite,
|
|
&dwNumBytesWritten,
|
|
NULL
|
|
);
|
|
|
|
if ( dwNumBytesToWrite != dwNumBytesWritten ) {
|
|
so->printf( "FAILED to write %s, with GetLastError = %d\n",
|
|
szPathName,
|
|
GetLastError()
|
|
);
|
|
CloseHandle(hFile);
|
|
return (FALSE);
|
|
}
|
|
SetEndOfFile(hFile);
|
|
|
|
}
|
|
|
|
if ( UpdateRefsPtr ) {
|
|
|
|
// Enter this into the log, skipping the first part that is the root
|
|
// of the symbols server
|
|
|
|
dwSizeDestDir = _tcslen(szDestDir);
|
|
dwFileSizeLow = GetFileSize(hTransFile, &dwFileSizeHigh);
|
|
|
|
if ( dwFileSizeLow == 0 && dwFileSizeHigh == 0 ) {
|
|
StringCbPrintf( szPathName, sizeof(szPathName), "%s,%s", szRefsDir + dwSizeDestDir, szPtrFileName);
|
|
} else {
|
|
StringCbPrintf( szPathName, sizeof(szPathName), "\n%s,%s", szRefsDir + dwSizeDestDir, szPtrFileName);
|
|
}
|
|
|
|
dwNumBytesToWrite = _tcslen(szPathName) * sizeof(TCHAR);
|
|
WriteFile( hTransFile,
|
|
(LPCVOID)(szPathName),
|
|
dwNumBytesToWrite,
|
|
&dwNumBytesWritten,
|
|
NULL
|
|
);
|
|
|
|
if ( dwNumBytesToWrite != dwNumBytesWritten ) {
|
|
so->printf( "FAILED to write to %s, with GetLastError = %d\n",
|
|
szPathName,
|
|
GetLastError()
|
|
);
|
|
return (FALSE);
|
|
}
|
|
|
|
// File.ptr was created successfully, now, add the contents of
|
|
// szPathName to refs.ptr
|
|
|
|
MyEnsureTrailingBackslash(szRefsDir);
|
|
rc = AddToReferenceCount( szRefsDir, szPtrFileName, "ptr", DeleteRefsPtr );
|
|
if (!rc) {
|
|
so->printf("AddToReferenceCount failed for %s,ptr,%s",
|
|
szDestDir, szPtrFileName);
|
|
}
|
|
|
|
}
|
|
|
|
// If you close this handle sooner, there will be problems if add and
|
|
// delete are running at the same time. The delete process can come in
|
|
// and delete the directory before AddToReferenceCount gets called.
|
|
// Then the CreateFile in there fails.
|
|
|
|
|
|
CloseHandle(hFile);
|
|
return (rc);
|
|
}
|
|
|
|
DWORD
|
|
StoreFromFile(
|
|
FILE *pStoreFromFile,
|
|
LPTSTR szDestDir,
|
|
PFILE_COUNTS pFileCounts) {
|
|
|
|
LPTSTR szFileName;
|
|
DWORD dw1,dw2;
|
|
LPTSTR szPtrFileName;
|
|
LPTSTR szBufCut;
|
|
|
|
TCHAR szFullFileName[_MAX_PATH];
|
|
TCHAR szFullPtrFileName[_MAX_PATH];
|
|
TCHAR szBuf[_MAX_PATH*4];
|
|
|
|
TCHAR szString[_MAX_PATH];
|
|
LPTSTR token2,token3,token4,token5,token6,token7;
|
|
ULONG i,comma_count,token_start;
|
|
|
|
BOOL rc;
|
|
|
|
ZeroMemory( szString, sizeof(szString) );
|
|
|
|
// Read in each line of the file
|
|
while ( !feof( pStoreFromFile) ) {
|
|
|
|
szFileName = NULL;
|
|
szPtrFileName = NULL;
|
|
StringCbCopy(szBuf, sizeof(szBuf), _T("") );
|
|
|
|
if (!fgets( szBuf, _MAX_PATH*4, pStoreFromFile)) {
|
|
break;
|
|
}
|
|
|
|
// Cut the comment
|
|
if ( (szBufCut = _tcschr( szBuf, ';' ) ) != NULL ) {
|
|
szBufCut[0] = '\0';
|
|
}
|
|
|
|
// skip no fields line
|
|
if (_tcschr( szBuf, ',' ) == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
StringCbCopy( szFullFileName, sizeof(szFullFileName), pArgs->szShareName );
|
|
StringCbCopy( szFullPtrFileName, sizeof(szFullPtrFileName), pArgs->szShareName );
|
|
|
|
|
|
// Step through szBuf and count how many commas there are
|
|
// If there are 3 commas, this is a new style file. If there
|
|
// are 4 commas, this is an old style file.
|
|
// If there are 7 commas, this is the newest style file.
|
|
|
|
token2=NULL;
|
|
token3=NULL;
|
|
token4=NULL;
|
|
token5=NULL;
|
|
token6=NULL;
|
|
token7=NULL;
|
|
|
|
comma_count=0;
|
|
i=0;
|
|
token_start=i;
|
|
|
|
while ( szBuf[i] != _T('\0') && comma_count < 7 ) {
|
|
if ( szBuf[i] == _T(',') ) {
|
|
switch (comma_count) {
|
|
case 0: szFileName=szBuf;
|
|
break;
|
|
case 1: token2=szBuf+token_start;
|
|
break;
|
|
case 2: token3=szBuf+token_start;
|
|
break;
|
|
case 3: token4=szBuf+token_start;
|
|
break;
|
|
case 4: token5=szBuf+token_start;
|
|
break;
|
|
case 5: token6=szBuf+token_start;
|
|
break;
|
|
case 6: token7=szBuf+token_start;
|
|
break;
|
|
default: break;
|
|
}
|
|
token_start=i+1;
|
|
szBuf[i]=_T('\0');
|
|
comma_count++;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if ( szFileName != NULL ) {
|
|
StringCbCat( szFullFileName, sizeof(szFullFileName), szFileName);
|
|
|
|
if ( comma_count == 3 || comma_count == 7 ) {
|
|
//This is the new style
|
|
StringCbCopy( szString, sizeof(szString), token2);
|
|
if ( (token3 != NULL ) && (*token3 != _T('\0')) ) {
|
|
szPtrFileName=token3;
|
|
}
|
|
} else {
|
|
dw1=atoi(token2);
|
|
dw2=atoi(token3);
|
|
if ( *token4 != _T('\0') ) {
|
|
szPtrFileName=token4;
|
|
}
|
|
GetSymbolServerDirs( szFileName, NULL, dw1, dw2, szString );
|
|
}
|
|
|
|
if ( comma_count == 7 ) {
|
|
StringCbCopy( szPriPubBin, sizeof(szPriPubBin), token4 );
|
|
}
|
|
|
|
if (pArgs->StorePtrs == TRUE) {
|
|
szPtrFileName=szFileName;
|
|
}
|
|
|
|
if ( szPtrFileName != NULL ) {
|
|
StringCbCat( szFullPtrFileName, sizeof(szFullPtrFileName), szPtrFileName);
|
|
}
|
|
|
|
|
|
if ( szPtrFileName == NULL ) {
|
|
rc = StoreFile(szDestDir,szFullFileName,szString,NULL);
|
|
|
|
} else {
|
|
rc = StoreFile(szDestDir,szFullFileName,szString,szFullPtrFileName);
|
|
}
|
|
|
|
if (rc) {
|
|
pFileCounts->NumPassedFiles++;
|
|
} else {
|
|
pFileCounts->NumFailedFiles++;
|
|
}
|
|
}
|
|
}
|
|
free(szBuf);
|
|
return(pFileCounts->NumFailedFiles);
|
|
}
|
|
|
|
BOOL
|
|
StoreNtFile(
|
|
LPTSTR szDestDir,
|
|
LPTSTR szFileName,
|
|
LPTSTR szPtrFileName,
|
|
USHORT *rc
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Stores this file as "szDestDir\szFileName\Checksum"
|
|
|
|
Return Value:
|
|
TRUE - file was stored successfully
|
|
FALSE - file was not stored successfully
|
|
|
|
--*/
|
|
{
|
|
|
|
BOOL temp_rc;
|
|
HANDLE DosFile = 0;
|
|
DWORD dwErrorCode = 0;
|
|
|
|
PIMAGE_DOS_HEADER pDosHeader = NULL;
|
|
PIMAGE_NT_HEADERS pNtHeader = NULL;
|
|
ULONG TimeDateStamp;
|
|
ULONG SizeOfImage;
|
|
TCHAR szString[_MAX_PATH];
|
|
|
|
ZeroMemory(szString, _MAX_PATH*sizeof(TCHAR) );
|
|
|
|
pDosHeader = SymCommonMapFileHeader( szFileName, &DosFile, &dwErrorCode );
|
|
if ( pDosHeader == NULL ) {
|
|
*rc = FILE_SKIPPED;
|
|
return FALSE;
|
|
};
|
|
|
|
pNtHeader = GetNtHeader( pDosHeader, DosFile);
|
|
if ( pNtHeader == NULL ) {
|
|
SymCommonUnmapFile((LPCVOID)pDosHeader,DosFile);
|
|
*rc = FILE_SKIPPED;
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
// Resource Dll's shouldn't have symbols
|
|
if ( SymCommonResourceOnlyDll((PVOID)pDosHeader) ) {
|
|
*rc = FILE_SKIPPED;
|
|
__leave;
|
|
}
|
|
|
|
TimeDateStamp = pNtHeader->FileHeader.TimeDateStamp;
|
|
|
|
if (pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
|
SizeOfImage = ((PIMAGE_NT_HEADERS32)pNtHeader)->OptionalHeader.SizeOfImage;
|
|
} else {
|
|
if (pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
|
SizeOfImage = ((PIMAGE_NT_HEADERS64)pNtHeader)->OptionalHeader.SizeOfImage;
|
|
} else {
|
|
SizeOfImage = 0;
|
|
}
|
|
}
|
|
|
|
} __finally {
|
|
SymCommonUnmapFile((LPCVOID)pDosHeader,DosFile);
|
|
}
|
|
|
|
if (*rc == FILE_SKIPPED)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
StringCbCopy( szPriPubBin, sizeof(szPriPubBin), _T("bin") );
|
|
|
|
GetSymbolServerDirs( szFileName,
|
|
NULL,
|
|
(DWORD) TimeDateStamp,
|
|
(DWORD) SizeOfImage,
|
|
szString );
|
|
|
|
temp_rc = StoreFile( szDestDir,
|
|
szFileName,
|
|
szString,
|
|
szPtrFileName );
|
|
|
|
*rc = (USHORT)temp_rc;
|
|
if (temp_rc) {
|
|
if (pArgs->CorruptBinaries) {
|
|
TCHAR BinToCorrupt[_MAX_PATH];
|
|
TCHAR Temp[_MAX_PATH];
|
|
LPTSTR pFilename;
|
|
DWORD dwRet = 0xFFFFFFFF;
|
|
|
|
SymCommonGetFullPathName(szDestDir, sizeof(BinToCorrupt)/sizeof(BinToCorrupt[0]), BinToCorrupt, &pFilename);
|
|
SymCommonGetFullPathName(szFileName, sizeof(Temp)/sizeof(Temp[0]), Temp, &pFilename);
|
|
StringCbCat(BinToCorrupt, sizeof(BinToCorrupt), szString );
|
|
StringCbCat(BinToCorrupt, sizeof(BinToCorrupt), TEXT("\\") );
|
|
StringCbCat(BinToCorrupt, sizeof(BinToCorrupt), pFilename );
|
|
|
|
if (! (dwRet=CorruptFile(BinToCorrupt))==PEWHACK_SUCCESS ) {
|
|
fprintf(stderr, "Unable to corrupt %s (0x%08x).\n", BinToCorrupt, dwRet);
|
|
}
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
else {
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
StorePdb(
|
|
LPTSTR szDestDir,
|
|
LPTSTR szFileName,
|
|
LPTSTR szPtrFileName,
|
|
USHORT *rc_flag
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Validates the PDB
|
|
|
|
Return Value:
|
|
TRUE PDB validates
|
|
FALSE PDB doesn't validate
|
|
--*/
|
|
|
|
{
|
|
|
|
BOOL rc;
|
|
|
|
BOOL valid;
|
|
PDB *pdb;
|
|
EC ec;
|
|
char szError[cbErrMax] = _T("");
|
|
SIG sig;
|
|
AGE age=0;
|
|
SIG70 sig70;
|
|
TCHAR szString[_MAX_PATH];
|
|
|
|
DBI *pdbi;
|
|
GSI *pgsi;
|
|
|
|
ZeroMemory( szString, _MAX_PATH * sizeof(TCHAR) );
|
|
ZeroMemory( &sig70, sizeof(SIG70) );
|
|
pdb=NULL;
|
|
|
|
__try
|
|
{
|
|
valid = PDBOpen( szFileName,
|
|
_T("r"),
|
|
0,
|
|
&ec,
|
|
szError,
|
|
&pdb
|
|
);
|
|
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
valid=FALSE;
|
|
}
|
|
|
|
if ( !valid ) {
|
|
SetLastError(ec);
|
|
*rc_flag = (USHORT)ec;
|
|
return FALSE;
|
|
}
|
|
|
|
// The DBI age is created when the exe is created.
|
|
// This age will not change if an operation is performed
|
|
// on the PDB that increments its PDB age.
|
|
|
|
__try
|
|
{
|
|
valid = PDBOpenDBI(pdb, pdbRead, NULL, &pdbi);
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
valid=FALSE;
|
|
}
|
|
|
|
if ( !valid ) {
|
|
SetLastError(ec);
|
|
*rc_flag = (USHORT)ec;
|
|
PDBClose(pdb);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Do we need to determine if this is a public or private pdb?
|
|
// If we do, then proceed through the next section.
|
|
//
|
|
// Windows stuffs type info into the kernels so this section tries
|
|
// a way around checking for type info to determine if this is a
|
|
// private pdb or not.
|
|
|
|
valid = TRUE;
|
|
|
|
__try
|
|
{
|
|
PrivateStripped=PDBPrivateStripped(pdb, pdbi);
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
valid = FALSE;
|
|
}
|
|
|
|
if ( !valid) {
|
|
DBIClose(pdbi);
|
|
PDBClose(pdb);
|
|
return FALSE;
|
|
}
|
|
|
|
if (PrivateStripped) {
|
|
StringCbCopy( szPriPubBin, sizeof(szPriPubBin), _T("pub") );
|
|
} else {
|
|
StringCbCopy( szPriPubBin, sizeof(szPriPubBin), _T("pri") );
|
|
}
|
|
|
|
// Determine if we are supposed to skip this file or index it.
|
|
|
|
if ( ( PrivateStripped && (pArgs->Filter == 2)) || // public pdb and index private pdbs
|
|
(!PrivateStripped && (pArgs->Filter == 1)) ) { // private pdb and index public pdbs
|
|
*rc_flag = FILE_SKIPPED;
|
|
DBIClose(pdbi);
|
|
PDBClose(pdb);
|
|
return TRUE;
|
|
}
|
|
|
|
if (PrivateStripped) {
|
|
StringCbCopy( szPriPubBin, sizeof(szPriPubBin), _T("pub") );
|
|
} else {
|
|
StringCbCopy( szPriPubBin, sizeof(szPriPubBin), _T("pri") );
|
|
}
|
|
|
|
age = pdbi->QueryAge();
|
|
// If the DBI age is zero, then use the pdb age
|
|
if ( age == 0 )
|
|
{
|
|
age = pdb->QueryAge();
|
|
}
|
|
sig = PDBQuerySignature(pdb);
|
|
rc = PDBQuerySignature2(pdb, &sig70);
|
|
|
|
DBIClose(pdbi);
|
|
PDBClose(pdb);
|
|
|
|
if (rc) {
|
|
GetSymbolServerDirs( szFileName,
|
|
&sig70,
|
|
(DWORD) sig,
|
|
(DWORD) age,
|
|
szString );
|
|
} else {
|
|
GetSymbolServerDirs( szFileName,
|
|
NULL,
|
|
(DWORD) sig,
|
|
(DWORD) age,
|
|
szString );
|
|
}
|
|
|
|
rc = StoreFile( szDestDir,
|
|
szFileName,
|
|
szString,
|
|
szPtrFileName
|
|
);
|
|
|
|
return (rc);
|
|
}
|