merging from SMARTUPDATE_BRANCH

This commit is contained in:
dveditz 1998-06-07 09:57:07 +00:00
parent 4851688af2
commit 659dd5acd0
6 changed files with 919 additions and 239 deletions

View File

@ -17,9 +17,11 @@
DEPTH = ../../../..
REQUIRES = softupdt
REQUIRES = softupdt zlib
CSRCS = nsdiff.c
CSRCS = nsdiff.c crc32.c
COPY = cp -p
PROGRAM = nsdiff$(BIN_SUFFIX)
@ -31,3 +33,7 @@ symbols:
@echo "PROGRAM = $(PROGRAM)"
@echo "LIBRARY = $(LIBRARY)"
@echo "TARGETS = $(TARGETS)"
crc32.c: $(DEPTH)/modules/zlib/src/crc32.c
@$(RM) $@
@$(COPY) $< $@

View File

@ -33,11 +33,13 @@ include <$(DEPTH)\config\config.mak>
PDBFILE = nsdiff.pdb
MAPFILE = nsdiff.map
REQUIRES=softupdt
CSRCS=nsdiff.c
C_OBJS=.\$(OBJDIR)\nsdiff.obj
REQUIRES=softupdt zlib
CSRCS=nsdiff.c crc32.c
C_OBJS=.\$(OBJDIR)\nsdiff.obj .\$(OBJDIR)\crc32.obj
!if "$(MOZ_BITS)" != "16"
LINCS=-I$(XPDIST)\public\softupdt
LINCS= \
-I$(XPDIST)\public\softupdt \
-I$(XPDIST)\public\zlib
!endif
include <$(DEPTH)\config\rules.mak>
@ -64,3 +66,6 @@ symbols:
@echo "DBM_LIB = $(DBM_LIB)"
@echo "INSTALL = $(INSTALL)"
crc32.c: $(DEPTH)/modules/zlib/src/crc32.c
@$(RM) $@
copy $(DEPTH)\modules\zlib\src\crc32.c $@

View File

