├── .gitignore ├── LICENSE ├── Makefile-bsdiff.am ├── Makefile.am ├── README.md ├── autogen.sh ├── bsdiff.c ├── bsdiff.h ├── bspatch.c ├── bspatch.h └── configure.ac /.gitignore: -------------------------------------------------------------------------------- 1 | .deps/* 2 | .libs/* 3 | *.lo 4 | *.o 5 | .dirstamp 6 | Makefile-bsdiff.am.inc 7 | AUTHORS 8 | NEWS 9 | README 10 | ChangeLog 11 | COPYING 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2003-2005 Colin Percival 2 | Copyright 2012 Matthew Endsley 3 | All rights reserved 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted providing that the following conditions 7 | are met: 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /Makefile-bsdiff.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Giuseppe Scrivano 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted providing that the following conditions 5 | # are met: 6 | # 1. Redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer. 8 | # 2. Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # 12 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 13 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 16 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 20 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 21 | # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 22 | # POSSIBILITY OF SUCH DAMAGE. 23 | # 24 | 25 | EXTRA_DIST += $(libbsdiff_srcpath)/bsdiff.h $(libbsdiff_srcpath)/bspatch.h $(libbsdiff_srcpath)/LICENSE $(libbsdiff_srcpath)/README.md 26 | 27 | libbsdiff_la_SOURCES = \ 28 | $(libbsdiff_srcpath)/bsdiff.c \ 29 | $(libbsdiff_srcpath)/bspatch.c \ 30 | $(NULL) 31 | 32 | libbsdiff_la_CFLAGS = $(AM_CFLAGS) 33 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = bsdiff bspatch 2 | 3 | bsdiff_SOURCES = bsdiff.c 4 | 5 | bspatch_SOURCES = bspatch.c 6 | 7 | bsdiff_CFLAGS = -DBSDIFF_EXECUTABLE 8 | bspatch_CFLAGS = -DBSPATCH_EXECUTABLE 9 | 10 | EXTRA_DIST = bsdiff.h bspatch.h 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | bsdiff/bspatch 2 | ============== 3 | bsdiff and bspatch are libraries for building and applying patches to binary 4 | files. 5 | 6 | The original algorithm and implementation was developed by Colin Percival. The 7 | algorithm is detailed in his (unpublished) paper, [Naïve Differences of Executable Code](http://www.daemonology.net/papers/bsdiff.pdf). For more information, visit his 8 | website at . 9 | 10 | I maintain this project seperately from Colin's work, with the goal of making 11 | the core functionality easily embedable in existing projects. 12 | 13 | Contact 14 | ------- 15 | [@MatthewEndsley](https://twitter.com/#!/MatthewEndsley) 16 | 17 | 18 | License 19 | ------- 20 | Copyright 2003-2005 Colin Percival 21 | Copyright 2012 Matthew Endsley 22 | 23 | This project is governed by the BSD 2-clause license. For details see the file 24 | titled LICENSE in the project root folder. 25 | 26 | Overview 27 | -------- 28 | There are two separate libraries in the project, bsdiff and bspatch. Each are 29 | self contained in bsdiff.c and bspatch.c The easiest way to integrate is to 30 | simply copy the c file to your source folder and build it. 31 | 32 | The overarching goal was to modify the original bsdiff/bspatch code from Colin 33 | and eliminate external dependencies and provide a simple interface to the core 34 | functionality. 35 | 36 | I've exposed relevant functions via the `_stream` classes. The only external 37 | dependency not exposed is `memcmp` in `bsdiff`. 38 | 39 | This library generates patches that are not compatible with the original bsdiff 40 | tool. The impompatibilities were motivated by the patching needs for the game 41 | AirMech and the following requirements: 42 | 43 | * Eliminate/minimize any seek operations when applying patches 44 | * Eliminate any required disk I/O and support embedded streams 45 | * Ability to easily embed the routines as a library instead of an external binary 46 | * Compile+run on all platforms we use to build the game (Windows, Linux, NaCl, OSX) 47 | 48 | Compiling 49 | --------- 50 | The libraries should compile warning free in any moderately recent version of 51 | gcc. The project uses `` which is technically a C99 file and not 52 | available in Microsoft Visual Studio. The easiest solution here is to use the 53 | msinttypes version of stdint.h from . 54 | The direct link for the lazy people is: 55 | . 56 | 57 | If your compiler does not provide an implementation of `` you can 58 | remove the header from the bsdiff/bspatch files and provide your own typedefs 59 | for the following symbols: `uint8_t`, `uint64_t` and `int64_t`. 60 | 61 | Examples 62 | -------- 63 | Each project has an optional main function that serves as an example for using 64 | the library. Simply defined `BSDIFF_EXECUTABLE` or `BSPATCH_EXECUTABLE` to 65 | enable building the standalone tools. 66 | 67 | Reference 68 | --------- 69 | ### bsdiff 70 | 71 | struct bsdiff_stream 72 | { 73 | void* opaque; 74 | void* (*malloc)(size_t size); 75 | void (*free)(void* ptr); 76 | int (*write)(struct bsdiff_stream* stream, 77 | const void* buffer, int size); 78 | }; 79 | 80 | int bsdiff(const uint8_t* old, int64_t oldsize, const uint8_t* new, 81 | int64_t newsize, struct bsdiff_stream* stream); 82 | 83 | 84 | In order to use `bsdiff`, you need to define functions for allocating memory and 85 | writing binary data. This behavior is controlled by the `stream` parameted 86 | passed to to `bsdiff(...)`. 87 | 88 | The `opaque` field is never read or modified from within the `bsdiff` function. 89 | The caller can use this field to store custom state data needed for the callback 90 | functions. 91 | 92 | The `malloc` and `free` members should point to functions that behave like the 93 | standard `malloc` and `free` C functions. 94 | 95 | The `write` function is called by bsdiff to write a block of binary data to the 96 | stream. The return value for `write` should be `0` on success and non-zero if 97 | the callback failed to write all data. In the default example, bzip2 is used to 98 | compress output data. 99 | 100 | `bsdiff` returns `0` on success and `-1` on failure. 101 | 102 | ### bspatch 103 | 104 | struct bspatch_stream 105 | { 106 | void* opaque; 107 | int (*read)(const struct bspatch_stream* stream, 108 | void* buffer, int length); 109 | }; 110 | 111 | int bspatch(const uint8_t* old, int64_t oldsize, uint8_t* new, 112 | int64_t newsize, struct bspatch_stream* stream); 113 | 114 | The `bspatch` function transforms the data for a file using data generated from 115 | `bsdiff`. The caller takes care of loading the old file and allocating space for 116 | new file data. The `stream` parameter controls the process for reading binary 117 | patch data. 118 | 119 | The `opaque` field is never read or modified from within the bspatch function. 120 | The caller can use this field to store custom state data needed for the read 121 | function. 122 | 123 | The `read` function is called by `bspatch` to read a block of binary data from 124 | the stream. The return value for `read` should be `0` on success and non-zero 125 | if the callback failed to read the requested amount of data. In the default 126 | example, bzip2 is used to decompress input data. 127 | 128 | `bspatch` returns `0` on success and `-1` on failure. On success, `new` contains 129 | the data for the patched file. 130 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | touch AUTHORS NEWS README ChangeLog 4 | cp LICENSE COPYING 5 | 6 | autoreconf -fis 7 | -------------------------------------------------------------------------------- /bsdiff.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2003-2005 Colin Percival 3 | * Copyright 2012 Matthew Endsley 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "bsdiff.h" 29 | 30 | #include 31 | #include 32 | 33 | #define MIN(x,y) (((x)<(y)) ? (x) : (y)) 34 | 35 | static void split(int64_t *I,int64_t *V,int64_t start,int64_t len,int64_t h) 36 | { 37 | int64_t i,j,k,x,tmp,jj,kk; 38 | 39 | if(len<16) { 40 | for(k=start;kstart) split(I,V,start,jj-start,h); 89 | 90 | for(i=0;ikk) split(I,V,kk,start+len-kk,h); 94 | } 95 | 96 | static void qsufsort(int64_t *I,int64_t *V,const uint8_t *old,int64_t oldsize) 97 | { 98 | int64_t buckets[256]; 99 | int64_t i,h,len; 100 | 101 | for(i=0;i<256;i++) buckets[i]=0; 102 | for(i=0;i0;i--) buckets[i]=buckets[i-1]; 105 | buckets[0]=0; 106 | 107 | for(i=0;iy) { 154 | *pos=I[st]; 155 | return x; 156 | } else { 157 | *pos=I[en]; 158 | return y; 159 | } 160 | }; 161 | 162 | x=st+(en-st)/2; 163 | if(memcmp(old+I[x],new,MIN(oldsize-I[x],newsize))<0) { 164 | return search(I,old,oldsize,new,newsize,x,en,pos); 165 | } else { 166 | return search(I,old,oldsize,new,newsize,st,x,pos); 167 | }; 168 | } 169 | 170 | static void offtout(int64_t x,uint8_t *buf) 171 | { 172 | memcpy(buf, &x, 8); 173 | } 174 | 175 | static int64_t writedata(struct bsdiff_stream* stream, const void* buffer, int64_t length) 176 | { 177 | int64_t result = 0; 178 | 179 | while (length > 0) 180 | { 181 | const int smallsize = (int)MIN(length, INT_MAX); 182 | const int writeresult = stream->write(stream, buffer, smallsize); 183 | if (writeresult == -1) 184 | { 185 | return -1; 186 | } 187 | 188 | result += writeresult; 189 | length -= smallsize; 190 | buffer = (uint8_t*)buffer + smallsize; 191 | } 192 | 193 | return result; 194 | } 195 | 196 | struct bsdiff_request 197 | { 198 | const uint8_t* old; 199 | int64_t oldsize; 200 | const uint8_t* new; 201 | int64_t newsize; 202 | struct bsdiff_stream* stream; 203 | int64_t *I; 204 | uint8_t *buffer; 205 | }; 206 | 207 | static int bsdiff_internal(const struct bsdiff_request req) 208 | { 209 | int64_t *I,*V; 210 | int64_t scan,pos,len; 211 | int64_t lastscan,lastpos,lastoffset; 212 | int64_t oldscore,scsc; 213 | int64_t s,Sf,lenf,Sb,lenb; 214 | int64_t overlap,Ss,lens; 215 | int64_t i; 216 | uint8_t *buffer; 217 | uint8_t buf[8 * 3]; 218 | 219 | if((V=req.stream->malloc((req.oldsize+1)*sizeof(int64_t)))==NULL) return -1; 220 | I = req.I; 221 | 222 | qsufsort(I,V,req.old,req.oldsize); 223 | req.stream->free(V); 224 | 225 | buffer = req.buffer; 226 | 227 | /* Compute the differences, writing ctrl as we go */ 228 | scan=0;len=0;pos=0; 229 | lastscan=0;lastpos=0;lastoffset=0; 230 | while(scanoldscore+8)) break; 244 | 245 | if((scan+lastoffsetSf*2-lenf) { Sf=s; lenf=i; }; 256 | }; 257 | 258 | lenb=0; 259 | if(scan=lastscan+i)&&(pos>=i);i++) { 262 | if(req.old[pos-i]==req.new[scan-i]) s++; 263 | if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; }; 264 | }; 265 | }; 266 | 267 | if(lastscan+lenf>scan-lenb) { 268 | overlap=(lastscan+lenf)-(scan-lenb); 269 | s=0;Ss=0;lens=0; 270 | for(i=0;iSs) { Ss=s; lens=i+1; }; 276 | }; 277 | 278 | lenf+=lens-overlap; 279 | lenb-=lens; 280 | }; 281 | 282 | offtout(lenf,buf); 283 | offtout((scan-lenb)-(lastscan+lenf),buf+8); 284 | offtout((pos-lenb)-(lastpos+lenf),buf+16); 285 | 286 | /* Write control data */ 287 | if (writedata(req.stream, buf, sizeof(buf))) 288 | return -1; 289 | 290 | /* Write diff data */ 291 | for(i=0;imalloc((oldsize+1)*sizeof(int64_t)))==NULL) 317 | return -1; 318 | 319 | if((req.buffer=stream->malloc(newsize+1))==NULL) 320 | { 321 | stream->free(req.I); 322 | return -1; 323 | } 324 | 325 | req.old = old; 326 | req.oldsize = oldsize; 327 | req.new = new; 328 | req.newsize = newsize; 329 | req.stream = stream; 330 | 331 | result = bsdiff_internal(req); 332 | 333 | stream->free(req.buffer); 334 | stream->free(req.I); 335 | 336 | return result; 337 | } 338 | 339 | #if defined(BSDIFF_EXECUTABLE) 340 | 341 | #include 342 | 343 | #include 344 | #include 345 | #include 346 | #include 347 | #include 348 | 349 | static int uncompressed_write(struct bsdiff_stream* stream, const void* buffer, int size) 350 | { 351 | FILE* fp = (FILE*)stream->opaque; 352 | size_t bytesWritten = fwrite((void*)buffer, 1, size, fp); 353 | if (bytesWritten != size) 354 | return -1; 355 | 356 | return 0; 357 | } 358 | 359 | int main(int argc,char *argv[]) 360 | { 361 | int fd; 362 | int bz2err; 363 | uint8_t *old,*new; 364 | off_t oldsize,newsize; 365 | uint8_t buf[8]; 366 | FILE * pf; 367 | struct bsdiff_stream stream; 368 | 369 | stream.malloc = malloc; 370 | stream.free = free; 371 | stream.write = uncompressed_write; 372 | 373 | if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); 374 | 375 | /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure 376 | that we never try to malloc(0) and get a NULL pointer */ 377 | if(((fd=open(argv[1],O_RDONLY,0))<0) || 378 | ((oldsize=lseek(fd,0,SEEK_END))==-1) || 379 | ((old=malloc(oldsize+1))==NULL) || 380 | (lseek(fd,0,SEEK_SET)!=0) || 381 | (read(fd,old,oldsize)!=oldsize) || 382 | (close(fd)==-1)) err(1,"%s",argv[1]); 383 | 384 | 385 | /* Allocate newsize+1 bytes instead of newsize bytes to ensure 386 | that we never try to malloc(0) and get a NULL pointer */ 387 | if(((fd=open(argv[2],O_RDONLY,0))<0) || 388 | ((newsize=lseek(fd,0,SEEK_END))==-1) || 389 | ((new=malloc(newsize+1))==NULL) || 390 | (lseek(fd,0,SEEK_SET)!=0) || 391 | (read(fd,new,newsize)!=newsize) || 392 | (close(fd)==-1)) err(2,"%s",argv[2]); 393 | 394 | /* Create the patch file */ 395 | if ((pf = fopen(argv[3], "w")) == NULL) 396 | err(3, "%s", argv[3]); 397 | 398 | stream.opaque = pf; 399 | if (bsdiff(old, oldsize, new, newsize, &stream)) 400 | err(4, "bsdiff"); 401 | 402 | if (fclose(pf)) 403 | err(5, "fclose"); 404 | 405 | /* Free the memory we used */ 406 | free(old); 407 | free(new); 408 | 409 | return 0; 410 | } 411 | 412 | #endif 413 | -------------------------------------------------------------------------------- /bsdiff.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2003-2005 Colin Percival 3 | * Copyright 2012 Matthew Endsley 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef BSDIFF_H 29 | # define BSDIFF_H 30 | 31 | # include 32 | # include 33 | 34 | struct bsdiff_stream 35 | { 36 | void* opaque; 37 | 38 | void* (*malloc)(size_t size); 39 | void (*free)(void* ptr); 40 | int (*write)(struct bsdiff_stream* stream, const void* buffer, int size); 41 | }; 42 | 43 | int bsdiff(const uint8_t* old, int64_t oldsize, const uint8_t* new, int64_t newsize, struct bsdiff_stream* stream); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /bspatch.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2003-2005 Colin Percival 3 | * Copyright 2012 Matthew Endsley 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "bspatch.h" 29 | 30 | static int64_t offtin(uint8_t *buf) 31 | { 32 | int64_t y; 33 | 34 | y=buf[7]&0x7F; 35 | y=y*256;y+=buf[6]; 36 | y=y*256;y+=buf[5]; 37 | y=y*256;y+=buf[4]; 38 | y=y*256;y+=buf[3]; 39 | y=y*256;y+=buf[2]; 40 | y=y*256;y+=buf[1]; 41 | y=y*256;y+=buf[0]; 42 | 43 | if(buf[7]&0x80) y=-y; 44 | 45 | return y; 46 | } 47 | 48 | int bspatch(const uint8_t* old, int64_t oldsize, uint8_t* new, int64_t newsize, struct bspatch_stream* stream) 49 | { 50 | uint8_t buf[8]; 51 | int64_t oldpos,newpos; 52 | int64_t ctrl[3]; 53 | int64_t i; 54 | 55 | oldpos=0;newpos=0; 56 | while(newposread(stream, buf, 8)) 60 | return -1; 61 | ctrl[i]=offtin(buf); 62 | }; 63 | 64 | /* Sanity-check */ 65 | if(newpos+ctrl[0]>newsize) 66 | return -1; 67 | 68 | /* Read diff string */ 69 | if (stream->read(stream, new + newpos, ctrl[0])) 70 | return -1; 71 | 72 | /* Add old data to diff string */ 73 | for(i=0;i=0) && (oldpos+inewsize) 83 | return -1; 84 | 85 | /* Read extra string */ 86 | if (stream->read(stream, new + newpos, ctrl[1])) 87 | return -1; 88 | 89 | /* Adjust pointers */ 90 | newpos+=ctrl[1]; 91 | oldpos+=ctrl[2]; 92 | }; 93 | 94 | return 0; 95 | } 96 | 97 | #if defined(BSPATCH_EXECUTABLE) 98 | 99 | #include 100 | #include 101 | #include 102 | #include 103 | #include 104 | #include 105 | #include 106 | #include 107 | #include 108 | #include 109 | 110 | static int bz2_read(const struct bspatch_stream* stream, void* buffer, int length) 111 | { 112 | int n; 113 | int bz2err; 114 | BZFILE* bz2; 115 | 116 | bz2 = (BZFILE*)stream->opaque; 117 | n = BZ2_bzRead(&bz2err, bz2, buffer, length); 118 | if (n != length) 119 | return -1; 120 | 121 | return 0; 122 | } 123 | 124 | int main(int argc,char * argv[]) 125 | { 126 | FILE * f; 127 | int fd; 128 | int bz2err; 129 | uint8_t header[24]; 130 | uint8_t *old, *new; 131 | int64_t oldsize, newsize; 132 | BZFILE* bz2; 133 | struct bspatch_stream stream; 134 | struct stat sb; 135 | 136 | if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); 137 | 138 | /* Open patch file */ 139 | if ((f = fopen(argv[3], "r")) == NULL) 140 | err(1, "fopen(%s)", argv[3]); 141 | 142 | /* Read header */ 143 | if (fread(header, 1, 24, f) != 24) { 144 | if (feof(f)) 145 | errx(1, "Corrupt patch\n"); 146 | err(1, "fread(%s)", argv[3]); 147 | } 148 | 149 | /* Check for appropriate magic */ 150 | if (memcmp(header, "ENDSLEY/BSDIFF43", 16) != 0) 151 | errx(1, "Corrupt patch\n"); 152 | 153 | /* Read lengths from header */ 154 | newsize=offtin(header+16); 155 | if(newsize<0) 156 | errx(1,"Corrupt patch\n"); 157 | 158 | /* Close patch file and re-open it via libbzip2 at the right places */ 159 | if(((fd=open(argv[1],O_RDONLY,0))<0) || 160 | ((oldsize=lseek(fd,0,SEEK_END))==-1) || 161 | ((old=malloc(oldsize+1))==NULL) || 162 | (lseek(fd,0,SEEK_SET)!=0) || 163 | (read(fd,old,oldsize)!=oldsize) || 164 | (fstat(fd, &sb)) || 165 | (close(fd)==-1)) err(1,"%s",argv[1]); 166 | if((new=malloc(newsize+1))==NULL) err(1,NULL); 167 | 168 | if (NULL == (bz2 = BZ2_bzReadOpen(&bz2err, f, 0, 0, NULL, 0))) 169 | errx(1, "BZ2_bzReadOpen, bz2err=%d", bz2err); 170 | 171 | stream.read = bz2_read; 172 | stream.opaque = bz2; 173 | if (bspatch(old, oldsize, new, newsize, &stream)) 174 | errx(1, "bspatch"); 175 | 176 | /* Clean up the bzip2 reads */ 177 | BZ2_bzReadClose(&bz2err, bz2); 178 | fclose(f); 179 | 180 | /* Write the new file */ 181 | if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,sb.st_mode))<0) || 182 | (write(fd,new,newsize)!=newsize) || (close(fd)==-1)) 183 | err(1,"%s",argv[2]); 184 | 185 | free(new); 186 | free(old); 187 | 188 | return 0; 189 | } 190 | 191 | #endif 192 | -------------------------------------------------------------------------------- /bspatch.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2003-2005 Colin Percival 3 | * Copyright 2012 Matthew Endsley 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef BSPATCH_H 29 | # define BSPATCH_H 30 | 31 | # include 32 | 33 | struct bspatch_stream 34 | { 35 | void* opaque; 36 | int (*read)(const struct bspatch_stream* stream, void* buffer, int length); 37 | }; 38 | 39 | int bspatch(const uint8_t* old, int64_t oldsize, uint8_t* new, int64_t newsize, struct bspatch_stream* stream); 40 | 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.69]) 5 | AC_INIT([bsdiff], [0.1]) 6 | AC_CONFIG_SRCDIR([bsdiff.c]) 7 | AC_CONFIG_HEADERS([config.h]) 8 | AM_INIT_AUTOMAKE([1.9]) 9 | 10 | # Checks for programs. 11 | AC_PROG_CC 12 | 13 | # Checks for libraries. 14 | # FIXME: Replace `main' with a function in `-lbz2': 15 | AC_CHECK_LIB([bz2], [BZ2_bzReadOpen]) 16 | 17 | AC_CHECK_HEADERS([fcntl.h limits.h stddef.h stdint.h stdlib.h string.h unistd.h]) 18 | 19 | # Checks for typedefs, structures, and compiler characteristics. 20 | AC_TYPE_INT64_T 21 | AC_TYPE_OFF_T 22 | AC_TYPE_SIZE_T 23 | AC_TYPE_UINT8_T 24 | 25 | # Checks for library functions. 26 | AC_FUNC_MALLOC 27 | AC_CHECK_FUNCS([memset]) 28 | 29 | AC_CONFIG_FILES([Makefile]) 30 | AC_OUTPUT 31 | --------------------------------------------------------------------------------