| Index: chrome/installer/mac/third_party/bsdiff/goobsdiff.c
|
| ===================================================================
|
| --- chrome/installer/mac/third_party/bsdiff/goobsdiff.c (revision 49280)
|
| +++ chrome/installer/mac/third_party/bsdiff/goobsdiff.c (working copy)
|
| @@ -33,11 +33,24 @@
|
| #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))
|
|
|
| static void split(off_t *I,off_t *V,off_t start,off_t len,off_t h)
|
| @@ -175,24 +188,114 @@
|
| };
|
| }
|
|
|
| -static void offtout(off_t x,u_char *buf)
|
| +static inline void offtout(off_t x,u_char *buf)
|
| {
|
| - off_t y;
|
| + *((off_t*)buf) = htole64(x);
|
| +}
|
|
|
| - if(x<0) y=-x; else y=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)
|
| +{
|
| + z_stream stream;
|
| + int err;
|
|
|
| - 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;
|
| + stream.next_in = (Bytef*)source;
|
| + stream.avail_in = (uInt)sourceLen;
|
|
|
| - if(x<0) buf[7]|=0x80;
|
| + stream.next_out = dest;
|
| + stream.avail_out = (uInt)*destLen;
|
| + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
|
| +
|
| + stream.zalloc = (alloc_func)0;
|
| + stream.zfree = (free_func)0;
|
| + stream.opaque = (voidpf)0;
|
| +
|
| + err = deflateInit2(&stream,
|
| + level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
|
| + if (err != Z_OK) return err;
|
| +
|
| + 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[])
|
| {
|
| int fd;
|
| @@ -205,15 +308,12 @@
|
| 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 @@
|
| (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 @@
|
| 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);
|
| + header[88] = make_small(&cb, &cblen);
|
| + header[89] = make_small(&db, &dblen);
|
| + header[90] = make_small(&eb, &eblen);
|
|
|
| - /* 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);
|
| + 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");
|
|
|
| - /* Compute size of compressed diff data */
|
| - if ((newsize = ftello(pf)) == -1)
|
| - err(1, "ftello");
|
| - offtout(newsize - len, header + 16);
|
| + offtout(cblen, header + 8);
|
| + offtout(dblen, header + 16);
|
| + offtout(eblen, header + 24);
|
|
|
| - /* 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);
|
| -
|
| /* 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);
|
|
|