@ -20,9 +20,9 @@
*
* A binary file diffing utility that creates diffs in GDIFF format
*
* nsdiff [-b"blocksize"] [-o"outfile"] oldfile newfile
* nsdiff [-b#] [-d] [-c#] [-o"outfile"] oldfile newfile
*
* Blocksize defaults to 32.
* Blocksize defaults to 64
* The outfile defaults to "newfile" with a .GDF extension
*
*------------------------------------------------------------------*/
@ -31,34 +31,26 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "gdiff.h"
/*--------------------------------------
* constants
*------------------------------------*/
#define IGNORE_SIZE 7
#define DEFAULT_BLOCKSIZE 32
#define FILENAMESIZE 513
#define OLDBUFSIZE 0x1FFF
#define MAXBUFSIZE 0xFFFF /* more requires long adds, wasting space */
#define CHKMOD 65536
#define HTBLSIZE 65521
#define destroyFdata(fd) { if ((fd)->data != NULL) free((fd)->data); }
#include "zlib.h"
/*--------------------------------------
* types
*------------------------------------*/
#if 0
/* zlib.h appears to define these now. If it stops remove the #if */
typedef unsigned long uint32;
typedef long int32;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned char uchar;
typedef unsigned char BOOL;
typedef unsigned char uint8;
#endif
typedef unsigned char XP_Bool;
typedef FILE* XP_File;
#include "gdiff.h"
typedef struct hnode {
uint32 chksum; /* true checksum of the block */
@ -74,15 +66,39 @@ typedef struct filedata {
uint32 bufsize; /* the physical size of the memory buffer */
uchar * data; /* a "bufsize" memory block for data */
FILE * file; /* file handle */
BOOL bDoAdds; /* If true check for "add" data before reading */
XP_Bool bDoAdds; /* If true check for "add" data before reading */
} FILEDATA;
/*--------------------------------------
* constants
*------------------------------------*/
#define IGNORE_SIZE 8
#define DEFAULT_BLOCKSIZE 64
#define FILENAMESIZE 513
#define OLDBUFSIZE 0x1FFF
#define MAXBUFSIZE 0xFFFF /* more requires long adds, wasting space */
#define CHKMOD 65536
#define HTBLSIZE 65521
#define destroyFdata(fd) do { if ((fd)->data != NULL) free((fd)->data); } while (0)
#define writelong(n,buf) do { \
*((buf)) = (uchar)( (n) >> 24 ); \
*((buf)+1) = (uchar)( ( (n) >> 16 ) & 0x00FF ); \
*((buf)+2) = (uchar)( ( (n) >> 8 ) & 0x00FF ); \
*((buf)+3) = (uchar)( (n) & 0x00FF ); } while(0)
/*--------------------------------------
* prototypes
*------------------------------------*/
void add( uchar *data, uint32 count, FILE *outf );
void adddata( FILEDATA *fd );
void calchash( uint8 type, FILE *fh, uchar *outbuf, int *outlen );
void copy( uint32 offset, uint32 count, FILE *outf );
uint32 checksum( uchar *buffer, uint32 offset, uint32 count );
HPTR *chunkOldFile( FILE *fh, uint32 blocksize );
@ -90,20 +106,28 @@ void cleanup( void );
uint32 compareFdata( FILEDATA *oldfd, uint32 oldpos, FILEDATA *newfd );
void diff( FILE *oldf, FILE *newf, FILE *outf );
uint32 getChecksum( FILEDATA *fd );
BOOL getFdata( FILEDATA *fdata, uint32 position );
BOOL initFdata( FILEDATA *fdata, FILE *file, uint32 bufsize, BOOL bDoAdds );
BOOL moreFdata( FILEDATA *fdata );
XP_Bool getFdata( FILEDATA *fdata, uint32 position );
XP_Bool initFdata( FILEDATA *fdata, FILE *file, uint32 bufsize, XP_Bool bDoAdds );
XP_Bool moreFdata( FILEDATA *fdata );
int openFiles( void );
void readFdata( FILEDATA *fdata, uint32 position );
void usage( void );
BOOL validateArgs( int argc, char *argv[] );
void writeHeader( FILE *outf );
XP_Bool validateArgs( int argc, char *argv[] );
void writeHeader( FILE *oldf, FILE *newf, FILE *outf );
#ifdef XP_PC
XP_Bool unbind( FILE *oldf );
XP_Bool unbindFile( char *name );
XP_Bool hasImports( FILE *oldf );
#endif
/*--------------------------------------
* Global data
*------------------------------------*/
XP_Bool bDebug = FALSE;
char *oldname = NULL,
*newname = NULL,
*outname = NULL;
@ -112,10 +136,19 @@ FILE *oldfile,
*newfile,
*outfile;
uint32 blocksize = DEFAULT_BLOCKSIZE;
uint32 blocksize = DEFAULT_BLOCKSIZE;
uint8 chksumtype = GDIFF_CS_CRC32;
HPTR *htbl;
uint32 addtotal = 0,
addmax = 0,
addnum = 0,
copymax = 0,
copynum = 0,
copytotal = 0;
/* for hashing stats */
uint32 slotsused = 0,
blockshashed = 0,
@ -124,6 +157,10 @@ uint32 slotsused = 0,
partialmatch = 0,
cmpfailed = 0;
#ifdef XP_PC
XP_Bool bUnbind = TRUE;
#endif /* XP_PC */
/*--------------------------------------
* main
@ -136,26 +173,31 @@ int main( int argc, char *argv[] )
/* Parse command line */
if ( !validateArgs( argc, argv ) ) {
err = ERR_ARGS;
err = GDIFF_ERR_ARGS;
}
else {
err = openFiles();
}
#ifdef XP_PC
/* unbind windows executables if requested */
if ( bUnbind )
bUnbind = (err == GDIFF_OK) ? unbind( oldfile ) : FALSE;
#endif /* XP_PC */
/* Calculate block checksums in old file */
if ( err == ERR_OK ) {
if ( err == GDIFF_OK ) {
htbl = chunkOldFile( oldfile, blocksize );
if ( htbl == NULL )
err = ERR_MEM;
err = GDIFF_ERR_MEM;
}
/* Do the diff */
if ( err == ERR_OK ) {
writeHeader( outfile );
if ( err == GDIFF_OK ) {
writeHeader( oldfile, newfile, outfile );
diff( oldfile, newfile, outfile );
}
@ -167,26 +209,18 @@ int main( int argc, char *argv[] )
/* Report status */
if ( err == ERR_OK ) {
fprintf( stderr, "\nHashed %ld blocks into %ld slots (out of %ld)\n",
blockshashed, slotsused, HTBLSIZE );
fprintf( stderr, "Blocks found: %ld\n", blocksfound );
fprintf( stderr, "Hashtable hits: %ld\n", hashhits );
fprintf( stderr, "memcmps failed: %ld\n", cmpfailed );
fprintf( stderr, "partial matches: %ld\n", partialmatch );
}
else {
if ( err != GDIFF_OK ) {
switch (err) {
case ERR_ARGS:
case GDIFF_ERR_ARGS:
fprintf( stderr, "Invalid arguments\n" );
usage();
break;
case ERR_ACCESS:
case GDIFF_ERR_ACCESS:
fprintf( stderr, "Error opening file\n" );
break;
case ERR_MEM:
case GDIFF_ERR_MEM:
fprintf( stderr, "Insufficient memory\n" );
break;
@ -195,6 +229,16 @@ int main( int argc, char *argv[] )
break;
}
}
else if ( bDebug ) {
fprintf( stderr, "\nHashed %ld blocks into %ld slots (out of %ld)\n",
blockshashed, slotsused, HTBLSIZE );
fprintf( stderr, "Blocks found: %ld\n", blocksfound );
fprintf( stderr, "Hashtable hits: %ld\n", hashhits );
fprintf( stderr, "memcmps failed: %ld\n", cmpfailed );
fprintf( stderr, "partial matches: %ld\n", partialmatch );
fprintf( stderr, "\n%ld bytes in %ld ADDs (%ld in largest)\n", addtotal, addnum, addmax );
fprintf( stderr, "%ld bytes in %ld COPYs (%ld in largest)\n", copytotal, copynum, copymax );
}
return (err);
}
@ -208,8 +252,15 @@ void add( uchar *data, uint32 count, FILE *outf )
{
uchar numbuf[5];
addnum++;
addtotal += count;
if ( count > addmax )
addmax = count;
#ifdef DEBUG
fprintf( stderr, "Adding %ld bytes\n", count );
if ( bDebug ) {
fprintf( stderr, "Adding %ld bytes\n", count );
}
#endif
if ( count == 0 )
@ -245,8 +296,16 @@ void add( uchar *data, uint32 count, FILE *outf )
void copy( uint32 offset, uint32 count, FILE *outf )
{
uchar numbuf[9];
copynum++;
copytotal += count;
if ( count > copymax )
copymax = count;
#ifdef DEBUG
fprintf( stderr, "Copying %ld bytes from offset %ld\n", count, offset );
if ( bDebug ) {
fprintf( stderr, "Copying %ld bytes from offset %ld\n", count, offset );
}
#endif
if ( count == 0 )
@ -343,7 +402,9 @@ HPTR *chunkOldFile( FILE *fh, uint32 blocksize )
bufsize = ( MAXBUFSIZE / blocksize ) * blocksize ;
#ifdef DEBUG
fprintf( stderr, "bufsize: %ld, tblsize: %ld\n", bufsize, HTBLSIZE*sizeof(HPTR) );
if ( bDebug ) {
fprintf( stderr, "bufsize: %ld, tblsize: %ld\n", bufsize, HTBLSIZE*sizeof(HPTR) );
}
#endif
table = (HPTR*)malloc( HTBLSIZE * sizeof(HPTR) );
@ -361,9 +422,6 @@ HPTR *chunkOldFile( FILE *fh, uint32 blocksize )
filepos = 0;
do {
bytesRead = fread( buffer, 1, bufsize, fh );
#ifdef DEBUG
fprintf( stderr, "read %ld bytes\n", bytesRead );
#endif
i = 0;
while ( i < bytesRead ) {
@ -452,10 +510,14 @@ void cleanup()
free( htbl );
}
#ifdef XP_PC
if ( bUnbind )
unlink( oldname );
#endif
}
#ifndef OLDDIFF
/*--------------------------------------
* diff
*------------------------------------*/
@ -558,7 +620,7 @@ bail:
}
BOOL initFdata( FILEDATA *fdata, FILE *file, uint32 bufsize, BOOL bDoAdds )
XP_Bool initFdata( FILEDATA *fdata, FILE *file, uint32 bufsize, XP_Bool bDoAdds )
{
fdata->filepos = 0;
fdata->offset = 0;
@ -577,7 +639,7 @@ BOOL initFdata( FILEDATA *fdata, FILE *file, uint32 bufsize, BOOL bDoAdds )
return (TRUE);
}
BOOL moreFdata( FILEDATA *fd )
XP_Bool moreFdata( FILEDATA *fd )
{
if ( fd->offset < fd->datalen ) {
/* pointer still in buffer */
@ -595,7 +657,7 @@ BOOL moreFdata( FILEDATA *fd )
}
}
BOOL getFdata( FILEDATA *fd, uint32 position )
XP_Bool getFdata( FILEDATA *fd, uint32 position )
{
if ( (position >= fd->filepos) && (position < (fd->filepos+fd->datalen)) ) {
/* the position is available in the current buffer */
@ -631,9 +693,6 @@ void readFdata( FILEDATA *fd, uint32 position )
fd->filepos = position;
fd->offset = 0;
fd->unwritten = 0;
#ifdef DEBUG
fprintf(stderr,"Read %ld %s bytes\n",fd->datalen, fd->bDoAdds?"NEW":"old");
#endif
}
void adddata( FILEDATA *fd )
@ -723,118 +782,6 @@ uint32 getChecksum( FILEDATA *fd )
}
#else /* !NEWDIFF, i.e. old buggy diff */
/*--------------------------------------
* diff
*------------------------------------*/
void diff( FILE *oldf, FILE *newf, FILE *outf )
{
uchar *olddata,
*newdata;
uint32 rChk,
i,
unwritten,
hash,
maxShifts,
oldbytes,
bytesRead;
HPTR node;
olddata = (uchar*)malloc(blocksize);
newdata = (uchar*)malloc(MAXBUFSIZE);
if (olddata == NULL || newdata == NULL ) {
fprintf( stderr, "Out of memory!\n" );
goto bail;
}
do {
bytesRead = fread( newdata, 1, MAXBUFSIZE, newf );
if ( bytesRead >= blocksize )
maxShifts = (bytesRead - blocksize + 1);
else
maxShifts = 0;
#ifdef DEBUG
fprintf( stderr, "read %ld new bytes\n", bytesRead );
#endif
unwritten = 0;
for ( i=0; i < maxShifts ; i++ ) {
/* wastefully slow, convert to rolling checksum */
rChk = checksum( newdata, i, blocksize );
hash = rChk % HTBLSIZE;
node = htbl[hash];
while( node != NULL ) {
hashhits++;
/* compare checksums to see if this might really be a match */
if ( rChk != node->chksum ) {
/* can't be a match */
node = node->next;
}
else {
/* might be a match, compare actual bits */
fseek( oldf, node->offset, SEEK_SET );
oldbytes = fread( olddata, 1, blocksize, oldf );
if ( memcmp( olddata, newdata+i, oldbytes ) != 0 ) {
cmpfailed++;
node = node->next;
}
else {
blocksfound++;
/* add any unmatched bytes from new file */
if ( i > unwritten )
add( newdata+unwritten, i-unwritten, outf );
/* copy the matched block from old file */
copy( node->offset, oldbytes, outf );
/* skip the copied bytes */
unwritten = (i + oldbytes);
/* "i" gets one less, the "for" increments it */
i = unwritten - 1;
/* done with this hash entry */
node = NULL;
}
}
}
}
/* prepare to read another block */
if ( unwritten < i ) {
/* add the unmatched data */
add( newdata+unwritten, i-unwritten, outf );
}
#if 0
if ( i < bytesRead ) {
/* shift filepointer back so uncompared data isn't missed */
fseek( newf, (i - bytesRead), SEEK_CUR );
}
#endif
} while ( bytesRead > 0 );
/* Terminate the GDIFF file */
fwrite( GDIFF_EOF, 1, 1, outf );
bail:
if ( olddata != NULL )
free( olddata );
if (newdata != NULL )
free( newdata );
}
#endif /* NEWDIFF */
/*--------------------------------------
* openFiles
@ -847,13 +794,13 @@ int openFiles()
oldfile = fopen( oldname, "rb" );
if ( oldfile == NULL ) {
fprintf( stderr, "Can't open %s for reading\n", oldname );
return ERR_ACCESS;
return GDIFF_ERR_ACCESS;
}
newfile = fopen( newname, "rb" );
if ( newfile == NULL ) {
fprintf( stderr, "Can't open %s for reading\n", newname );
return ERR_ACCESS;
return GDIFF_ERR_ACCESS;
}
if ( outname == NULL || *outname == '\0' ) {
@ -864,10 +811,10 @@ int openFiles()
outfile = fopen( outname, "wb" );
if ( outfile == NULL ) {
fprintf( stderr, "Can't open %s for writing\n", outname );
return ERR_ACCESS;
return GDIFF_ERR_ACCESS;
}
return ERR_OK;
return GDIFF_OK;
}
@ -880,7 +827,17 @@ void usage ()
fprintf( stderr, "\n NSDiff [-b#] [-o\"outfile\"] oldfile newfile\n\n" );
fprintf( stderr, " -b size of blocks to compare in bytes, " \
"default %d\n", DEFAULT_BLOCKSIZE );
fprintf( stderr, " -o name of output diff file\n\n" );
fprintf( stderr, " -c# checksum type\n");
fprintf( stderr, " 1: MD5 (not supported yet)\n");
fprintf( stderr, " 2: SHA (not supported yet)\n");
fprintf( stderr, " 32: CRC-32 (default)\n");
fprintf( stderr, " -d diagnostic output\n" );
fprintf( stderr, " -o name of output diff file\n" );
#ifdef XP_PC
fprintf( stderr, " -wb- turn off special handling for Win32 bound images\n" );
#endif
fprintf( stderr, "\n" );
}
@ -888,7 +845,7 @@ void usage ()
* validateArgs
*------------------------------------*/
BOOL validateArgs( int argc, char *argv[] )
XP_Bool validateArgs( int argc, char *argv[] )
{
int i;
for ( i = 1; i < argc; i++ ) {
@ -898,10 +855,34 @@ BOOL validateArgs( int argc, char *argv[] )
blocksize = atoi( argv[i]+2 );
break;
case 'c':
chksumtype = atoi( argv[i]+2 );
break;
case 'o':
outname = argv[i]+2;
break;
case 'd':
bDebug = TRUE;
break;
#ifdef XP_PC
/* windows only option. -wb to set-up for bound
* images (the default) -wb- to turn it off */
case 'w':
if ( *(argv[i]+2) == 'b' ) {
if ( *(argv[i]+3) == '-' )
bUnbind = FALSE;
else
bUnbind = TRUE;
}
else {
fprintf( stderr, "Unknown windows option %s\n", argv[i] );
return (FALSE);
}
#endif /* XP_PC */
default:
fprintf( stderr, "Unknown option %s\n", argv[i] );
return (FALSE);
@ -918,12 +899,6 @@ BOOL validateArgs( int argc, char *argv[] )
return (FALSE);
}
}
#ifdef DEBUG
fprintf( stderr, "Blocksize: %d\n", blocksize );
fprintf( stderr, "Old file: %s\n", oldname );
fprintf( stderr, "New file: %s\n", newname );
fprintf( stderr, "diff file: %s\n", outname );
#endif
/* validate arguments */
@ -945,8 +920,381 @@ BOOL validateArgs( int argc, char *argv[] )
* writeHeader
*------------------------------------*/
void writeHeader( FILE *outf )
void writeHeader( FILE *oldf, FILE *newf, FILE *outf )
{
fwrite( "\xd1\xff\xd1\xff\05\0\0\0\0\0\0", 1, 11, outf );
uchar databuf[512];
int datalen;
int oldlen, newlen, applen;
uchar *plen;
/* magic number and version */
memcpy( databuf, "\xd1\xff\xd1\xff\05", 5 );
datalen = 5;
/* calculate and store checksum info */
databuf[datalen] = chksumtype;
datalen++;
databuf[datalen] = 0; /* initial checksum length */
plen = databuf+datalen;
datalen++;
calchash( chksumtype, oldf, databuf+datalen, &oldlen );
datalen += oldlen;
calchash( chksumtype, newf, databuf+datalen, &newlen );
datalen += newlen;
*plen = oldlen+newlen;
/* application-specific data */
applen = 0;
#ifdef XP_PC
if ( bUnbind ) {
strcpy( databuf+datalen+4, APPFLAG_W32BOUND );
applen = strlen( APPFLAG_W32BOUND ) + 1;
}
#endif /* XP_PC */
writelong( applen, databuf+datalen );
datalen += (applen + 4);
/* write out the header */
fwrite( databuf, 1, datalen, outf );
}
/*------------------------------------------
* calchash
*----------------------------------------*/
#define BUFSIZE 8192
void calchash( uint8 type, FILE *fh, uchar *outbuf, int *outlen )
{
uchar buffer[BUFSIZE];
switch (type)
{
case GDIFF_CS_CRC32:
{
uint32 crc;
uint32 nRead;
fseek( fh, 0, SEEK_SET );
crc = crc32( 0L, Z_NULL, 0 );
nRead = fread( buffer, 1, BUFSIZE, fh );
while ( nRead > 0 ) {
crc = crc32( crc, buffer, nRead );
nRead = fread( buffer, 1, BUFSIZE, fh );
}
fseek( fh, 0, SEEK_SET );
*(outbuf) = (uchar)( crc >> 24 );
*(outbuf+1) = (uchar)( ( crc >> 16 ) & 0x00FF );
*(outbuf+2) = (uchar)( ( crc >> 8 ) & 0x00FF );
*(outbuf+3) = (uchar)( crc & 0x00FF );
*outlen = 4;
break;
}
case GDIFF_CS_NONE:
default:
*outlen = 0;
break;
}
}
#ifdef XP_PC
#include <sys/types.h>
#include <sys/stat.h>
#include <windows.h>
#include <winnt.h>
XP_Bool unbind( FILE *oldf )
{
int i;
struct _stat st;
char filename[MAX_PATH];
XP_Bool unbound = FALSE;
if ( hasImports( oldf ) )
{
strcpy( filename, oldname );
for ( i = strlen(filename); i > 0; i-- ) {
filename[i-1] = '~';
if ( _stat( filename, &st ) != 0 )
break;
}
if ( CopyFile( oldname, filename, FALSE ) ) {
strcpy( oldname, filename ); /* save new name */
if ( unbindFile( oldname ) ) {
oldfile = fopen( oldname, "rb" );
unbound = TRUE;
}
}
}
fseek( oldfile, 0, SEEK_SET );
return unbound;
}
XP_Bool hasImports( FILE *fh )
{
int i;
DWORD nRead;
IMAGE_DOS_HEADER mz;
IMAGE_NT_HEADERS nt;
IMAGE_SECTION_HEADER sec;
/* read and validate the MZ header */
fseek( fh, 0, SEEK_SET );
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 ) {
/* found imports! */
return TRUE;
}
}
bail:
/* not a Win32 PE image or no import section */
return FALSE;
}
XP_Bool unbindFile( char* fname )
{
int i;
DWORD nRead;
PDWORD pOrigThunk;
PDWORD pBoundThunk;
FILE *fh;
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;
/* 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) {
if (!pfnBindImageEx(0, fname, NULL, NULL, NULL))
fprintf( stderr, " ERROR: Pre-binding failed\n" );
}
else {
fprintf( stderr, " ERROR: Couldn't find BindImageEx()\n" );
}
FreeLibrary(hImageHelp);
}
else {
fprintf( stderr, " ERROR: Could not load ImageHlp.dll\n" );
goto bail;
}
fh = fopen( fname, "r+b" );
if ( fh == NULL ) {
fprintf( stderr, " ERROR: Couldn't open %s\n", fname );
goto bail;
}
/* read and validate the MZ header */
nRead = fread( &mz, 1, sizeof(mz), fh );
if ( nRead != sizeof(mz) ) {
fprintf( stderr, " ERROR: Unexpected EOF reading DOS header\n" );
goto bail;
}
else if ( mz.e_magic != IMAGE_DOS_SIGNATURE ) {
fprintf( stderr, " ERROR: Invalid DOS header\n" );
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) ) {
fprintf( stderr, " ERROR: Unexpected EOF reading PE headers\n" );
goto bail;
}
if ( nt.Signature != IMAGE_NT_SIGNATURE ) {
fprintf( stderr, " ERROR: Not a Win32 Portable Executable (PE) file\n" );
goto bail;
}
else if ( nt.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC ) {
fprintf( stderr, " ERROR: Invalid PE Optional Header\n" );
goto bail;
}
/* find .idata section */
for (i = nt.FileHeader.NumberOfSections; i > 0; i--)
{
nRead = fread( &sec, 1, sizeof(sec), fh );
if ( nRead != sizeof(sec) ) {
fprintf( stderr, " ERROR: EOF reading section headers\n" );
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 ) {
fprintf( stderr, " ERROR: Memory allocation problem\n" );
goto bail;
}
fseek( fh, sec.PointerToRawData, SEEK_SET );
nRead = fread( buf, 1, sec.SizeOfRawData, fh );
if ( nRead != sec.SizeOfRawData ) {
fprintf( stderr, " ERROR: Unexpected EOF reading .idata\n" );
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;
}
fprintf( stdout, " %s bindings removed\n",
buf + (pImp->Name - sec.VirtualAddress) );
}
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 */
fprintf( stdout, " Deleting NT Bound Import Directory\n" );
buf = (char*)calloc( pDir->Size, 1 );
if ( buf == NULL ) {
fprintf( stderr, " ERROR: Memory allocation problem\n" );
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 );
}
fclose(fh);
return TRUE;
bail:
fclose(fh);
return FALSE;
}
#endif

