📄 bdiff.c
字号:
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: Mainline for binary diff utility.
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "bdiff.h"
//#include "exeform.h"
#include "watcom.h"
#include "symtab.h"
#include "machtype.h"
#ifdef USE_DBGINFO
#include "dbginfo.h"
#endif
typedef enum {
ALG_NOTHING, /* find differences without extra info */
ALG_ONLY_NEW, /* only the new exe's debugging info is available */
ALG_BOTH, /* both exe's have debugging info available */
} algorithm;
#define BUFF_SIZE 16384
#define NL "\r\n"
#define NL_SIZE 2
typedef struct {
fpos_t last_offset;
} walker_data;
typedef struct exe_blk {
struct exe_blk *next;
fpos_t start;
uint_32 length;
uint_16 mod_offset;
} exe_blk;
typedef struct exe_mod {
struct exe_blk *blocks;
unsigned_16 mod_offset;
char name[1];
} exe_mod;
#if 0
typedef struct exe_info {
int fd;
symbol_table mods_by_offset;
symbol_table mods_by_name;
symbol_table blks;
exe_form_t form;
struct {
int fd;
fpos_t start; /* start of debugging info */
} sym;
} exe_info;
#endif
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
char buff[BUFF_SIZE];
byte *OldSymName;
byte *NewSymName;
//exe_info old;
//exe_info new;
byte *PatchFile;
foff PatchSize;
byte *OldFile;
byte *NewFile;
int AppendPatchLevel;
char *SyncString = NULL;
extern void Execute( byte * );
extern void GetMsg( char *, int );
extern void FileCheck( int fd, char *name );
extern void SeekCheck( long pos, char *name );
extern void MsgPrintf( int resourceid, va_list arglist );
#define MAX_DIFF (1L<<17)
#define MIN_DIFF (1L<<7)
#define MIN_EQUALITY (1L<<6)
#if MIN_EQUALITY > MIN_DIFF / 2
#error "No dice buddy. Try again!"
#endif
typedef struct region {
struct region *next;
foff old_start;
foff new_start;
foff size;
hole diff;
int dependants;
} region;
static region *SimilarRegions = NULL;
static region *DiffRegions = NULL;
static region *HoleRegions = NULL;
static region *HoleArray;
static foff SimilarSize = 0;
static foff NumHoles = 0;
static foff NumDiffs = 0;
static foff DiffSize = 0;
static foff HolesInRegion = 0;
static foff NumSimilarities = 0;
static foff HoleCount[3] = { 0, 0, 0 };
static foff HoleHeaders = 0;
static byte *OldCurr;
static byte *NewCurr;
static byte *TestOld;
static byte *TestNew;
static byte *SaveOld;
static byte *SaveNew;
static foff EndOld;
static int OldCorrection;
static foff EndNew;
static int NewCorrection;
static byte *CurrPatch;
static int Verbose;
static char *NewName;
static char *CommentFile;
static char LevelBuff[64];
static foff SyncOld = (foff)-1;
static foff SyncNew = (foff)-1;
/*
* Utility routines
* ================
*/
static void Err( int format, va_list args )
{
char msgbuf[80];
GetMsg( msgbuf, MSG_ERROR );
printf( msgbuf );
MsgPrintf( format, args);
}
void PatchError( int format, ... )
{
va_list args;
va_start( args, format );
Err( format, args );
printf( "\n" );
va_end( args );
MsgFini();
exit( EXIT_FAILURE );
}
void FilePatchError( int format, ... )
{
va_list args;
int err;
va_start( args, format );
err = errno;
Err( format, args );
printf( ": %s\n", strerror( err ) );
va_end( args );
MsgFini();
exit( EXIT_FAILURE );
}
void stats( char *format, ... )
{
va_list arg;
if( Verbose ) {
va_start( arg, format );
vprintf( format, arg );
fflush( stdout );
va_end( arg );
}
}
void NotNull( void *p, char *str )
{
if( p == NULL ) {
PatchError( ERR_NO_MEMORY, str );
}
}
void Usage( char *name )
{
char msgbuf[80];
int i;
GetMsg( msgbuf, MSG_USAGE_LN_1 );
printf( msgbuf, name );
for( i = MSG_USAGE_LN_2; i <= MSG_USAGE_LN_6; i++ ) {
GetMsg( msgbuf, i );
puts( msgbuf );
}
MsgFini();
exit( EXIT_FAILURE );
}
char *ReadIn( char *name, foff buff_size, foff read_size )
{
int fd;
char *buff;
buff = _allocate( buff_size );
NotNull( buff, "file buffer" );
fd = open( name, O_RDONLY+O_BINARY, 0 );
FileCheck( fd, name );
if( read( fd, buff, read_size ) != read_size ) {
FilePatchError( ERR_CANT_READ, name );
}
return( buff );
}
foff FileSize( char *name, int *correction )
{
foff size;
int fd;
char buff[ sizeof( LEVEL ) ];
if( access( name, R_OK ) != 0 ) {
PatchError( ERR_CANT_FIND, name );
} else {
fd = open( name, O_RDONLY+O_BINARY, 0 );
FileCheck( fd, name );
size = lseek( fd, 0, SEEK_END );
SeekCheck( size, name );
*correction = 0;
if( size > sizeof( LEVEL ) ) {
SeekCheck( lseek( fd, -(long)sizeof( LEVEL ), SEEK_END ), name );
if( read( fd, buff, sizeof( LEVEL ) ) != sizeof( LEVEL ) ) {
FilePatchError( ERR_CANT_READ, name );
}
if( memcmp( buff, LEVEL, LEVEL_HEAD_SIZE ) == 0 ) {
size -= sizeof( LEVEL ); /* lie about size */
*correction = sizeof( LEVEL );
}
}
close( fd );
}
return( size );
}
/*
* Routines to create "regions" and add them to their lists
*/
void AddRegion( region **owner, foff old_start, foff new_start, foff size )
{
region *reg;
reg = _allocate( sizeof( region ) );
NotNull( reg, "region" );
reg->next = *owner;
reg->old_start = old_start;
reg->new_start = new_start;
reg->size = size;
*owner = reg;
}
void AddSimilar( foff old_start, foff new_start, foff size )
{
SimilarSize += size;
if( SimilarRegions ) {
foff last_old;
foff last_new;
last_old = SimilarRegions->old_start + SimilarRegions->size;
last_new = SimilarRegions->new_start + SimilarRegions->size;
if( last_old == old_start && last_new == new_start ) {
SimilarRegions->size += size;
return;
}
}
HolesInRegion = 0;
NumSimilarities++;
AddRegion( &SimilarRegions, old_start, new_start, size );
}
void AddSimilarDiff( foff old_start, foff new_start, foff size )
{
if( SimilarRegions != NULL ) {
if( old_start+size < EndOld || new_start+size < EndNew ) {
if( SimilarRegions->new_start >= ( new_start + size ) ) {
AddDiff( new_start + size,
SimilarRegions->new_start - ( new_start + size ) );
}
}
}
AddSimilar( old_start, new_start, size );
}
void AddDiff( foff new_start, foff size )
{
if( size == 0 ) return;
DiffSize += size;
if( DiffRegions ) {
foff last_new;
last_new = DiffRegions->new_start + DiffRegions->size;
if( last_new == new_start ) {
DiffRegions->size += size;
return;
}
}
NumDiffs++;
AddRegion( &DiffRegions, -1, new_start, size );
}
void AddHole( foff old_start, foff new_start )
{
NumHoles++;
HolesInRegion++;
AddRegion( &HoleRegions, old_start, new_start, sizeof( hole ) );
HoleRegions->diff = *(hole*)( NewFile + HoleRegions->new_start )
- *(hole*)( OldFile + HoleRegions->old_start );
}
/*
* =====================================================================
* Routines to compare the files ignoring "holes". A hole is a 1-4 byte
* difference in the two files. These are handled specially in the patch
* file, since these are the changed relocation items caused by a shift
* in the code within the executable.
* =====================================================================
*/
int TheSameIgnoringHoles( void )
{
int i;
byte *end_old;
byte *end_new;
/* sync two file pointers up to an identical byte */
for( i = 0; ; ++i ) {
if( i == sizeof(hole)+1 ) {
return( 0 );
}
if( *TestOld == *TestNew ) {
break;
}
++TestOld;
++TestNew;
}
/* find out if TestOld and TestNew are similar for length MIN_EQUALITY */
end_old = TestOld + MIN_EQUALITY;
end_new = TestNew + MIN_EQUALITY;
for(;;) {
if( TestOld >= end_old ) return( 1 );
if( TestNew >= end_new ) return( 1 );
if( *TestOld != *TestNew ) {
if( TestOld[sizeof(hole)] != TestNew[sizeof(hole)] ) {
if( TestOld[2*sizeof(hole)] != TestNew[2*sizeof(hole)] ) {
if( TestOld[3*sizeof(hole)] != TestNew[3*sizeof(hole)] ) {
return( 0 );
}
TestOld += sizeof(hole);
TestNew += sizeof(hole);
}
TestOld += sizeof(hole);
TestNew += sizeof(hole);
}
TestOld += sizeof(hole)-1;
TestNew += sizeof(hole)-1;
}
++TestOld;
++TestNew;
}
}
int AreasAreSimilar( foff_diff adjust, foff_diff backup_amt )
{
byte *lastold;
byte *lastnew;
/*
* Find out if there is a similar area (the same ignoring holes)
* if we move OldCurr and NewCurr back by "backup_amt", adjusting
* NewCurr by adjust (the shift between the two areas)
*/
#define AddAndCheck( size ) if( TestOld + size >= OldCurr ) break; \
if( TestNew + size >= NewCurr ) break; \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -