PATCH_RET_CODE OpenOld( foff len, int prompt, foff new_size, foff new_sum ) { int handle; foff actual_len; prompt=prompt; _splitpath( NewName, NULL, NULL, new_fname, new_ext ); _splitpath( path, drive, dir, fname, ext ); _makepath( new_path, drive, dir, new_fname, new_ext ); NewName = new_path; #if !defined( INSTALL_PROGRAM ) { char temp[_MAX_PATH]; char msgbuf[MAX_RESOURCE_SIZE]; if( prompt && DoPrompt ) { for( ;; ) { GetMsg( msgbuf, MSG_MODIFY ); cprintf( msgbuf, path ); while( kbhit() ) getch(); gets( temp ); if( tolower( temp[0] ) == 'n' ) { PatchError( ERR_PATCH_ABORTED ); } if( tolower( temp[0] ) == 'y' ) break; } } } #endif handle = open( path, O_RDONLY+O_BINARY, 0 ); FileCheck( handle, path ); MyOpen( &OldFile, handle, path ); actual_len = lseek( handle, 0, SEEK_END ); SeekCheck( actual_len, path ); if( actual_len != len && (actual_len + sizeof( PATCH_LEVEL )) != len && (actual_len - sizeof( PATCH_LEVEL )) != len ) { if( actual_len >= new_size ) { if( CheckSumOld( new_size ) == new_sum ) { MyClose( &OldFile ); return( PATCH_ALREADY_PATCHED ); } } PatchError( ERR_WRONG_SIZE, path, actual_len, len ); MyClose( &OldFile ); return( PATCH_BAD_LENGTH ); } SeekCheck( lseek( handle, 0, SEEK_SET ), path ); return( PATCH_RET_OKAY ); }
void MyClose( MY_FILE *file ) { if( file->dirty ) { SeekCheck( fseek( file->fd, file->start, SEEK_SET ), file->name ); if( fwrite( file->buff, 1, file->len, file->fd ) != file->len ) { PatchError( ERR_CANT_WRITE, file->name ); } } fclose( file->fd ); }
PATCH_RET_CODE InitPatch( char **target_given ) { char *p; int compare_sig; char target[FILENAME_MAX]; char ch; char *temp; PATCH_RET_CODE ret; #ifdef BDIFF char *tmp; #else char tmp[4]; #endif ret = OpenPatch(); if( ret != PATCH_RET_OKAY ) { return( ret ); } p = SIGNATURE; compare_sig = 1; for( ;; ) { ch = InPatch( char ); if( ch == EOF_CHAR ) break; if( compare_sig ) { if( ch != *p ) { PatchError( ERR_NOT_PATCHFILE, PatchName ); return( PATCH_RET_OKAY ); } ++p; if( ch == END_SIG_CHAR ) { compare_sig = 0; } } } p = target; for( ;; ) { *p = ch = InPatch( char ); ++p; if( ch == '\0' ) break; } if( (*target_given) != NULL ) { temp = SetOld( (*target_given) ); } else { temp = FindOld( target ); } if( temp ) { *target_given = temp; return( PATCH_RET_OKAY ); } else { *target_given = NULL; ClosePatch(); return( PATCH_CANT_OPEN_FILE ); } }
PATCH_RET_CODE InitHoles( void ) { NumHoles = 0; HoleArraySize = (64*1024L) / sizeof( save_hole ) - 1; for( ;; ) { HoleArray = _allocate( HoleArraySize*sizeof(save_hole) ); if( HoleArray != NULL ) break; HoleArraySize /= 2; if( HoleArraySize < 100 ) { PatchError( ERR_MEMORY_OUT ); return( PATCH_NO_MEMORY ); } } return( PATCH_RET_OKAY ); }
void InBuffer( MY_FILE *file, foff off, size_t len, size_t eob ) { if( off < file->start || off+len > file->start+eob ) { if( file->dirty ) { SeekCheck( fseek( file->fd, file->start, SEEK_SET), file->name ); if( fwrite( file->buff, 1, file->len, file->fd ) != file->len ) { PatchError( ERR_CANT_WRITE, file->name ); } } if( ( off & ~(SECTOR_SIZE - 1) ) + BUFFER_SIZE > off + len ) { off &= ~(SECTOR_SIZE - 1); } SeekCheck( fseek( file->fd, off, SEEK_SET ), file->name ); file->start = off; file->len = fread( file->buff, 1, BUFFER_SIZE, file->fd ); file->dirty = false; } }
PATCH_RET_CODE CloseNew( foff len, foff actual_sum, int *havenew ) { foff sum; foff off; int fd; char *p; *havenew = 1; off = 0; sum = 0; p = NewFile; while( off != len ) { sum += *p; ++p; ++off; } if( sum != actual_sum ) { *havenew = 0; if( CheckSumOld( len ) == actual_sum ) { return( PATCH_RET_OKAY ); } else { PatchError( ERR_WRONG_CHECKSUM, sum, actual_sum ); _free( NewFile ); NewFile = NULL; return( PATCH_BAD_CHECKSUM ); } } fd = open( NewName, O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, S_IRWXU ); FileCheck( fd, NewName ); if( write( fd, NewFile, len ) != len ) { *havenew = 0; FilePatchError( ERR_CANT_WRITE, NewName ); _free( NewFile ); NewFile = NULL; return( PATCH_CANT_WRITE ); } close( fd ); SameDate( NewName, PatchName ); _free( NewFile ); NewFile = NULL; return( PATCH_RET_OKAY ); }
extern PATCH_RET_CODE DoPatch( char *patchname, int doprompt, int dobackup, int printlevel, char *outfilename ) { char buffer[ sizeof( LEVEL ) ]; #ifndef _WPATCH char *target = NULL; #endif PATCH_RET_CODE ret; outfilename=outfilename; PatchName = patchname; DoPrompt = doprompt; DoBackup = dobackup; PrintLevel = printlevel; NewName = tmpnam( NULL ); #ifndef _WPATCH if( access( PatchName, R_OK ) != 0 ) { PatchError( ERR_CANT_FIND, PatchName ); return( PATCH_CANT_FIND_PATCH ); } #endif #if !defined( INSTALL_PROGRAM ) if( PrintLevel ) { GetLevel( PatchName ); if( CurrLevel[ 0 ] == '\0' ) { Message( MSG_NOT_PATCHED, PatchName ); } else { Message( MSG_PATCHED_TO_LEVEL, PatchName, CurrLevel ); } return( PATCH_RET_OKAY ); } #endif _splitpath( PatchName, NULL, NULL, NULL, buffer ); #ifndef _WPATCH ret = InitPatch( &target ); #else ret = InitPatch( &outfilename ); #endif #if defined( INSTALL_PROGRAM ) if( ret != PATCH_RET_OKAY ) { return( ret ); } if( outfilename != NULL ) { strcpy( outfilename, target ); PatchingFile( PatchName, outfilename ); } #endif #ifndef _WPATCH GetLevel( target ); if( stricmp( buffer, CurrLevel ) <= 0 ) { ClosePatch(); #if !defined( INSTALL_PROGRAM ) Message( MSG_ALREADY_PATCHED, target, CurrLevel ); #endif return( PATCH_ALREADY_PATCHED ); } else { #endif ret = Execute(); if( ret != PATCH_RET_OKAY ) { return( ret ); } #ifndef _WPATCH } #endif #if !defined( INSTALL_PROGRAM ) && !defined( _WPATCH ) Message( MSG_SUCCESSFULLY_PATCHED, target, buffer ); #endif return( PATCH_RET_OKAY ); }
PATCH_RET_CODE Execute( byte *dest ) { char *tmp; #else PATCH_RET_CODE Execute( void ) { char tmp[4]; #if defined(__386__) #if defined(_WPATCH) extern MY_FILE NewFile; #define InNew( offset ) ( Input( &NewFile, tmp, offset, \ sizeof(hole)), \ *(hole*)tmp ) #define OutNew( off, x, type ) *(type*)tmp = (x); \ Output( &NewFile, tmp, \ off, sizeof( type ) ); #else extern byte *NewFile; #define OutNew( off, x, type ) *(type*)(NewFile+off) = (x); #define InNew( off ) *(hole*)(NewFile+off) #endif #elif defined(BDUMP) #define InNew( offset ) 1 #define OutNew( off, x, type ) ( x ) #undef Dump #define Dump( x ) printf x #undef DOPROMPT #undef DOBACKUP #define DOPROMPT 0 #define DOBACKUP 0 #else extern MY_FILE NewFile; extern void Input( MY_FILE *file, void *tmp, foff off, size_t len ); #define InNew( offset ) ( Input( &NewFile, tmp, offset, \ sizeof(hole)), \ *(hole*)tmp ) extern void Output( MY_FILE *file, void *tmp, foff off, size_t len ); #define OutNew( off, x, type ) *(type*)tmp = (x); \ Output( &NewFile, tmp, \ off, sizeof( type ) ); #endif #endif patch_cmd cmd; byte next; hole diff; foff size; foff incr; foff iters; foff old_size; foff new_size; foff checksum; foff new_offset; foff old_offset; char ch; int havenew; PATCH_RET_CODE ret; PATCH_RET_CODE ret2; #ifdef BDIFF char *dummy = NULL; #endif havenew = 1; #ifdef BDIFF InitPatch( &dummy ); #endif old_size = InPatch( foff ); new_size = InPatch( foff ); checksum = InPatch( foff ); ret = OpenOld( old_size, DOPROMPT, new_size, checksum ); if( ret != PATCH_RET_OKAY ) goto error1; ret = OpenNew( new_size ); if( ret != PATCH_RET_OKAY ) goto error2; InitHoles(); for( ;; ) { #if defined( INSTALL_PROGRAM ) #if defined( WINNT ) || defined( WIN ) || defined( OS2 ) if( StatusCancelled() ) { ret = PATCH_RET_CANCEL; goto error3; } #endif #endif cmd = InPatch( patch_cmd ); if( cmd == CMD_DONE ) break; switch( cmd ) { case CMD_DIFFS: new_offset = InPatch( foff ); size = InPatch( foff ); Dump(( "Different new-%8.8lx size-%8.8lx\n", new_offset, size )); while( size != 0 ) { OutNew( new_offset, InPatch( byte ), byte ); ++new_offset; --size; } break; case CMD_SAMES: new_offset = InPatch( foff ); old_offset = InPatch( foff ); size = InPatch( foff ); Dump(( "Similar new-%8.8lx old-%8.8lx size-%8.8lx\n", new_offset, old_offset, size)); while( size != 0 ) { OutNew( new_offset, InOld( old_offset ), byte ); ++new_offset; ++old_offset; --size; } break; case CMD_ITER_HOLES: new_offset = InPatch( foff ); diff = InPatch( hole ); iters = InPatch( foff ); incr = InPatch( foff ); ch = InPatch( byte ); Dump(( "IterHole new-%8.8lx diff-%8.8lx iter-%8.8lx inc-%8.8lx\n", new_offset, diff, iters, incr )); while( iters != 0 ) { AddHole( new_offset, diff ); new_offset += incr; --iters; } break; case CMD_HOLES: new_offset = InPatch( foff ); diff = InPatch( hole ); for( ;; ) { Dump(( "Hole new-%8.8lx diff-%8.8lx\n",new_offset,diff)); AddHole( new_offset, diff ); next = InPatch( byte ); if( next == 0 ) break; if( ( next & 0x80 ) == 0 ) { new_offset += (foff)next & 0x7f; } else if( ( next & 0x40 ) == 0 ) { new_offset += ( (foff)next & 0x3f ) << 8; new_offset += (foff)InPatch( byte ); } else { new_offset += ( (foff)next & 0x3f ) << 16; new_offset += (foff)InPatch(byte) << 8; new_offset += (foff)InPatch(byte); } } break; default: PatchError( ERR_BAD_PATCHFILE, PatchName ); ret = PATCH_BAD_PATCH_FILE; goto error3; } } ret = PATCH_RET_OKAY; FlushHoles(); error3: FreeHoleArray(); ret2 = CloseNew( new_size, checksum, &havenew ); if( ret == PATCH_RET_OKAY ) { ret = ret2; } error2: CloseOld( havenew && DOPROMPT, DOBACKUP ); error1: ClosePatch(); return( ret ); }