Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Unified Diff: chrome/installer/mac/third_party/bsdiff/goobspatch.c

Issue 2716005: Modify bsdiff 4.3 to goobsdiff, which is appropriate for use as the Mac binary differ/patcher (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/installer/mac/third_party/bsdiff/goobsdiff.gyp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/installer/mac/third_party/bsdiff/goobspatch.c
===================================================================
--- chrome/installer/mac/third_party/bsdiff/goobspatch.c (revision 49280)
+++ chrome/installer/mac/third_party/bsdiff/goobspatch.c (working copy)
@@ -28,109 +28,226 @@
__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 <err.h>
+#include <openssl/sha.h>
#include <unistd.h>
-#include <fcntl.h>
+#include <zlib.h>
-static off_t offtin(u_char *buf)
+#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)
{
- off_t y;
+ return le64toh(*((off_t*)buf));
+}
- 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];
+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]);
+}
- if(buf[7]&0x80) y=-y;
+/* cfile is a uniform interface to read from maybe-compressed files. */
- return y;
+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, * cpf, * dpf, * epf;
- BZFILE * cpfbz2, * dpfbz2, * epfbz2;
- int cbz2err, dbz2err, ebz2err;
+ FILE * f;
+ cfile cf, df, ef;
int fd;
- ssize_t oldsize,newsize;
- ssize_t bzctrllen,bzdatalen;
- u_char header[32],buf[8];
+ 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 lenread;
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\n",argv[0]);
+ if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile",argv[0]);
/* Open patch file */
- if ((f = fopen(argv[3], "r")) == NULL)
+ if ((f = fopen(argv[3], "rb")) == 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
+ 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, 32, f) < 32) {
+ if (fread(header, 1, sizeof(header), f) < sizeof(header)) {
if (feof(f))
- errx(1, "Corrupt patch\n");
+ errx(1, "corrupt patch (header size)");
err(1, "fread(%s)", argv[3]);
}
/* Check for appropriate magic */
- if (memcmp(header, "BSDIFF40", 8) != 0)
- errx(1, "Corrupt patch\n");
+ if (memcmp(header, "BSDIFF4G", 8) != 0)
+ errx(1, "corrupt patch (magic)");
/* 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");
+ 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)");
- /* Close patch file and re-open it via libbzip2 at the right places */
+ 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 ((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) ||
@@ -138,28 +255,32 @@
(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++) {
- lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
- if ((lenread < 8) || ((cbz2err != BZ_OK) &&
- (cbz2err != BZ_STREAM_END)))
- errx(1, "Corrupt patch\n");
+ cfread(&cf, buf, 8);
ctrl[i]=offtin(buf);
};
/* Sanity-check */
if(newpos+ctrl[0]>newsize)
- errx(1,"Corrupt patch\n");
+ errx(1,"corrupt patch (diff): overrun");
/* 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");
+ cfread(&df, new + newpos, ctrl[0]);
/* Add old data to diff string */
for(i=0;i<ctrl[0];i++)
@@ -172,30 +293,33 @@
/* Sanity-check */
if(newpos+ctrl[1]>newsize)
- errx(1,"Corrupt patch\n");
+ errx(1,"corrupt patch (extra): overrun");
/* 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");
+ cfread(&ef, new + newpos, ctrl[1]);
/* 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]);
+ /* 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,0666))<0) ||
+ if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0644))<0) ||
(write(fd,new,newsize)!=newsize) || (close(fd)==-1))
- err(1,"%s",argv[2]);
+ err(1,"open/write/close(%s)",argv[2]);
free(new);
free(old);
« no previous file with comments | « chrome/installer/mac/third_party/bsdiff/goobsdiff.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698