diff --git a/.idea/bsdiff.iml b/.idea/bsdiff.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/bsdiff.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..5d56335 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..0d2a477 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,528 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + len + scan + pos + err + printf + Sf + Sb + lastoffset + lastpost + lastpos + Buffer output + search + + + + + + + + + + + true + DEFINITION_ORDER + + + + + + + + + + + + JSON + + + JavaScript + + + JavaScript function metricsJavaScript + + + Naming conventionsJavaScript + + + Potentially confusing code constructsJavaScript + + + Probable bugsJavaScript + + + Python + + + XPath + + + + + C/C++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + project + + + true + + + + DIRECTORY + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1488932062518 + + + 1489040063411 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f69cb1a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.6) +project(bsdiff) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_C_STANDARD 11) + +set(SOURCE_FILES + bsdiff.c + bsdiff.h + bspatch.c + bspatch.h + config.h) + +add_executable(bsdiff ${SOURCE_FILES}) \ No newline at end of file diff --git a/bsdiff.c b/bsdiff.c index 628f1c1..43eb3ab 100644 --- a/bsdiff.c +++ b/bsdiff.c @@ -29,324 +29,477 @@ #include #include +#include -#define MIN(x,y) (((x)<(y)) ? (x) : (y)) - -static void split(int64_t *I,int64_t *V,int64_t start,int64_t len,int64_t h) -{ - int64_t i,j,k,x,tmp,jj,kk; - - if(len<16) { - for(k=start;kstart) split(I,V,start,jj-start,h); - - for(i=0;ikk) split(I,V,kk,start+len-kk,h); +#define MIN(x, y) (((x)<(y)) ? (x) : (y)) + +static void split(int64_t *I, int64_t *V, int64_t start, int64_t len, int64_t h) { + int64_t i, j, k, x, tmp, jj, kk; + + if (len < 16) { + for (k = start; k < start + len; k += j) { + j = 1; + x = V[I[k] + h]; + for (i = 1; k + i < start + len; i++) { + if (V[I[k + i] + h] < x) { + x = V[I[k + i] + h]; + j = 0; + }; + if (V[I[k + i] + h] == x) { + tmp = I[k + j]; + I[k + j] = I[k + i]; + I[k + i] = tmp; + j++; + }; + }; + for (i = 0; i < j; i++) V[I[k + i]] = k + j - 1; + if (j == 1) I[k] = -1; + }; + return; + }; + + x = V[I[start + len / 2] + h]; + jj = 0; + kk = 0; + for (i = start; i < start + len; i++) { + if (V[I[i] + h] < x) jj++; + if (V[I[i] + h] == x) kk++; + }; + jj += start; + kk += jj; + + i = start; + j = 0; + k = 0; + while (i < jj) { + if (V[I[i] + h] < x) { + i++; + } else if (V[I[i] + h] == x) { + tmp = I[i]; + I[i] = I[jj + j]; + I[jj + j] = tmp; + j++; + } else { + tmp = I[i]; + I[i] = I[kk + k]; + I[kk + k] = tmp; + k++; + }; + }; + + while (jj + j < kk) { + if (V[I[jj + j] + h] == x) { + j++; + } else { + tmp = I[jj + j]; + I[jj + j] = I[kk + k]; + I[kk + k] = tmp; + k++; + }; + }; + + if (jj > start) split(I, V, start, jj - start, h); + + for (i = 0; i < kk - jj; i++) V[I[jj + i]] = kk - 1; + if (jj == kk - 1) I[jj] = -1; + + if (start + len > kk) split(I, V, kk, start + len - kk, h); } -static void qsufsort(int64_t *I,int64_t *V,const uint8_t *old,int64_t oldsize) -{ - int64_t buckets[256]; - int64_t i,h,len; - - for(i=0;i<256;i++) buckets[i]=0; - for(i=0;i0;i--) buckets[i]=buckets[i-1]; - buckets[0]=0; - - for(i=0;i 0; i--) buckets[i] = buckets[i - 1]; + buckets[0] = 0; + + for (i = 0; i < oldsize; i++) I[++buckets[old[i]]] = i; + for (i = 0; i < oldsize; i++) V[i] = buckets[old[i]]; + V[oldsize] = 0; + for (i = 1; i < 256; i++) if (buckets[i] == buckets[i - 1] + 1) I[buckets[i]] = -1; + I[0] = -1; + + for (h = 1; I[0] != -(oldsize + 1); h += h) { + len = 0; + for (i = 0; i < oldsize + 1;) { + if (I[i] < 0) { + len -= I[i]; + i -= I[i]; + } else { + if (len) I[i - len] = -len; + len = V[I[i]] + 1 - i; + split(I, V, i, len, h); + i += len; + len = 0; + }; + }; + if (len) I[i - len] = -len; + }; + + for (i = 0; i < oldsize + 1; i++) I[V[i]] = i; } -static int64_t matchlen(const uint8_t *old,int64_t oldsize,const uint8_t *new,int64_t newsize) -{ - int64_t i; +/* + * Given two pointers, old and new, limited by old_size and new_size accordingly, + * return me the amount of bytes that matched from the beginning of the pointers + * (not to exceed either old_size or new_size). + */ +static int64_t matchlen(const uint8_t *old, int64_t old_size, const uint8_t *new, int64_t new_size) { + int64_t i; - for(i=0;(iy) { - *pos=I[st]; - return x; - } else { - *pos=I[en]; - return y; - } - }; - - x=st+(en-st)/2; - if(memcmp(old+I[x],new,MIN(oldsize-I[x],newsize))<0) { - return search(I,old,oldsize,new,newsize,x,en,pos); - } else { - return search(I,old,oldsize,new,newsize,st,x,pos); - }; +/** + * @param I index (suffix array of old) + * @param old original binary (never changes!) + * @param old_size original binary size + * @param new search from this location in new binary + * @param new_size how many bytes available in new + * @param st starting index(?) + * @param en ending index(?) + * @param pos where to write position in old where the longer + * match was found. + * @return matched length. + */ +static int64_t search(const int64_t *I, const uint8_t *old, int64_t old_size, + const uint8_t *new, int64_t new_size, int64_t st, int64_t en, int64_t *pos) { + int64_t x, y; + + // If distance between 2 indexes less than 2 + // $TODO is there a guarantee that st != en? + if (en - st < 2) { + // try to match suffix #st (x) and suffix #en (y) at 'new' + x = matchlen(old + I[st], old_size - I[st], new, new_size); + y = matchlen(old + I[en], old_size - I[en], new, new_size); + + if (x > y) { + *pos = I[st]; + return x; + } else { + *pos = I[en]; + return y; + } + }; + + // x is the middle between start and end + x = st + (en - st) / 2; + // If bytewise, the string at index (x) is "left" of string at "new"... + if (memcmp(old + I[x], new, MIN(old_size - I[x], new_size)) < 0) { + // let's look for a match between "x" and "en" + // that's because it's not gonna ever be left of x, since I + // is ordered + return search(I, old, old_size, new, new_size, x, en, pos); + } else { + // otherwise, let's look between st and x (can't be right of x) + return search(I, old, old_size, new, new_size, st, x, pos); + }; } -static void offtout(int64_t x,uint8_t *buf) -{ - int64_t y; +static void offtout(int64_t x, uint8_t *buf) { + int64_t y; + + if (x < 0) y = -x; else y = x; + + buf[0] = y % 256; + y -= buf[0]; + y = y / 256; + buf[1] = y % 256; + y -= buf[1]; + y = y / 256; + buf[2] = y % 256; + y -= buf[2]; + y = y / 256; + buf[3] = y % 256; + y -= buf[3]; + y = y / 256; + buf[4] = y % 256; + y -= buf[4]; + y = y / 256; + buf[5] = y % 256; + y -= buf[5]; + y = y / 256; + buf[6] = y % 256; + y -= buf[6]; + y = y / 256; + buf[7] = y % 256; + + if (x < 0) buf[7] |= 0x80; +} - if(x<0) y=-x; else y=x; +static int64_t writedata(struct bsdiff_stream *stream, const void *buffer, int64_t length) { + int64_t result = 0; - buf[0]=y%256;y-=buf[0]; - y=y/256;buf[1]=y%256;y-=buf[1]; - y=y/256;buf[2]=y%256;y-=buf[2]; - y=y/256;buf[3]=y%256;y-=buf[3]; - y=y/256;buf[4]=y%256;y-=buf[4]; - y=y/256;buf[5]=y%256;y-=buf[5]; - y=y/256;buf[6]=y%256;y-=buf[6]; - y=y/256;buf[7]=y%256; + while (length > 0) { + const int smallsize = (int) MIN(length, INT_MAX); + const int writeresult = stream->write(stream, buffer, smallsize); + if (writeresult == -1) { + return -1; + } - if(x<0) buf[7]|=0x80; -} + result += writeresult; + length -= smallsize; + buffer = (uint8_t *) buffer + smallsize; + } -static int64_t writedata(struct bsdiff_stream* stream, const void* buffer, int64_t length) -{ - int64_t result = 0; - - while (length > 0) - { - const int smallsize = (int)MIN(length, INT_MAX); - const int writeresult = stream->write(stream, buffer, smallsize); - if (writeresult == -1) - { - return -1; - } - - result += writeresult; - length -= smallsize; - buffer = (uint8_t*)buffer + smallsize; - } - - return result; + return result; } -struct bsdiff_request -{ - const uint8_t* old; - int64_t oldsize; - const uint8_t* new; - int64_t newsize; - struct bsdiff_stream* stream; - int64_t *I; - uint8_t *buffer; +struct bsdiff_request { + const uint8_t *old; + int64_t oldsize; + const uint8_t *new; + int64_t newsize; + struct bsdiff_stream *stream; + int64_t *I; + uint8_t *buffer; }; -static int bsdiff_internal(const struct bsdiff_request req) -{ - int64_t *I,*V; - int64_t scan,pos,len; - int64_t lastscan,lastpos,lastoffset; - int64_t oldscore,scsc; - int64_t s,Sf,lenf,Sb,lenb; - int64_t overlap,Ss,lens; - int64_t i; - uint8_t *buffer; - uint8_t buf[8 * 3]; - - if((V=req.stream->malloc((req.oldsize+1)*sizeof(int64_t)))==NULL) return -1; - I = req.I; - - qsufsort(I,V,req.old,req.oldsize); - req.stream->free(V); - - buffer = req.buffer; - - /* Compute the differences, writing ctrl as we go */ - scan=0;len=0;pos=0; - lastscan=0;lastpos=0;lastoffset=0; - while(scanoldscore+8)) break; - - if((scan+lastoffsetSf*2-lenf) { Sf=s; lenf=i; }; - }; - - lenb=0; - if(scan=lastscan+i)&&(pos>=i);i++) { - if(req.old[pos-i]==req.new[scan-i]) s++; - if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; }; - }; - }; - - if(lastscan+lenf>scan-lenb) { - overlap=(lastscan+lenf)-(scan-lenb); - s=0;Ss=0;lens=0; - for(i=0;iSs) { Ss=s; lens=i+1; }; - }; - - lenf+=lens-overlap; - lenb-=lens; - }; - - offtout(lenf,buf); - offtout((scan-lenb)-(lastscan+lenf),buf+8); - offtout((pos-lenb)-(lastpos+lenf),buf+16); - - /* Write control data */ - if (writedata(req.stream, buf, sizeof(buf))) - return -1; - - /* Write diff data */ - for(i=0;imalloc((req.oldsize + 1) * sizeof(int64_t))) == NULL) return -1; + I = req.I; + + qsufsort(I, V, req.old, req.oldsize); + req.stream->free(V); + + buffer = req.buffer; + + /* Compute the differences, writing ctrl as we go */ + + scan = 0; // position we are scanning New from. + len = 0; + pos = 0; + lastscan = 0; + lastpos = 0; + lastoffset = 0; + + + while (scan < req.newsize) { + oldscore = 0; + + printf("About to start scan@%'lld, last_scan=%'lld, last_pos=%'lld, last_offset=%'lld\n", + scan, lastscan, lastpos, lastoffset); + + for (scsc = scan += len; scan < req.newsize; scan++) { + len = search(I, req.old, req.oldsize, req.new + scan, req.newsize - scan, + 0, req.oldsize, &pos); + + // len now has the length of a matched string of 'req.new+scan' anywhere in old. + // pos points to where that match was found. + + printf("New@%'lld matched old@%'lld for %'lld bytes. Will calc old score from %'lld\n", + scan, pos, len, (lastoffset+scsc)); + + for (; scsc < scan + len; scsc++) + + // let's drag scsc from the start of the scan, in amount of matched length. + + if ((scsc + lastoffset < req.oldsize) && + (req.old[scsc + lastoffset] == req.new[scsc])) + oldscore++; + + printf("Old score %'lld\n", oldscore); + + if (((len == oldscore) && (len != 0)) || + (len > oldscore + 8)) { + printf("stopping scan because %s\n", (len > oldscore + 8)?"Length is superior":"100% match"); + break; + } + + if ((scan + lastoffset < req.oldsize) && + (req.old[scan + lastoffset] == req.new[scan])) { + printf("Old score %'lld, decreasing\n", oldscore); + oldscore--; + } + }; + + printf("Scan completed, len=%'lld, score %'lld, %'lld bytes left in new\n", len, oldscore, req.newsize-scan); + + if ((len != oldscore) || (scan == req.newsize)) { + +#if 0 + printf("Writing buffer, len %'lld oldscore %'lld, scan %'lld, new size %'lld\n", + len, oldscore, scan, req.newsize); +#endif + + // we want to establish 2 values: lenf and lenb + // lenf is how many bytes are we gonna 'diff' + // lenb is how many bytes we gonna not serve at all right now + // (and instead deal with them in the next scan) + + // we are effectively dealing with the block of New[lastscan to scan] + // and Old[lastpos to pos] The beginning of New block is aligned with the beginning of the Old + // block, and their ends are also aligned, which creates "compression" or "tear" in the "middle". + + // lenf is calculated as: the index between lastscan and scan (not to exceed oldsize, counting from lastpos), + // where the difference between the doubled amount of matches from Old[lastpos] and New[lastscan] to (i) + // is maximized. + s = 0; + fill_rate = 0; + lenf = 0; + for (i = 0; (lastscan + i < scan) && (lastpos + i < req.oldsize);) { + // s is the amount of matched characters. + if (req.old[lastpos + i] == req.new[lastscan + i]) s++; + i++; + if (s * 2 - i > fill_rate) { + // if the amount of matched characters minus + fill_rate = s * 2 - i; + lenf = i; + }; + }; + + // lenb is in essence reverse of lenf. We start an index from the end of the current block. + // We then find the value where the amount of matched bytes from the end of the block, doubled, + // minus total amount of bytes considered, is maximum. + + lenb = 0; + if (scan < req.newsize) { + s = 0; + fill_rate = 0; + for (i = 1; (scan >= lastscan + i) && (pos >= i); i++) { + if (req.old[pos - i] == req.new[scan - i]) s++; + if (s * 2 - i > fill_rate) { + fill_rate = s * 2 - i; + lenb = i; + }; + }; + }; + + // now of course it is possible there is an overlap, considering how we + // arrived to both lenf and lenb + if (lastscan + lenf > scan - lenb) { + overlap = (lastscan + lenf) - (scan - lenb); + + s = 0; + Ss = 0; + lens = 0; + for (i = 0; i < overlap; i++) { + + // we are comparing the overlapped block simultaneously + // to the old binary as if overlap was relative with the beginning + // of the old block, and as if it was relative to the end of the old block. + // + // Think of it that way: + // new block |-----------------| + // new block |-----[ ovl ]-----| + // old block |---------------| + // can be viewed as: + // |-----[ ovl ]---| (relative to the beginning of the block) + // |---[ ovl ]-----| (relative to the end of the block) + // we are trying to establish "lens", + // which tells us how to divide up the overlaid part + + // if the byte matches with an overlap if taken from the beginning of the old + // block, increase s. + if (req.new[lastscan + lenf - overlap + i] == + req.old[lastpos + lenf - overlap + i]) + s++; + + // but if the byte matches with the overlap if taken from the end of the old block, + // decrease s. + if (req.new[scan - lenb + i] == + req.old[pos - lenb + i]) + s--; + + + if (s > Ss) { + // remember the index inside the overlap where s value was maximum. + Ss = s; + lens = i + 1; + }; + }; + + + // lens is a stake inside the overlap region, we divide along the stake, + // everything on the left goes to lenf, and on the right to lenb. + + lenf += lens - overlap; + lenb -= lens; + }; + + // now, all of space between oldscan and scan is divided into potentially 3 regions: + // 1. oldscan to oldscan + lenf : all of that region is to be considered a "diff" + // region right now. + // 2. oldscan + lenf to scan - lenb : area that is considered "new", and is quoted verbatim + // 3. scan - lenb to scan : area that we are postponing for now. + + // read diff stream of that length + offtout(lenf, buf); + // write out that many bytes of new file + offtout((scan - lenb) - (lastscan + lenf), buf + 8); + // replacing that many bytes of the old file + offtout((pos - lenb) - (lastpos + lenf), buf + 16); + + /* Write control data */ + if (writedata(req.stream, buf, sizeof(buf))) + return -1; + + int64_t zrs = 0; + + /* Write diff data */ + for (i = 0; i < lenf; i++) + if (!(buffer[i] = req.new[lastscan + i] - req.old[lastpos + i])) zrs++; + if (writedata(req.stream, buffer, lenf)) + return -1; + + printf("Buffer output has %'lld diff, %'lld as-is, %'lld backup, old index %'lld, zero count %'lld\n", + lenf, (scan - lenb) - (lastscan + lenf), lenb, (pos - lenb) - (lastpos + lenf), zrs); + + /* Write extra data */ + for (i = 0; i < (scan - lenb) - (lastscan + lenf); i++) + buffer[i] = req.new[lastscan + lenf + i]; + if (writedata(req.stream, buffer, (scan - lenb) - (lastscan + lenf))) + return -1; + + lastscan = scan - lenb; + lastpos = pos - lenb; + lastoffset = pos - scan; + } + }; + + return 0; } -int bsdiff(const uint8_t* old, int64_t oldsize, const uint8_t* new, int64_t newsize, struct bsdiff_stream* stream) -{ - int result; - struct bsdiff_request req; +int bsdiff(const uint8_t *old, int64_t oldsize, const uint8_t *new, int64_t newsize, struct bsdiff_stream *stream) { + int result; + struct bsdiff_request req; - if((req.I=stream->malloc((oldsize+1)*sizeof(int64_t)))==NULL) - return -1; + if ((req.I = stream->malloc((oldsize + 1) * sizeof(int64_t))) == NULL) + return -1; - if((req.buffer=stream->malloc(newsize+1))==NULL) - { - stream->free(req.I); - return -1; - } + if ((req.buffer = stream->malloc(newsize + 1)) == NULL) { + stream->free(req.I); + return -1; + } - req.old = old; - req.oldsize = oldsize; - req.new = new; - req.newsize = newsize; - req.stream = stream; + req.old = old; + req.oldsize = oldsize; + req.new = new; + req.newsize = newsize; + req.stream = stream; - result = bsdiff_internal(req); + result = bsdiff_internal(req); - stream->free(req.buffer); - stream->free(req.I); + stream->free(req.buffer); + stream->free(req.I); - return result; + return result; } #if defined(BSDIFF_EXECUTABLE) @@ -362,84 +515,84 @@ int bsdiff(const uint8_t* old, int64_t oldsize, const uint8_t* new, int64_t news static int bz2_write(struct bsdiff_stream* stream, const void* buffer, int size) { - int bz2err; - BZFILE* bz2; + int bz2err; + BZFILE* bz2; - bz2 = (BZFILE*)stream->opaque; - BZ2_bzWrite(&bz2err, bz2, (void*)buffer, size); - if (bz2err != BZ_STREAM_END && bz2err != BZ_OK) - return -1; + bz2 = (BZFILE*)stream->opaque; + BZ2_bzWrite(&bz2err, bz2, (void*)buffer, size); + if (bz2err != BZ_STREAM_END && bz2err != BZ_OK) + return -1; - return 0; + return 0; } int main(int argc,char *argv[]) { - int fd; - int bz2err; - uint8_t *old,*new; - off_t oldsize,newsize; - uint8_t buf[8]; - FILE * pf; - struct bsdiff_stream stream; - BZFILE* bz2; - - memset(&bz2, 0, sizeof(bz2)); - stream.malloc = malloc; - stream.free = free; - stream.write = bz2_write; - - if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); - - /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure - that we never try to malloc(0) and get a NULL pointer */ - if(((fd=open(argv[1],O_RDONLY,0))<0) || - ((oldsize=lseek(fd,0,SEEK_END))==-1) || - ((old=malloc(oldsize+1))==NULL) || - (lseek(fd,0,SEEK_SET)!=0) || - (read(fd,old,oldsize)!=oldsize) || - (close(fd)==-1)) err(1,"%s",argv[1]); - - - /* Allocate newsize+1 bytes instead of newsize bytes to ensure - that we never try to malloc(0) and get a NULL pointer */ - if(((fd=open(argv[2],O_RDONLY,0))<0) || - ((newsize=lseek(fd,0,SEEK_END))==-1) || - ((new=malloc(newsize+1))==NULL) || - (lseek(fd,0,SEEK_SET)!=0) || - (read(fd,new,newsize)!=newsize) || - (close(fd)==-1)) err(1,"%s",argv[2]); - - /* Create the patch file */ - if ((pf = fopen(argv[3], "w")) == NULL) - err(1, "%s", argv[3]); - - /* Write header (signature+newsize)*/ - offtout(newsize, buf); - if (fwrite("ENDSLEY/BSDIFF43", 16, 1, pf) != 1 || - fwrite(buf, sizeof(buf), 1, pf) != 1) - err(1, "Failed to write header"); - - - if (NULL == (bz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0))) - errx(1, "BZ2_bzWriteOpen, bz2err=%d", bz2err); - - stream.opaque = bz2; - if (bsdiff(old, oldsize, new, newsize, &stream)) - err(1, "bsdiff"); - - BZ2_bzWriteClose(&bz2err, bz2, 0, NULL, NULL); - if (bz2err != BZ_OK) - err(1, "BZ2_bzWriteClose, bz2err=%d", bz2err); - - if (fclose(pf)) - err(1, "fclose"); - - /* Free the memory we used */ - free(old); - free(new); - - return 0; + int fd; + int bz2err; + uint8_t *old,*new; + off_t oldsize,newsize; + uint8_t buf[8]; + FILE * pf; + struct bsdiff_stream stream; + BZFILE* bz2; + + memset(&bz2, 0, sizeof(bz2)); + stream.malloc = malloc; + stream.free = free; + stream.write = bz2_write; + + if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); + + /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure + that we never try to malloc(0) and get a NULL pointer */ + if(((fd=open(argv[1],O_RDONLY,0))<0) || + ((oldsize=lseek(fd,0,SEEK_END))==-1) || + ((old=malloc(oldsize+1))==NULL) || + (lseek(fd,0,SEEK_SET)!=0) || + (read(fd,old,oldsize)!=oldsize) || + (close(fd)==-1)) err(1,"%s",argv[1]); + + + /* Allocate newsize+1 bytes instead of newsize bytes to ensure + that we never try to malloc(0) and get a NULL pointer */ + if(((fd=open(argv[2],O_RDONLY,0))<0) || + ((newsize=lseek(fd,0,SEEK_END))==-1) || + ((new=malloc(newsize+1))==NULL) || + (lseek(fd,0,SEEK_SET)!=0) || + (read(fd,new,newsize)!=newsize) || + (close(fd)==-1)) err(1,"%s",argv[2]); + + /* Create the patch file */ + if ((pf = fopen(argv[3], "w")) == NULL) + err(1, "%s", argv[3]); + + /* Write header (signature+newsize)*/ + offtout(newsize, buf); + if (fwrite("ENDSLEY/BSDIFF43", 16, 1, pf) != 1 || + fwrite(buf, sizeof(buf), 1, pf) != 1) + err(1, "Failed to write header"); + + + if (NULL == (bz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0))) + errx(1, "BZ2_bzWriteOpen, bz2err=%d", bz2err); + + stream.opaque = bz2; + if (bsdiff(old, oldsize, new, newsize, &stream)) + err(1, "bsdiff"); + + BZ2_bzWriteClose(&bz2err, bz2, 0, NULL, NULL); + if (bz2err != BZ_OK) + err(1, "BZ2_bzWriteClose, bz2err=%d", bz2err); + + if (fclose(pf)) + err(1, "fclose"); + + /* Free the memory we used */ + free(old); + free(new); + + return 0; } #endif