diff options
author | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-09 21:09:13 +0000 |
---|---|---|
committer | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-09 21:09:13 +0000 |
commit | abfbdf119992742605e52ac1d1ab61ab2e9f03f5 (patch) | |
tree | 4d84e5b1062cb9caeb6597eec533dea3eb0c2ed1 /chrome/installer/mac | |
parent | 07556f7f8976250b9ef9ce3a788afed53ef6e0af (diff) | |
download | chromium_src-abfbdf119992742605e52ac1d1ab61ab2e9f03f5.zip chromium_src-abfbdf119992742605e52ac1d1ab61ab2e9f03f5.tar.gz chromium_src-abfbdf119992742605e52ac1d1ab61ab2e9f03f5.tar.bz2 |
Modify bsdiff 4.3 to create goobsdiff, which is appropriate for use as the Mac
binary differ/patcher.
BUG=45017
TEST=none
Review URL: http://codereview.chromium.org/2716005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@49316 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer/mac')
-rw-r--r-- | chrome/installer/mac/third_party/bsdiff/README.chromium | 41 | ||||
-rw-r--r-- | chrome/installer/mac/third_party/bsdiff/bspatch.c | 204 | ||||
-rw-r--r-- | chrome/installer/mac/third_party/bsdiff/goobsdiff.c (renamed from chrome/installer/mac/third_party/bsdiff/bsdiff.c) | 256 | ||||
-rw-r--r-- | chrome/installer/mac/third_party/bsdiff/goobsdiff.gyp | 36 | ||||
-rw-r--r-- | chrome/installer/mac/third_party/bsdiff/goobspatch.c | 328 |
5 files changed, 574 insertions, 291 deletions
diff --git a/chrome/installer/mac/third_party/bsdiff/README.chromium b/chrome/installer/mac/third_party/bsdiff/README.chromium index 4e8b024..edee853 100644 --- a/chrome/installer/mac/third_party/bsdiff/README.chromium +++ b/chrome/installer/mac/third_party/bsdiff/README.chromium @@ -8,7 +8,44 @@ License File: LICENSE Description: Binary diff/patch utility. There are other copies of BSDiff in the Chromium repository, but they're all different. The other copies are based on Mozilla's -fork of BSDiff, which serves a different set of needs. +fork of BSDiff, which serves a different set of needs. Relative to upstream +BSDiff, Mozilla's version removes all compression, adds a CRC-32 check of the +original file, replaces the custom off_t encoding with signed 32-bit +big-endian integers, and contains a total reorganization of the code. The +version in this directory contains no Mozilla code and builds directly on the +upstream version. It retains and enhances the compression, uses SHA1 to check +both the original file and the patched file, uses a different off_t encoding +more compatible with the original, and involves minimal changes to the +original code. + +Theoretically, a hash of the original file should be enough to guarantee data +integrity, but in the event of algorithmic or programming bugs or other +unexpected conditions, a hash of the patched file provides a better guarantee. +This implementation now checks the integrity of both the original and the +patched files. SHA1, rather than CRC-32, is used to minimize the likelihood +that an original file that has been intentionally tampered with will produce +an altered patched file without being detected. Local Modifications: - - Added LICENSE file by copying the license block from bsdiff.c and bspatch.c. + - Added LICENSE file by copying the license block from bsdiff.c and + bspatch.c. + - The following modifications are relative to the original unpatched version, + checked in to the Chromium repository at r49280. + - Created goobsdiff.gyp for GYP build system integration. + - Renamed bsdiff.c to goobsdiff.c and bspatch.c to goobspatch.c. + - Added #include <sys/types.h> to goobspatch.c so that it compiles. (Oops!) + - Changed the magic number in the header from BSDIFF40 to BSDIFF4G. + - Expanded the header to include SHA1 hashes of the original and new files, + and added hash checks to the patcher. + - Expanded the header to include the lengths of the control, diff, and extra + blocks in the patch file, and added patch file length validation to the + patcher. + - Replaced custom off_t encoding with signed 64-bit little-endian integers. + - The control, diff, and extra blocks can be compressed with bzip2 or gzip, + or left uncompressed, independently of one another, depending on which is + smallest. This often results in a net reduction in patch size of about 3%. + - Error messages in the patcher are slightly more descriptive. + - The patcher treats a few more unexpected read cases as errors than it did + previously. This will theoretically cause it to exit with an error instead + of sitting in a busy loop or crashing when certain malformatted patch files + are provided. diff --git a/chrome/installer/mac/third_party/bsdiff/bspatch.c b/chrome/installer/mac/third_party/bsdiff/bspatch.c deleted file mode 100644 index f4b821c..0000000 --- a/chrome/installer/mac/third_party/bsdiff/bspatch.c +++ /dev/null @@ -1,204 +0,0 @@ -/*- - * Copyright 2003-2005 Colin Percival - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#if 0 -__FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:06 cperciva Exp $"); -#endif - -#include <bzlib.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <err.h> -#include <unistd.h> -#include <fcntl.h> - -static off_t offtin(u_char *buf) -{ - off_t y; - - y=buf[7]&0x7F; - y=y*256;y+=buf[6]; - y=y*256;y+=buf[5]; - y=y*256;y+=buf[4]; - y=y*256;y+=buf[3]; - y=y*256;y+=buf[2]; - y=y*256;y+=buf[1]; - y=y*256;y+=buf[0]; - - if(buf[7]&0x80) y=-y; - - return y; -} - -int main(int argc,char * argv[]) -{ - FILE * f, * cpf, * dpf, * epf; - BZFILE * cpfbz2, * dpfbz2, * epfbz2; - int cbz2err, dbz2err, ebz2err; - int fd; - ssize_t oldsize,newsize; - ssize_t bzctrllen,bzdatalen; - u_char header[32],buf[8]; - u_char *old, *new; - off_t oldpos,newpos; - off_t ctrl[3]; - off_t lenread; - off_t i; - - if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); - - /* Open patch file */ - if ((f = fopen(argv[3], "r")) == NULL) - err(1, "fopen(%s)", argv[3]); - - /* - File format: - 0 8 "BSDIFF40" - 8 8 X - 16 8 Y - 24 8 sizeof(newfile) - 32 X bzip2(control block) - 32+X Y bzip2(diff block) - 32+X+Y ??? bzip2(extra block) - with control block a set of triples (x,y,z) meaning "add x bytes - from oldfile to x bytes from the diff block; copy y bytes from the - extra block; seek forwards in oldfile by z bytes". - */ - - /* Read header */ - if (fread(header, 1, 32, f) < 32) { - if (feof(f)) - errx(1, "Corrupt patch\n"); - err(1, "fread(%s)", argv[3]); - } - - /* Check for appropriate magic */ - if (memcmp(header, "BSDIFF40", 8) != 0) - errx(1, "Corrupt patch\n"); - - /* Read lengths from header */ - bzctrllen=offtin(header+8); - bzdatalen=offtin(header+16); - newsize=offtin(header+24); - if((bzctrllen<0) || (bzdatalen<0) || (newsize<0)) - errx(1,"Corrupt patch\n"); - - /* Close patch file and re-open it via libbzip2 at the right places */ - if (fclose(f)) - err(1, "fclose(%s)", argv[3]); - if ((cpf = fopen(argv[3], "r")) == NULL) - err(1, "fopen(%s)", argv[3]); - if (fseeko(cpf, 32, SEEK_SET)) - err(1, "fseeko(%s, %lld)", argv[3], - (long long)32); - if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL) - errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err); - if ((dpf = fopen(argv[3], "r")) == NULL) - err(1, "fopen(%s)", argv[3]); - if (fseeko(dpf, 32 + bzctrllen, SEEK_SET)) - err(1, "fseeko(%s, %lld)", argv[3], - (long long)(32 + bzctrllen)); - if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL) - errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err); - if ((epf = fopen(argv[3], "r")) == NULL) - err(1, "fopen(%s)", argv[3]); - if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET)) - err(1, "fseeko(%s, %lld)", argv[3], - (long long)(32 + bzctrllen + bzdatalen)); - if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL) - errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err); - - 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]); - if((new=malloc(newsize+1))==NULL) err(1,NULL); - - oldpos=0;newpos=0; - while(newpos<newsize) { - /* Read control data */ - for(i=0;i<=2;i++) { - lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8); - if ((lenread < 8) || ((cbz2err != BZ_OK) && - (cbz2err != BZ_STREAM_END))) - errx(1, "Corrupt patch\n"); - ctrl[i]=offtin(buf); - }; - - /* Sanity-check */ - if(newpos+ctrl[0]>newsize) - errx(1,"Corrupt patch\n"); - - /* Read diff string */ - lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]); - if ((lenread < ctrl[0]) || - ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END))) - errx(1, "Corrupt patch\n"); - - /* Add old data to diff string */ - for(i=0;i<ctrl[0];i++) - if((oldpos+i>=0) && (oldpos+i<oldsize)) - new[newpos+i]+=old[oldpos+i]; - - /* Adjust pointers */ - newpos+=ctrl[0]; - oldpos+=ctrl[0]; - - /* Sanity-check */ - if(newpos+ctrl[1]>newsize) - errx(1,"Corrupt patch\n"); - - /* Read extra string */ - lenread = BZ2_bzRead(&ebz2err, epfbz2, new + newpos, ctrl[1]); - if ((lenread < ctrl[1]) || - ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END))) - errx(1, "Corrupt patch\n"); - - /* Adjust pointers */ - newpos+=ctrl[1]; - oldpos+=ctrl[2]; - }; - - /* Clean up the bzip2 reads */ - BZ2_bzReadClose(&cbz2err, cpfbz2); - BZ2_bzReadClose(&dbz2err, dpfbz2); - BZ2_bzReadClose(&ebz2err, epfbz2); - if (fclose(cpf) || fclose(dpf) || fclose(epf)) - err(1, "fclose(%s)", argv[3]); - - /* Write the new file */ - if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) || - (write(fd,new,newsize)!=newsize) || (close(fd)==-1)) - err(1,"%s",argv[2]); - - free(new); - free(old); - - return 0; -} diff --git a/chrome/installer/mac/third_party/bsdiff/bsdiff.c b/chrome/installer/mac/third_party/bsdiff/goobsdiff.c index 150a7f7..8d41ec3 100644 --- a/chrome/installer/mac/third_party/bsdiff/bsdiff.c +++ b/chrome/installer/mac/third_party/bsdiff/goobsdiff.c @@ -33,10 +33,23 @@ __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bsdiff/bsdiff.c,v 1.1 2005/08/06 01:59:05 #include <bzlib.h> #include <err.h> #include <fcntl.h> +#include <openssl/sha.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <zlib.h> + +#if defined(__APPLE__) +#include <libkern/OSByteOrder.h> +#define htole64(x) OSSwapHostToLittleInt64(x) +#elif defined(__linux__) +#include <endian.h> +#elif defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64)) +#define htole64(x) (x) +#else +#error Provide htole64 for this platform +#endif #define MIN(x,y) (((x)<(y)) ? (x) : (y)) @@ -175,22 +188,112 @@ static off_t search(off_t *I,u_char *old,off_t oldsize, }; } -static void offtout(off_t x,u_char *buf) +static inline void offtout(off_t x,u_char *buf) +{ + *((off_t*)buf) = htole64(x); +} + +/* zlib provides compress2, which deflates to deflate (zlib) format. This is + * unfortunately distinct from gzip format in that the headers wrapping the + * decompressed data are different. gbspatch reads gzip-compressed data using + * the file-oriented gzread interface, which only supports gzip format. + * compress2gzip is identical to zlib's compress2 except that it produces gzip + * output compatible with gzread. This change is achieved by calling + * deflateInit2 instead of deflateInit and specifying 31 for windowBits; + * numbers greater than 15 cause the addition of a gzip wrapper. */ +static int compress2gzip(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, int level) { - off_t y; + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - if(x<0) y=-x; else y=x; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)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; + err = deflateInit2(&stream, + level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY); + if (err != Z_OK) return err; - if(x<0) buf[7]|=0x80; + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* Recompress buf of size buf_len using bzip2 or gzip. The smallest version is + * used. The original uncompressed variant may be the smallest. Returns a + * number identifying the encoding, 1 for uncompressed, 2 for bzip2, and 3 for + * gzip. If the original uncompressed variant is not smallest, it is freed. + * The caller must free any buf after this function returns. */ +static char make_small(u_char **buf, off_t *buf_len) +{ + u_char *source = *buf; + off_t source_len = *buf_len; + u_char *bz2, *gz; + unsigned int bz2_len; + unsigned long gz_len; + int zerr; + char smallest; + + smallest = 1; + + bz2_len = source_len + 1; + bz2 = malloc(bz2_len); + zerr = BZ2_bzBuffToBuffCompress((char*)bz2, &bz2_len, (char*)source, + source_len, 9, 0, 0); + if (zerr == BZ_OK) { + if (bz2_len < *buf_len) { + smallest = 2; + *buf = bz2; + *buf_len = bz2_len; + } else { + free(bz2); + bz2 = NULL; + } + } else if (zerr == BZ_OUTBUFF_FULL) { + free(bz2); + bz2 = NULL; + } else { + errx(1, "BZ2_bzBuffToBuffCompress: %d", zerr); + } + + gz_len = source_len + 1; + gz = malloc(gz_len); + zerr = compress2gzip(gz, &gz_len, source, source_len, 9); + if (zerr == Z_OK) { + if (gz_len < *buf_len) { + smallest = 3; + *buf = gz; + *buf_len = gz_len; + } else { + free(gz); + gz = NULL; + } + } else if (zerr == Z_BUF_ERROR) { + free(gz); + gz = NULL; + } else { + errx(1, "compress2gzip: %d", zerr); + } + + if (smallest != 1) { + free(source); + } + + return smallest; } int main(int argc,char *argv[]) @@ -205,15 +308,12 @@ int main(int argc,char *argv[]) off_t s,Sf,lenf,Sb,lenb; off_t overlap,Ss,lens; off_t i; - off_t dblen,eblen; - u_char *db,*eb; - u_char buf[8]; - u_char header[32]; + off_t cblen, dblen, eblen; + u_char *cb, *db, *eb; + u_char header[96]; FILE * pf; - BZFILE * pfbz2; - int bz2err; - if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); + if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile",argv[0]); /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure that we never try to malloc(0) and get a NULL pointer */ @@ -240,35 +340,44 @@ int main(int argc,char *argv[]) (read(fd,new,newsize)!=newsize) || (close(fd)==-1)) err(1,"%s",argv[2]); - if(((db=malloc(newsize+1))==NULL) || + if(((cb=malloc(newsize+1))==NULL) || + ((db=malloc(newsize+1))==NULL) || ((eb=malloc(newsize+1))==NULL)) err(1,NULL); + cblen=0; dblen=0; eblen=0; /* Create the patch file */ - if ((pf = fopen(argv[3], "w")) == NULL) + if ((pf = fopen(argv[3], "wb")) == NULL) err(1, "%s", argv[3]); - /* Header is - 0 8 "BSDIFF40" - 8 8 length of bzip2ed ctrl block - 16 8 length of bzip2ed diff block - 24 8 length of new file */ - /* File is - 0 32 Header - 32 ?? Bzip2ed ctrl block - ?? ?? Bzip2ed diff block - ?? ?? Bzip2ed extra block */ - memcpy(header,"BSDIFF40",8); - offtout(0, header + 8); - offtout(0, header + 16); - offtout(newsize, header + 24); - if (fwrite(header, 32, 1, pf) != 1) + /* File format: + 0 8 "BSDIFF4G" + 8 8 length of compressed control block (x) + 16 8 length of compressed diff block (y) + 24 8 length of compressed extra block (z) + 32 8 length of old file + 40 8 length of new file + 48 20 SHA1 of old file + 68 20 SHA1 of new file + 88 1 encoding of control block + 89 1 encoding of diff block + 90 1 encoding of extra block + 91 5 unused + 96 x compressed control block + 96+x y compressed diff block + 96+x+y z compressed extra block + Encodings are 1 (uncompressed), 2 (bzip2), and 3 (gzip). */ + memset(header, 0, sizeof(header)); + if (fwrite(header, sizeof(header), 1, pf) != 1) err(1, "fwrite(%s)", argv[3]); + memcpy(header, "BSDIFF4G", 8); + offtout(oldsize, header + 32); + offtout(newsize, header + 40); + SHA1(old, oldsize, header + 48); + SHA1(new, newsize, header + 68); - /* Compute the differences, writing ctrl as we go */ - if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL) - errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err); + /* Compute the differences */ scan=0;len=0; lastscan=0;lastpos=0;lastoffset=0; while(scan<newsize) { @@ -331,69 +440,46 @@ int main(int argc,char *argv[]) dblen+=lenf; eblen+=(scan-lenb)-(lastscan+lenf); - offtout(lenf,buf); - BZ2_bzWrite(&bz2err, pfbz2, buf, 8); - if (bz2err != BZ_OK) - errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); + offtout(lenf, cb + cblen); + cblen += 8; - offtout((scan-lenb)-(lastscan+lenf),buf); - BZ2_bzWrite(&bz2err, pfbz2, buf, 8); - if (bz2err != BZ_OK) - errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); + offtout((scan - lenb) - (lastscan + lenf), cb + cblen); + cblen += 8; - offtout((pos-lenb)-(lastpos+lenf),buf); - BZ2_bzWrite(&bz2err, pfbz2, buf, 8); - if (bz2err != BZ_OK) - errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); + offtout((pos - lenb) - (lastpos + lenf), cb + cblen); + cblen += 8; lastscan=scan-lenb; lastpos=pos-lenb; lastoffset=pos-scan; }; }; - BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL); - if (bz2err != BZ_OK) - errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err); - - /* Compute size of compressed ctrl data */ - if ((len = ftello(pf)) == -1) - err(1, "ftello"); - offtout(len-32, header + 8); - - /* Write compressed diff data */ - if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL) - errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err); - BZ2_bzWrite(&bz2err, pfbz2, db, dblen); - if (bz2err != BZ_OK) - errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); - BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL); - if (bz2err != BZ_OK) - errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err); - - /* Compute size of compressed diff data */ - if ((newsize = ftello(pf)) == -1) - err(1, "ftello"); - offtout(newsize - len, header + 16); - - /* Write compressed extra data */ - if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL) - errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err); - BZ2_bzWrite(&bz2err, pfbz2, eb, eblen); - if (bz2err != BZ_OK) - errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); - BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL); - if (bz2err != BZ_OK) - errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err); + + header[88] = make_small(&cb, &cblen); + header[89] = make_small(&db, &dblen); + header[90] = make_small(&eb, &eblen); + + if (fwrite(cb, 1, cblen, pf) != cblen) + err(1, "fwrite"); + if (fwrite(db, 1, dblen, pf) != dblen) + err(1, "fwrite"); + if (fwrite(eb, 1, eblen, pf) != eblen) + err(1, "fwrite"); + + offtout(cblen, header + 8); + offtout(dblen, header + 16); + offtout(eblen, header + 24); /* Seek to the beginning, write the header, and close the file */ if (fseeko(pf, 0, SEEK_SET)) err(1, "fseeko"); - if (fwrite(header, 32, 1, pf) != 1) + if (fwrite(header, sizeof(header), 1, pf) != 1) err(1, "fwrite(%s)", argv[3]); if (fclose(pf)) err(1, "fclose"); /* Free the memory we used */ + free(cb); free(db); free(eb); free(I); diff --git a/chrome/installer/mac/third_party/bsdiff/goobsdiff.gyp b/chrome/installer/mac/third_party/bsdiff/goobsdiff.gyp new file mode 100644 index 0000000..7fe95f8 --- /dev/null +++ b/chrome/installer/mac/third_party/bsdiff/goobsdiff.gyp @@ -0,0 +1,36 @@ +# Copyright (c) 2010 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'target_defaults': { + 'type': 'executable', + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/usr/lib/libbz2.dylib', + '$(SDKROOT)/usr/lib/libz.dylib', + '$(SDKROOT)/usr/lib/libcrypto.dylib', + ], + }, + }, + 'targets': [ + { + 'target_name': 'goobsdiff', + 'sources': [ + 'goobsdiff.c', + ], + }, + { + 'target_name': 'goobspatch', + 'sources': [ + 'goobspatch.c', + ], + }, + ], +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/chrome/installer/mac/third_party/bsdiff/goobspatch.c b/chrome/installer/mac/third_party/bsdiff/goobspatch.c new file mode 100644 index 0000000..e519f17 --- /dev/null +++ b/chrome/installer/mac/third_party/bsdiff/goobspatch.c @@ -0,0 +1,328 @@ +/*- + * Copyright 2003-2005 Colin Percival + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if 0 +__FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:06 cperciva Exp $"); +#endif + +#include <sys/types.h> + +#include <bzlib.h> +#include <err.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <openssl/sha.h> +#include <unistd.h> +#include <zlib.h> + +#if defined(__APPLE__) +#include <libkern/OSByteOrder.h> +#define le64toh(x) OSSwapLittleToHostInt64(x) +#elif defined(__linux__) +#include <endian.h> +#elif defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64)) +#define le64toh(x) (x) +#else +#error Provide le64toh for this platform +#endif + +static inline off_t offtin(u_char *buf) +{ + return le64toh(*((off_t*)buf)); +} + +static void sha1tostr(const u_char *sha1, char *sha1str) +{ + int i; + for (i = 0; i < SHA_DIGEST_LENGTH; ++i) + sprintf(&sha1str[i * 2], "%02x", sha1[i]); +} + +/* cfile is a uniform interface to read from maybe-compressed files. */ + +typedef struct { + FILE *f; /* method = 1, 2 */ + union { + BZFILE *bz2; /* method = 2 */ + gzFile gz; /* method = 3 */ + } u; + const char *tag; + unsigned char method; +} cfile; + +/* Opens a file at path, seeks to offset off, and prepares for reading using + * the specified method. Supported methods are plain uncompressed (1), bzip2 + * (2), and gzip (3). tag is used as an identifier for error reporting. */ +static void cfopen(cfile *cf, const char *path, off_t off, + const char *tag, unsigned char method) +{ + int fd; + int zerr; + + if (method == 1 || method == 2) { + /* Use stdio for uncompressed files. The bzip interface also + * sits on top of a stdio FILE* but does not take "ownership" + * of the FILE*. */ + if ((cf->f = fopen(path, "rb")) == NULL) + err(1, "fdopen(%s)", tag); + if ((fseeko(cf->f, off, SEEK_SET)) != 0) + err(1, "fseeko(%s, %lld)", tag, off); + if (method == 2) { + if ((cf->u.bz2 = BZ2_bzReadOpen(&zerr, cf->f, 0, 0, + NULL, 0)) == NULL) + errx(1, "BZ2_bzReadOpen(%s): %d", tag, zerr); + } + } else if (method == 3) { + if ((fd = open(path, O_RDONLY)) < 0) + err(1, "open(%s)", tag); + if (lseek(fd, off, SEEK_SET) != off) + err(1, "lseek(%s, %lld)", tag, off); + if ((cf->u.gz = gzdopen(fd, "rb")) == NULL) + errx(1, "gzdopen(%s)", tag); + } else { + errx(1, "cfopen(%s): unknown method %d", tag, method); + } + + cf->tag = tag; + cf->method = method; +} + +static void cfclose(cfile *cf) +{ + int zerr; + + if (cf->method == 1 || cf->method == 2) { + if (cf->method == 2) { + zerr = BZ_OK; + BZ2_bzReadClose(&zerr, cf->u.bz2); + if (zerr != BZ_OK) + errx(1, "BZ2_bzReadClose(%s): %d\n", + cf->tag, zerr); + } + if (fclose(cf->f) != 0) + err(1, "fclose(%s)", cf->tag); + } else if (cf->method == 3) { + if ((zerr = gzclose(cf->u.gz)) != Z_OK) + errx(1, "gzclose(%s): %d", cf->tag, zerr); + } else { + errx(1, "cfclose(%s): unknown method %d", cf->tag, cf->method); + } +} + +static void cfread(cfile *cf, u_char *buf, size_t len) +{ + size_t nread; + int zerr; + + if (cf->method == 1) { + if ((nread = fread(buf, 1, len, cf->f)) != len) { + if (!ferror(cf->f)) + errx(1, "fread(%s, %zd): short read %zd", + cf->tag, len, nread); + err(1, "fread(%s, %zd)", cf->tag, len); + } + } else if (cf->method == 2) { + zerr = BZ_OK; + if ((nread = BZ2_bzRead(&zerr, cf->u.bz2, buf, len)) != len) { + if (zerr == BZ_OK) + errx(1, "BZ2_bzRead(%s, %zd): short read %zd", + cf->tag, len, nread); + errx(1, "BZ2_bzRead(%s, %zd): %d", cf->tag, len, zerr); + } + } else if (cf->method == 3) { + if ((nread = gzread(cf->u.gz, buf, len)) != len) { + zerr = Z_OK; + gzerror(cf->u.gz, &zerr); + if (zerr == Z_OK) + errx(1, "gzread(%s, %zd): short read %zd", + cf->tag, len, nread); + errx(1, "gzread(%s, %zd): %d", cf->tag, len, zerr); + } + } else { + errx(1, "cfread(%s, %zd): unknown method %d", + cf->tag, len, cf->method); + } +} + +int main(int argc,char * argv[]) +{ + FILE * f; + cfile cf, df, ef; + int fd; + off_t expect_oldsize, oldsize, newsize, patchsize; + off_t zctrllen, zdatalen, zextralen; + u_char header[96], buf[8]; + u_char *old, *new; + off_t oldpos,newpos; + off_t ctrl[3]; + off_t i; + u_char sha1[SHA_DIGEST_LENGTH]; + char sha1str[SHA_DIGEST_LENGTH * 2 + 1]; + char expected_sha1str[SHA_DIGEST_LENGTH * 2 + 1]; + + if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile",argv[0]); + + /* Open patch file */ + if ((f = fopen(argv[3], "rb")) == NULL) + err(1, "fopen(%s)", argv[3]); + + /* + File format: + 0 8 "BSDIFF4G" + 8 8 length of compressed control block (x) + 16 8 length of compressed diff block (y) + 24 8 length of compressed extra block (z) + 32 8 length of old file + 40 8 length of new file + 48 20 SHA1 of old file + 68 20 SHA1 of new file + 88 1 encoding of control block + 89 1 encoding of diff block + 90 1 encoding of extra block + 91 5 unused + 96 x compressed control block + 96+x y compressed diff block + 96+x+y z compressed extra block + Encodings are 1 (uncompressed), 2 (bzip2), and 3 (gzip). + The control block is a set of triples (x,y,z) meaning "add x bytes + from oldfile to x bytes from the diff block; copy y bytes from the + extra block; seek forwards in oldfile by z bytes". + */ + + /* Read header */ + if (fread(header, 1, sizeof(header), f) < sizeof(header)) { + if (feof(f)) + errx(1, "corrupt patch (header size)"); + err(1, "fread(%s)", argv[3]); + } + + /* Check for appropriate magic */ + if (memcmp(header, "BSDIFF4G", 8) != 0) + errx(1, "corrupt patch (magic)"); + + /* Read lengths from header */ + zctrllen = offtin(header + 8); + zdatalen = offtin(header + 16); + zextralen = offtin(header + 24); + expect_oldsize = offtin(header + 32); + newsize = offtin(header + 40); + if (zctrllen < 0 || zdatalen < 0 || zextralen < 0) + errx(1, "corrupt patch (stream sizes)"); + if (expect_oldsize < 0 || newsize < 0) + errx(1, "corrupt patch (file sizes)"); + + if (fseeko(f, 0, SEEK_END) != 0 || (patchsize = ftello(f)) < 0) + err(1, "fseeko/ftello(%s)", argv[3]); + if (patchsize != sizeof(header) + zctrllen + zdatalen + zextralen) + errx(1, "corrupt patch (patch size)"); + + cfopen(&cf, argv[3], sizeof(header), "control", header[88]); + cfopen(&df, argv[3], sizeof(header) + zctrllen, "diff", header[89]); + cfopen(&ef, argv[3], sizeof(header) + zctrllen + zdatalen, "extra", + header[90]); + + if (fclose(f)) + err(1, "fclose(%s)", argv[3]); + + 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]); + if (expect_oldsize != oldsize) + errx(1, "old size mismatch: %lld != %lld", + oldsize, expect_oldsize); + SHA1(old, oldsize, sha1); + if (memcmp(sha1, header + 48, sizeof(sha1)) != 0) { + sha1tostr(sha1, sha1str); + sha1tostr(header + 48, expected_sha1str); + errx(1, "old hash mismatch: %s != %s", + sha1str, expected_sha1str); + } + if((new=malloc(newsize+1))==NULL) err(1,NULL); + + oldpos=0;newpos=0; + while(newpos<newsize) { + /* Read control data */ + for(i=0;i<=2;i++) { + cfread(&cf, buf, 8); + ctrl[i]=offtin(buf); + }; + + /* Sanity-check */ + if(newpos+ctrl[0]>newsize) + errx(1,"corrupt patch (diff): overrun"); + + /* Read diff string */ + cfread(&df, new + newpos, ctrl[0]); + + /* Add old data to diff string */ + for(i=0;i<ctrl[0];i++) + if((oldpos+i>=0) && (oldpos+i<oldsize)) + new[newpos+i]+=old[oldpos+i]; + + /* Adjust pointers */ + newpos+=ctrl[0]; + oldpos+=ctrl[0]; + + /* Sanity-check */ + if(newpos+ctrl[1]>newsize) + errx(1,"corrupt patch (extra): overrun"); + + /* Read extra string */ + cfread(&ef, new + newpos, ctrl[1]); + + /* Adjust pointers */ + newpos+=ctrl[1]; + oldpos+=ctrl[2]; + }; + + /* Clean up the readers */ + cfclose(&cf); + cfclose(&df); + cfclose(&ef); + + SHA1(new, newsize, sha1); + if (memcmp(sha1, header + 68, sizeof(sha1)) != 0) { + sha1tostr(sha1, sha1str); + sha1tostr(header + 68, expected_sha1str); + errx(1, "new hash mismatch: %s != %s", + sha1str, expected_sha1str); + } + + /* Write the new file */ + if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0644))<0) || + (write(fd,new,newsize)!=newsize) || (close(fd)==-1)) + err(1,"open/write/close(%s)",argv[2]); + + free(new); + free(old); + + return 0; +} |