View File

@ -30,10 +30,9 @@
#include <stdlib.h>
#include <string.h>
#include "gdiff.h"
/*--------------------------------------
* constants
* constants / macros
*------------------------------------*/
#define BUFSIZE 32768
@ -56,10 +55,14 @@ typedef unsigned long uint32;
typedef long int32;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned char uchar;
typedef unsigned char BOOL;
typedef unsigned char XP_Bool;
typedef unsigned char uint8;
typedef FILE* XP_File;
#include "gdiff.h"
/*--------------------------------------
* prototypes
@ -113,7 +116,7 @@ int main( int argc, char *argv[] )
/* Parse command line */
if ( !validateArgs( argc, argv ) ) {
err = ERR_ARGS;
err = GDIFF_ERR_ARGS;
}
else {
err = openFiles();
@ -122,7 +125,7 @@ int main( int argc, char *argv[] )
/* Process the patchfile */
if ( err == ERR_OK ) {
if ( err == GDIFF_OK ) {
err = doPatch();
}
@ -134,21 +137,21 @@ int main( int argc, char *argv[] )
/* Report status */
if ( err == ERR_OK ) {
if ( err == GDIFF_OK ) {
}
else {
switch (err) {
case ERR_ARGS:
case GDIFF_ERR_ARGS:
fprintf( stderr, "Invalid arguments\n" );
usage();
break;
case ERR_ACCESS:
case GDIFF_ERR_ACCESS:
fprintf( stderr, "Error opening file\n" );
break;
case ERR_MEM:
case GDIFF_ERR_MEM:
fprintf( stderr, "Insufficient memory\n" );
break;
@ -169,7 +172,7 @@ int main( int argc, char *argv[] )
int add( uint32 count )
{
int err = ERR_OK;
int err = GDIFF_OK;
uint32 nRead;
uint32 chunksize;
@ -177,7 +180,7 @@ int add( uint32 count )
chunksize = ( count > BUFSIZE) ? BUFSIZE : count;
nRead = fread( databuf, 1, chunksize, diffile );
if ( nRead != chunksize ) {
err = ERR_BADDIFF;
err = GDIFF_ERR_BADDIFF;
break;
}
@ -222,7 +225,7 @@ void cleanup()
int copy( uint32 position, uint32 count )
{
int err = ERR_OK;
int err = GDIFF_OK;
uint32 nRead;
uint32 chunksize;
@ -233,7 +236,7 @@ int copy( uint32 position, uint32 count )
nRead = fread( databuf, 1, chunksize, oldfile );
if ( nRead != chunksize ) {
err = ERR_OLDFILE;
err = GDIFF_ERR_OLDFILE;
break;
}
@ -260,20 +263,20 @@ int doPatch()
databuf = (uchar*)malloc(BUFSIZE);
if ( databuf == NULL ) {
err = ERR_MEM;
err = GDIFF_ERR_MEM;
goto fail;
}
err = parseHeader();
if (err != ERR_OK)
if (err != GDIFF_OK)
goto fail;
err = validateOldFile();
if ( err != ERR_OK )
if ( err != GDIFF_OK )
goto fail;
err = parseAppdata();
if ( err != ERR_OK )
if ( err != GDIFF_OK )
goto fail;
@ -282,7 +285,7 @@ int doPatch()
done = feof(diffile);
while ( !done ) {
err = getcmd( &opcode, OPSIZE );
if ( err != ERR_OK )
if ( err != GDIFF_OK )
break;
switch (opcode)
@ -293,63 +296,63 @@ int doPatch()
case ADD16:
err = getcmd( cmdbuf, ADD16SIZE );
if ( err == ERR_OK ) {
if ( err == GDIFF_OK ) {
err = add( getshort( cmdbuf ) );
}
break;
case ADD32:
err = getcmd( cmdbuf, ADD32SIZE );
if ( err == ERR_OK ) {
if ( err == GDIFF_OK ) {
err = add( getlong( cmdbuf ) );
}
break;
case COPY16BYTE:
err = getcmd( cmdbuf, COPY16BYTESIZE );
if ( err == ERR_OK ) {
if ( err == GDIFF_OK ) {
err = copy( getshort(cmdbuf), *(cmdbuf+sizeof(short)) );
}
break;
case COPY16SHORT:
err = getcmd( cmdbuf, COPY16SHORTSIZE );
if ( err == ERR_OK ) {
if ( err == GDIFF_OK ) {
err = copy(getshort(cmdbuf),getshort(cmdbuf+sizeof(short)));
}
break;
case COPY16LONG:
err = getcmd( cmdbuf, COPY16LONGSIZE );
if ( err == ERR_OK ) {
if ( err == GDIFF_OK ) {
err = copy(getshort(cmdbuf),getlong(cmdbuf+sizeof(short)));
}
break;
case COPY32BYTE:
err = getcmd( cmdbuf, COPY32BYTESIZE );
if ( err == ERR_OK ) {
if ( err == GDIFF_OK ) {
err = copy( getlong(cmdbuf), *(cmdbuf+sizeof(long)) );
}
break;
case COPY32SHORT:
err = getcmd( cmdbuf, COPY32SHORTSIZE );
if ( err == ERR_OK ) {
if ( err == GDIFF_OK ) {
err = copy( getlong(cmdbuf),getshort(cmdbuf+sizeof(long)) );
}
break;
case COPY32LONG:
err = getcmd( cmdbuf, COPY32LONGSIZE );
if ( err == ERR_OK ) {
if ( err == GDIFF_OK ) {
err = copy( getlong(cmdbuf), getlong(cmdbuf+sizeof(long)) );
}
break;
case COPY64:
/* we don't support 64-bit file positioning yet */
err = ERR_OPCODE;
err = GDIFF_ERR_OPCODE;
break;
default:
@ -357,11 +360,11 @@ int doPatch()
break;
}
if ( err != ERR_OK )
if ( err != GDIFF_OK )
done = TRUE;
}
if ( err == ERR_OK ) {
if ( err == GDIFF_OK ) {
err = validateNewFile();
}
@ -385,9 +388,9 @@ int getcmd( uchar *buffer, uint32 length )
bytesRead = fread( buffer, 1, length, diffile );
if ( bytesRead != length )
return ERR_BADDIFF;
return GDIFF_ERR_BADDIFF;
return ERR_OK;
return GDIFF_OK;
}
@ -401,13 +404,13 @@ char openFiles()
oldfile = fopen( oldname, "rb" );
if ( oldfile == NULL ) {
fprintf( stderr, "Can't open %s for reading\n", oldname );
return ERR_ACCESS;
return GDIFF_ERR_ACCESS;
}
diffile = fopen( difname, "rb" );
if ( diffile == NULL ) {
fprintf( stderr, "Can't open %s for reading\n", difname );
return ERR_ACCESS;
return GDIFF_ERR_ACCESS;
}
if ( outname == NULL || *outname == '\0' ) {
@ -418,10 +421,10 @@ char openFiles()
}
if ( outfile == NULL ) {
fprintf( stderr, "Can't open %s for writing\n", outname );
return ERR_ACCESS;
return GDIFF_ERR_ACCESS;
}
return ERR_OK;
return GDIFF_OK;
}
@ -432,7 +435,7 @@ char openFiles()
int parseHeader( void )
{
int err = ERR_OK;
int err = GDIFF_OK;
uint32 cslen;
uint32 oldcslen;
uint32 newcslen;
@ -441,20 +444,20 @@ int parseHeader( void )
nRead = fread( header, 1, GDIFF_HEADERSIZE, diffile );
if ( nRead != GDIFF_HEADERSIZE ) {
err = ERR_HEADER;
err = GDIFF_ERR_HEADER;
}
else if (memcmp( header, GDIFF_MAGIC, GDIFF_MAGIC_LEN ) != 0 ) {
err = ERR_HEADER;
err = GDIFF_ERR_HEADER;
}
else if ( header[GDIFF_VER_POS] != GDIFF_VER ) {
err = ERR_HEADER;
err = GDIFF_ERR_HEADER;
}
else {
checksumType = header[GDIFF_CS_POS];
cslen = header[GDIFF_CSLEN_POS];
if ( checksumType > 0 ) {
err = ERR_CHKSUMTYPE;
err = GDIFF_ERR_CHKSUMTYPE;
}
else if ( cslen > 0 ) {
oldcslen = cslen / 2;
@ -468,15 +471,15 @@ int parseHeader( void )
if ( nRead == oldcslen ) {
nRead = fread( finalChecksum, 1, newcslen, diffile );
if ( nRead != newcslen ) {
err = ERR_HEADER;
err = GDIFF_ERR_HEADER;
}
}
else {
err = ERR_HEADER;
err = GDIFF_ERR_HEADER;
}
}
else {
err = ERR_MEM;
err = GDIFF_ERR_MEM;
}
}
}
@ -493,14 +496,14 @@ int parseHeader( void )
int parseAppdata( void )
{
int err = ERR_OK;
int err = GDIFF_OK;
uint32 nRead;
uint32 appdataSize;
uchar lenbuf[GDIFF_APPDATALEN];
nRead = fread( lenbuf, 1, GDIFF_APPDATALEN, diffile );
if ( nRead != GDIFF_APPDATALEN ) {
err = ERR_HEADER;
err = GDIFF_ERR_HEADER;
}
else {
appdataSize = getlong(lenbuf);
@ -581,9 +584,9 @@ char validateArgs( int argc, char *argv[] )
int validateNewFile()
{
if ( checksumType > 0 )
return ERR_CHKSUMTYPE;
return GDIFF_ERR_CHKSUMTYPE;
else
return ERR_OK;
return GDIFF_OK;
}
@ -593,8 +596,8 @@ int validateNewFile()
int validateOldFile()
{
if ( checksumType > 0 )
return ERR_CHKSUMTYPE;
return GDIFF_ERR_CHKSUMTYPE;
else
return ERR_OK;
return GDIFF_OK;
}

View File

@ -0,0 +1,62 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#VERBOSE = 1
DEPTH=..\..\..\..
#cannot define PROGRAM in manifest compatibly with NT and UNIX
PROGRAM= .\$(OBJDIR)\nsunbind.exe
include <$(DEPTH)\config\config.mak>
# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/
# rules.mak will append C_OBJS onto OBJS.
# OBJS = $(CSRCS:.c=.obj)
PDBFILE = nsdiff.pdb
MAPFILE = nsdiff.map
REQUIRES=softupdt
CSRCS=nsunbind.c
C_OBJS=.\$(OBJDIR)\nsunbind.obj
!if "$(MOZ_BITS)" != "16"
LINCS=-I$(XPDIST)\public\softupdt
!endif
include <$(DEPTH)\config\rules.mak>
INSTALL = $(MAKE_INSTALL)
objs: $(OBJS)
programs: $(PROGRAM)
install:: $(TARGETS)
$(INSTALL) $(TARGETS) $(DIST)/bin
symbols:
@echo "CSRCS = $(CSRCS)"
@echo "INCS = $(INCS)"
@echo "OBJS = $(OBJS)"
@echo "LIBRARY = $(LIBRARY)"
@echo "PROGRAM = $(PROGRAM)"
@echo "TARGETS = $(TARGETS)"
@echo "DIST = $(DIST)"
@echo "VERSION_NUMBER = $(VERSION_NUMBER)"
@echo "WINFE = $(WINFE)"
@echo "DBM_LIB = $(DBM_LIB)"
@echo "INSTALL = $(INSTALL)"

View File

@ -0,0 +1,256 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*--------------------------------------------------------------------
* NSUnbind
*
* A utility to remove Bound Imports info from Win32 images
*
* nsunbind <exename>
*
*------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <windows.h>
#include <winnt.h>
/*--------------------------------------
* types
*------------------------------------*/
typedef unsigned long uint32;
typedef long int32;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned char uchar;
typedef unsigned char XP_Bool;
typedef unsigned char uint8;
typedef FILE* XP_File;
#include "gdiff.h"
/*--------------------------------------
* prototypes
*------------------------------------*/
void unbind( char * );
/*--------------------------------------
* main
*------------------------------------*/
int main( int argc, char *argv[] )
{
int i;
/* Parse command line */
if ( argc < 2 ) {
fprintf( stderr, "\n usage: nsunbind file ...\n\n" );
}
else {
for ( i = 1; i < argc; i++ )
{
fprintf( stderr, "NSUNBIND: %s\n", argv[i] );
unbind( argv[i] );
}
}
return 0;
}
void unbind( char* fname )
{
int i;
DWORD nRead;
PDWORD pOrigThunk;
PDWORD pBoundThunk;
FILE *fh;
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;
fh = fopen( fname, "r+b" );
if ( fh == NULL ) {
fprintf( stderr, " ERROR: Couldn't open %s\n", fname );
return;
}
/* read and validate the MZ header */
nRead = fread( &mz, 1, sizeof(mz), fh );
if ( nRead != sizeof(mz) ) {
fprintf( stderr, " ERROR: Unexpected EOF reading DOS header\n" );
goto bail;
}
else if ( mz.e_magic != IMAGE_DOS_SIGNATURE ) {
fprintf( stderr, " ERROR: Invalid DOS header\n" );
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) ) {
fprintf( stderr, " ERROR: Unexpected EOF reading PE headers\n" );
goto bail;
}
if ( nt.Signature != IMAGE_NT_SIGNATURE ) {
fprintf( stderr, " ERROR: Not a Win32 Portable Executable (PE) file\n" );
goto bail;
}
else if ( nt.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC ) {
fprintf( stderr, " ERROR: Invalid PE Optional Header\n" );
goto bail;
}
/* find .idata section */
for (i = nt.FileHeader.NumberOfSections; i > 0; i--)
{
nRead = fread( &sec, 1, sizeof(sec), fh );
if ( nRead != sizeof(sec) ) {
fprintf( stderr, " ERROR: EOF reading section headers\n" );
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 ) {
fprintf( stderr, " ERROR: Memory allocation problem\n" );
goto bail;
}
fseek( fh, sec.PointerToRawData, SEEK_SET );
nRead = fread( buf, 1, sec.SizeOfRawData, fh );
if ( nRead != sec.SizeOfRawData ) {
fprintf( stderr, " ERROR: Unexpected EOF reading .idata\n" );
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;
}
fprintf( stdout, " %s bindings removed\n",
buf + (pImp->Name - sec.VirtualAddress) );
}
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 */
fprintf( stdout, " Deleting NT Bound Import Directory\n" );
buf = (char*)calloc( pDir->Size, 1 );
if ( buf == NULL ) {
fprintf( stderr, " ERROR: Memory allocation problem\n" );
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 );
nRead = fwrite( &nt, 1, sizeof(nt), fh );
}
else
{
fprintf( stdout, " Nothing to unbind\n");
}
bail:
fclose(fh);
}