gerv%gerv.net 8b69962ee3 Bug 236613: change to MPL/LGPL/GPL tri-license.
git-svn-id: svn://10.0.0.236/trunk@155500 18797224-902f-48f8-a5cc-f745e15eee43
2004-04-25 21:07:34 +00:00

1001 lines
26 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "xp_mcom.h"
#include "zlib.h"
#include "nsSoftUpdateEnums.h"
#include "gdiff.h"
#ifdef WIN32
#include <windows.h>
#include <winnt.h>
#endif
#ifdef SUNOS4
#include <unistd.h> /* for SEEK_SET */
#endif
#ifdef XP_MAC
#include "Errors.h" /* for fnfErr */
#endif
/*--------------------------------------
* constants / macros
*------------------------------------*/
#define BUFSIZE 32768
#define OPSIZE 1
#define MAXCMDSIZE 12
#define SRCFILE 0
#define OUTFILE 1
#define getshort(s) (uint16)( ((uchar)*(s) << 8) + ((uchar)*((s)+1)) )
#define getlong(s) \
(uint32)( ((uchar)*(s) << 24) + ((uchar)*((s)+1) << 16 ) + \
((uchar)*((s)+2) << 8) + ((uchar)*((s)+3)) )
/*--------------------------------------
* prototypes
*------------------------------------*/
static int32 gdiff_ApplyPatch( pDIFFDATA dd );
static int32 gdiff_add( pDIFFDATA dd, uint32 count );
static int32 gdiff_copy( pDIFFDATA dd, uint32 position, uint32 count );
static int32 gdiff_getdiff( pDIFFDATA dd, uchar *buffer, uint32 length );
static int32 gdiff_parseHeader( pDIFFDATA dd );
static int32 gdiff_validateFile( pDIFFDATA dd, int file );
static int32 gdiff_valCRC32( pDIFFDATA dd, XP_File fh, uint32 chksum );
#ifdef WIN32
static XP_Bool su_unbind( char *oldsrc, XP_FileType, char *newsrc, XP_FileType);
#endif
/*--------------------------------------------------------------
* SU_PatchFile()
*
* Applies a GDIFF "patchfile" to "srcfile", creating
* the new "outfile" to contain the results
*--------------------------------------------------------------
*/
int32 SU_PatchFile( char* srcfile, XP_FileType srctype, char* patchfile,
XP_FileType patchtype, char* outfile, XP_FileType outtype )
{
DIFFDATA *dd;
int32 status = GDIFF_ERR_MEM;
char *realfile = srcfile;
XP_FileType realtype = srctype;
char *tmpurl = NULL;
dd = XP_CALLOC( 1, sizeof(DIFFDATA) );
if ( dd != NULL )
{
dd->databuf = XP_ALLOC(BUFSIZE);
if ( dd->databuf == NULL ) {
status = GDIFF_ERR_MEM;
goto cleanup;
}
dd->bufsize = BUFSIZE;
/* validate the patch header and check for special instructions */
dd->fDiff = XP_FileOpen( patchfile, patchtype, XP_FILE_READ_BIN );
if ( dd->fDiff != NULL ) {
status = gdiff_parseHeader( dd );
}
else {
status = GDIFF_ERR_ACCESS;
}
#ifdef WIN32
/* unbind Win32 images */
if ( dd->bWin32BoundImage && status == GDIFF_OK ) {
tmpurl = WH_TempName( xpURL, NULL );
if ( tmpurl != NULL ) {
if (su_unbind( srcfile, srctype, tmpurl, xpURL )) {
realfile = tmpurl;
realtype = xpURL;
}
}
else
status = GDIFF_ERR_MEM;
}
#endif
#ifdef XP_MAC
if ( dd->bMacAppleSingle && status == GDIFF_OK )
{
FSSpec srcFSSpec, tmpFSSpec;
char *srcMacPath, *tmpMacPath;
/* We need a tmp file so that we can AppleSingle the src file */
tmpurl = WH_TempName( xpURL, NULL );
/* Put the source file into a mac file path */
tmpMacPath = WH_FileName( tmpurl, xpURL );
/* Get the mac filepath for srcMacPath */
srcMacPath = WH_FileName( srcfile, srctype );
/* bail if we did not get our files! */
if ( tmpMacPath == NULL || srcMacPath == NULL)
{
XP_FREEIF( srcMacPath );
XP_FREEIF( tmpMacPath );
goto cleanup;
}
/* Get the source FSSpec */
status = FSpLocationFromFullPath(strlen(srcMacPath), srcMacPath, &srcFSSpec);
if (status != noErr)
{
XP_FREEIF( srcMacPath );
XP_FREEIF( tmpMacPath );
goto cleanup;
}
/* Get the temporary FSSpec. THis is where the encoded file will go */
status = FSpLocationFromFullPath(strlen(tmpMacPath), tmpMacPath, &tmpFSSpec);
if (status != noErr && status != fnfErr)
{
XP_FREEIF( srcMacPath );
XP_FREEIF( tmpMacPath );
goto cleanup;
}
/* Encode! */
status = PAS_EncodeFile(&srcFSSpec, &tmpFSSpec);
if (status == noErr)
{
/* set */
realfile = tmpurl;
realtype = xpURL;
}
XP_FREEIF( srcMacPath );
XP_FREEIF( tmpMacPath );
}
#endif
if ( status != GDIFF_OK )
goto cleanup;
/* apply the patch to the source file */
dd->fSrc = XP_FileOpen( realfile, realtype, XP_FILE_READ_BIN );
dd->fOut = XP_FileOpen( outfile, outtype, XP_FILE_TRUNCATE_BIN );
if ( dd->fSrc != NULL && dd->fOut != NULL )
{
status = gdiff_validateFile( dd, SRCFILE );
/* specify why diff failed */
if (status == GDIFF_ERR_CHECKSUM)
status = GDIFF_ERR_CHECKSUM_TARGET;
if ( status == GDIFF_OK )
status = gdiff_ApplyPatch( dd );
if ( status == GDIFF_OK )
status = gdiff_validateFile( dd, OUTFILE );
/* specify why diff failed */
if (status == GDIFF_ERR_CHECKSUM)
status = GDIFF_ERR_CHECKSUM_RESULT;
}
else
{
status = GDIFF_ERR_ACCESS;
}
}
#ifdef XP_MAC
if ( dd->bMacAppleSingle && status == GDIFF_OK )
{
FSSpec outFSSpec;
char *outMacPath;
char* anotherURL;
char* anotherURLMacPath;
FSSpec anotherFSSpec;
Str63 fileName;
/* We need a temp file so that we can decode somewhere */
anotherURL = WH_TempName( xpURL, NULL );
/* Get the mac file path for anotherURL */
anotherURLMacPath = WH_FileName( anotherURL, xpURL );
/* Get the mac file path for outfile */
outMacPath = WH_FileName( outfile, outtype );
if ( anotherURLMacPath == NULL || outMacPath == NULL)
{
status = mFulErr;
goto macPostProcessCleanup;
}
/* Get the out FSSpec. This is where the decoded will end up */
status = FSpLocationFromFullPath(strlen(outMacPath), outMacPath, &outFSSpec);
if (status != noErr)
{
goto macPostProcessCleanup;
}
/* Get the anotherURL FSSpec. This is where the decoded will first be placed */
status = FSpLocationFromFullPath(strlen(anotherURLMacPath), anotherURLMacPath, &anotherFSSpec);
if (status != noErr && status != fnfErr)
{
goto macPostProcessCleanup;
}
/* Close the out file so that we can read it */
XP_FileClose( dd->fOut );
dd->fOut = NULL;
status = PAS_DecodeFile(&outFSSpec, &anotherFSSpec);
if (status != noErr)
{
goto macPostProcessCleanup;
}
/* Delete the outfile so that we can replace */
XP_FileRemove( outfile, outtype );
/* get the name of the file */
BlockMove(outFSSpec.name, fileName, sizeof(Str63) );
/* We want the parent */
outFSSpec.name[0] = 0;
/* Copy the output of the decodef to the outfile location passed to us */
status = FSpFileCopy(&anotherFSSpec, &outFSSpec, fileName, NULL, 0,true);
if (status != noErr)
{
goto macPostProcessCleanup;
}
macPostProcessCleanup:
XP_FREEIF( outMacPath );
XP_FREEIF( anotherURLMacPath );
if(anotherURL)
{
XP_FileRemove( anotherURL, xpURL );
XP_FREEIF( anotherURL );
}
if (status != noErr)
{
goto cleanup;
}
}
#endif
cleanup:
if ( dd != NULL )
{
if ( dd->fSrc != NULL )
XP_FileClose( dd->fSrc );
if ( dd->fDiff != NULL )
XP_FileClose( dd->fDiff );
if ( dd->fOut != NULL )
XP_FileClose( dd->fOut );
if ( status != GDIFF_OK )
XP_FileRemove( outfile, outtype );
XP_FREEIF( dd->databuf );
XP_FREEIF( dd->oldChecksum );
XP_FREEIF( dd->newChecksum );
XP_FREE(dd);
}
if ( tmpurl != NULL ) {
XP_FileRemove( tmpurl, xpURL );
XP_FREE( tmpurl );
}
/* lets map any GDIFF error to nice SU errors */
switch (status)
{
case GDIFF_OK:
break;
case GDIFF_ERR_HEADER:
case GDIFF_ERR_BADDIFF:
case GDIFF_ERR_OPCODE:
case GDIFF_ERR_CHKSUMTYPE:
status = SUERR_PATCH_BAD_DIFF;
break;
case GDIFF_ERR_CHECKSUM_TARGET:
status = SUERR_PATCH_BAD_CHECKSUM_TARGET;
break;
case GDIFF_ERR_CHECKSUM_RESULT:
status = SUERR_PATCH_BAD_CHECKSUM_RESULT;
break;
case GDIFF_ERR_OLDFILE:
case GDIFF_ERR_ACCESS:
case GDIFF_ERR_MEM:
case GDIFF_ERR_UNKNOWN:
default:
status = SUERR_UNEXPECTED_ERROR;
break;
}
return status;
}
/*---------------------------------------------------------
* gdiff_ApplyPatch()
*
* Combines patch data with source file to produce the
* new target file. Assumes all three files have been
* opened, GDIFF header read, and all other setup complete
*
* The GDIFF patch is processed sequentially which random
* access is neccessary for the source file.
*---------------------------------------------------------
*/
static
int32 gdiff_ApplyPatch( pDIFFDATA dd )
{
int32 err;
XP_Bool done;
uint32 position;
uint32 count;
uchar opcode;
uchar cmdbuf[MAXCMDSIZE];
done = FALSE;
while ( !done ) {
err = gdiff_getdiff( dd, &opcode, OPSIZE );
if ( err != GDIFF_OK )
break;
switch (opcode)
{
case ENDDIFF:
done = TRUE;
break;
case ADD16:
err = gdiff_getdiff( dd, cmdbuf, ADD16SIZE );
if ( err == GDIFF_OK ) {
err = gdiff_add( dd, getshort( cmdbuf ) );
}
break;
case ADD32:
err = gdiff_getdiff( dd, cmdbuf, ADD32SIZE );
if ( err == GDIFF_OK ) {
err = gdiff_add( dd, getlong( cmdbuf ) );
}
break;
case COPY16BYTE:
err = gdiff_getdiff( dd, cmdbuf, COPY16BYTESIZE );
if ( err == GDIFF_OK ) {
position = getshort( cmdbuf );
count = *(cmdbuf + sizeof(short));
err = gdiff_copy( dd, position, count );
}
break;
case COPY16SHORT:
err = gdiff_getdiff( dd, cmdbuf, COPY16SHORTSIZE );
if ( err == GDIFF_OK ) {
position = getshort( cmdbuf );
count = getshort(cmdbuf + sizeof(short));
err = gdiff_copy( dd, position, count );
}
break;
case COPY16LONG:
err = gdiff_getdiff( dd, cmdbuf, COPY16LONGSIZE );
if ( err == GDIFF_OK ) {
position = getshort( cmdbuf );
count = getlong(cmdbuf + sizeof(short));
err = gdiff_copy( dd, position, count );
}
break;
case COPY32BYTE:
err = gdiff_getdiff( dd, cmdbuf, COPY32BYTESIZE );
if ( err == GDIFF_OK ) {
position = getlong( cmdbuf );
count = *(cmdbuf + sizeof(long));
err = gdiff_copy( dd, position, count );
}
break;
case COPY32SHORT:
err = gdiff_getdiff( dd, cmdbuf, COPY32SHORTSIZE );
if ( err == GDIFF_OK ) {
position = getlong( cmdbuf );
count = getshort(cmdbuf + sizeof(long));
err = gdiff_copy( dd, position, count );
}
break;
case COPY32LONG:
err = gdiff_getdiff( dd, cmdbuf, COPY32LONGSIZE );
if ( err == GDIFF_OK ) {
position = getlong( cmdbuf );
count = getlong(cmdbuf + sizeof(long));
err = gdiff_copy( dd, position, count );
}
break;
case COPY64:
/* we don't support 64-bit file positioning yet */
err = GDIFF_ERR_OPCODE;
break;
default:
err = gdiff_add( dd, opcode );
break;
}
if ( err != GDIFF_OK )
done = TRUE;
}
/* return status */
return (err);
}
/*---------------------------------------------------------
* gdiff_add()
*
* append "count" bytes from diff file to new file
*---------------------------------------------------------
*/
static
int32 gdiff_add( pDIFFDATA dd, uint32 count )
{
int32 err = GDIFF_OK;
uint32 nRead;
uint32 chunksize;
while ( count > 0 ) {
chunksize = ( count > dd->bufsize) ? dd->bufsize : count;
nRead = XP_FileRead( dd->databuf, chunksize, dd->fDiff );
if ( nRead != chunksize ) {
err = GDIFF_ERR_BADDIFF;
break;
}
XP_FileWrite( dd->databuf, chunksize, dd->fOut );
count -= chunksize;
}
return (err);
}
/*---------------------------------------------------------
* gdiff_copy()
*
* copy "count" bytes from "position" in source file
*---------------------------------------------------------
*/
static
int32 gdiff_copy( pDIFFDATA dd, uint32 position, uint32 count )
{
int32 err = GDIFF_OK;
uint32 nRead;
uint32 chunksize;
XP_FileSeek( dd->fSrc, position, SEEK_SET );
while ( count > 0 ) {
chunksize = (count > dd->bufsize) ? dd->bufsize : count;
nRead = XP_FileRead( dd->databuf, chunksize, dd->fSrc );
if ( nRead != chunksize ) {
err = GDIFF_ERR_OLDFILE;
break;
}
XP_FileWrite( dd->databuf, chunksize, dd->fOut );
count -= chunksize;
}
return (err);
}
/*---------------------------------------------------------
* gdiff_getdiff()
*
* reads the next "length" bytes of the diff into "buffer"
*
* XXX: need a diff buffer to optimize reads!
*---------------------------------------------------------
*/
static
int32 gdiff_getdiff( pDIFFDATA dd, uchar *buffer, uint32 length )
{
uint32 bytesRead;
bytesRead = XP_FileRead( buffer, length, dd->fDiff );
if ( bytesRead != length )
return GDIFF_ERR_BADDIFF;
return GDIFF_OK;
}
/*---------------------------------------------------------
* gdiff_parseHeader()
*
* reads and validates the GDIFF header info
*---------------------------------------------------------
*/
static
int32 gdiff_parseHeader( pDIFFDATA dd )
{
int32 err = GDIFF_OK;
uint8 cslen;
uint8 oldcslen;
uint8 newcslen;
uint32 nRead;
uchar header[GDIFF_HEADERSIZE];
/* Read the fixed-size part of the header */
nRead = XP_FileRead( header, GDIFF_HEADERSIZE, dd->fDiff );
if ( nRead != GDIFF_HEADERSIZE ||
XP_MEMCMP( header, GDIFF_MAGIC, GDIFF_MAGIC_LEN ) != 0 ||
header[GDIFF_VER_POS] != GDIFF_VER )
{
err = GDIFF_ERR_HEADER;
}
else
{
/* get the checksum information */
dd->checksumType = header[GDIFF_CS_POS];
cslen = header[GDIFF_CSLEN_POS];
if ( cslen > 0 )
{
oldcslen = cslen / 2;
newcslen = cslen - oldcslen;
XP_ASSERT( newcslen == oldcslen );
dd->checksumLength = oldcslen;
dd->oldChecksum = XP_ALLOC(oldcslen);
dd->newChecksum = XP_ALLOC(newcslen);
if ( dd->oldChecksum != NULL && dd->newChecksum != NULL )
{
nRead = XP_FileRead( dd->oldChecksum, oldcslen, dd->fDiff );
if ( nRead == oldcslen )
{
nRead = XP_FileRead( dd->newChecksum, newcslen, dd->fDiff);
if ( nRead != newcslen ) {
err = GDIFF_ERR_HEADER;
}
}
else {
err = GDIFF_ERR_HEADER;
}
}
else {
err = GDIFF_ERR_MEM;
}
}
/* get application data, if any */
if ( err == GDIFF_OK )
{
uint32 appdataSize;
uchar *buf;
uchar lenbuf[GDIFF_APPDATALEN];
nRead = XP_FileRead( lenbuf, GDIFF_APPDATALEN, dd->fDiff );
if ( nRead == GDIFF_APPDATALEN )
{
appdataSize = getlong(lenbuf);
if ( appdataSize > 0 )
{
buf = (uchar *)XP_ALLOC( appdataSize );
if ( buf != NULL )
{
nRead = XP_FileRead( buf, appdataSize, dd->fDiff );
if ( nRead == appdataSize )
{
if ( 0 == XP_MEMCMP( buf, APPFLAG_W32BOUND, appdataSize ) )
dd->bWin32BoundImage = TRUE;
if ( 0 == XP_MEMCMP( buf, APPFLAG_APPLESINGLE, appdataSize ) )
dd->bMacAppleSingle = TRUE;
}
else {
err = GDIFF_ERR_HEADER;
}
XP_FREE( buf );
}
else {
err = GDIFF_ERR_MEM;
}
}
}
else {
err = GDIFF_ERR_HEADER;
}
}
}
return (err);
}
/*---------------------------------------------------------
* gdiff_validateFile()
*
* computes the checksum of the file and compares it to
* the value stored in the GDIFF header
*---------------------------------------------------------
*/
static
int32 gdiff_validateFile( pDIFFDATA dd, int file )
{
int32 result;
XP_File fh;
uchar * chksum;
/* which file are we dealing with? */
if ( file == SRCFILE ) {
fh = dd->fSrc;
chksum = dd->oldChecksum;
}
else { /* OUTFILE */
fh = dd->fOut;
chksum = dd->newChecksum;
}
/* make sure file's at beginning */
XP_FileSeek( fh, 0, SEEK_SET );
/* calculate appropriate checksum */
switch (dd->checksumType)
{
case GDIFF_CS_NONE:
result = GDIFF_OK;
break;
case GDIFF_CS_CRC32:
if ( dd->checksumLength == CRC32_LEN )
result = gdiff_valCRC32( dd, fh, getlong(chksum) );
else
result = GDIFF_ERR_HEADER;
break;
case GDIFF_CS_MD5:
case GDIFF_CS_SHA:
default:
/* unsupported checksum type */
result = GDIFF_ERR_CHKSUMTYPE;
break;
}
/* reset file position to beginning and return status */
XP_FileSeek( fh, 0, SEEK_SET );
return (result);
}
/*---------------------------------------------------------
* gdiff_valCRC32()
*
* computes the checksum of the file and compares it to
* the passed in checksum. Assumes file is positioned at
* beginning.
*---------------------------------------------------------
*/
static
int32 gdiff_valCRC32( pDIFFDATA dd, XP_File fh, uint32 chksum )
{
uint32 crc;
uint32 nRead;
crc = crc32(0L, Z_NULL, 0);
nRead = XP_FileRead( dd->databuf, dd->bufsize, fh );
while ( nRead > 0 )
{
crc = crc32( crc, dd->databuf, nRead );
nRead = XP_FileRead( dd->databuf, dd->bufsize, fh );
}
if ( crc == chksum )
return GDIFF_OK;
else
return GDIFF_ERR_CHECKSUM;
}
#ifdef WIN32
/*---------------------------------------------------------
* su_unbind()
*
* strips import binding information from Win32
* executables and .DLL's
*---------------------------------------------------------
*/
static
XP_Bool su_unbind( char *oldurl, XP_FileType oldtype, char *newurl, XP_FileType newtype)
{
XP_Bool bSuccess = FALSE;
char *oldfile;
char *newfile;
int i;
DWORD nRead;
PDWORD pOrigThunk;
PDWORD pBoundThunk;
FILE *fh = NULL;
char *buf;
BOOL bModified = FALSE;
BOOL bImports = FALSE;
IMAGE_DOS_HEADER mz;
IMAGE_NT_HEADERS nt;
IMAGE_SECTION_HEADER sec;
PIMAGE_DATA_DIRECTORY pDir;
PIMAGE_IMPORT_DESCRIPTOR pImp;
typedef BOOL (__stdcall *BINDIMAGEEX)(DWORD Flags,
LPSTR ImageName,
LPSTR DllPath,
LPSTR SymbolPath,
PVOID StatusRoutine);
HINSTANCE hImageHelp;
BINDIMAGEEX pfnBindImageEx;
oldfile = WH_FileName( oldurl, oldtype );
newfile = WH_FileName( newurl, newtype );
if ( oldfile != NULL && newfile != NULL &&
CopyFile( oldfile, newfile, FALSE ) )
{
/* call BindImage() first to make maximum room for a possible
* NT-style Bound Import Descriptors which can change various
* offsets in the file */
hImageHelp = LoadLibrary("IMAGEHLP.DLL");
if ( hImageHelp > (HINSTANCE)HINSTANCE_ERROR ) {
pfnBindImageEx = (BINDIMAGEEX)GetProcAddress(hImageHelp, "BindImageEx");
if (pfnBindImageEx) {
pfnBindImageEx(0, newfile, NULL, NULL, NULL);
}
FreeLibrary(hImageHelp);
}
fh = fopen( newfile, "r+b" );
if ( fh == NULL )
goto bail;
/* read and validate the MZ header */
nRead = fread( &mz, 1, sizeof(mz), fh );
if ( nRead != sizeof(mz) || mz.e_magic != IMAGE_DOS_SIGNATURE )
goto bail;
/* read and validate the NT header */
fseek( fh, mz.e_lfanew, SEEK_SET );
nRead = fread( &nt, 1, sizeof(nt), fh );
if ( nRead != sizeof(nt) ||
nt.Signature != IMAGE_NT_SIGNATURE ||
nt.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC )
{
goto bail;
}
/* find .idata section */
for (i = nt.FileHeader.NumberOfSections; i > 0; i--)
{
nRead = fread( &sec, 1, sizeof(sec), fh );
if ( nRead != sizeof(sec) )
goto bail;
if ( memcmp( sec.Name, ".idata", 6 ) == 0 ) {
bImports = TRUE;
break;
}
}
/* Zap any binding in the imports section */
if ( bImports )
{
buf = (char*)malloc( sec.SizeOfRawData );
if ( buf == NULL )
goto bail;
fseek( fh, sec.PointerToRawData, SEEK_SET );
nRead = fread( buf, 1, sec.SizeOfRawData, fh );
if ( nRead != sec.SizeOfRawData ) {
free( buf );
goto bail;
}
pImp = (PIMAGE_IMPORT_DESCRIPTOR)buf;
while ( pImp->OriginalFirstThunk != 0 )
{
if ( pImp->TimeDateStamp != 0 || pImp->ForwarderChain != 0 )
{
/* found a bound .DLL */
pImp->TimeDateStamp = 0;
pImp->ForwarderChain = 0;
bModified = TRUE;
pOrigThunk = (PDWORD)(buf + (DWORD)(pImp->OriginalFirstThunk) - sec.VirtualAddress);
pBoundThunk = (PDWORD)(buf + (DWORD)(pImp->FirstThunk) - sec.VirtualAddress);
for ( ; *pOrigThunk != 0; pOrigThunk++, pBoundThunk++ ) {
*pBoundThunk = *pOrigThunk;
}
}
pImp++;
}
if ( bModified )
{
/* it's been changed, write out the section */
fseek( fh, sec.PointerToRawData, SEEK_SET );
fwrite( buf, 1, sec.SizeOfRawData, fh );
}
free( buf );
}
/* Check for a Bound Import Directory in the headers */
pDir = &nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT];
if ( pDir->VirtualAddress != 0 )
{
/* we've got one, so stomp it */
buf = (char*)calloc( pDir->Size, 1 );
if ( buf == NULL )
goto bail;
fseek( fh, pDir->VirtualAddress, SEEK_SET );
fwrite( buf, pDir->Size, 1, fh );
free( buf );
pDir->VirtualAddress = 0;
pDir->Size = 0;
bModified = TRUE;
}
/* Write out changed headers if necessary */
if ( bModified )
{
/* zap checksum since it's now invalid */
nt.OptionalHeader.CheckSum = 0;
fseek( fh, mz.e_lfanew, SEEK_SET );
fwrite( &nt, 1, sizeof(nt), fh );
}
bSuccess = TRUE;
}
bail:
if ( fh != NULL )
fclose(fh);
XP_FREEIF( oldfile );
XP_FREEIF( newfile );
return bSuccess;
}
#endif