SASC
DVBSoftCAM

bspatch.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright 2003-2005 Colin Percival
00003  * All rights reserved
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted providing that the following conditions 
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  *
00014  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00015  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00016  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00017  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00018  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00019  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00020  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00021  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00022  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00023  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00024  * POSSIBILITY OF SUCH DAMAGE.
00025  */
00026 
00027 #if 0
00028 __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:06 cperciva Exp $");
00029 #endif
00030 
00031 #include <bzlib.h>
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <err.h>
00036 #include <unistd.h>
00037 #include <fcntl.h>
00038 
00039 static off_t offtin(u_char *buf)
00040 {
00041         off_t y;
00042 
00043         y=buf[7]&0x7F;
00044         y=y*256;y+=buf[6];
00045         y=y*256;y+=buf[5];
00046         y=y*256;y+=buf[4];
00047         y=y*256;y+=buf[3];
00048         y=y*256;y+=buf[2];
00049         y=y*256;y+=buf[1];
00050         y=y*256;y+=buf[0];
00051 
00052         if(buf[7]&0x80) y=-y;
00053 
00054         return y;
00055 }
00056 
00057 int main(int argc,char * argv[])
00058 {
00059         FILE * f, * cpf, * dpf, * epf;
00060         BZFILE * cpfbz2, * dpfbz2, * epfbz2;
00061         int cbz2err, dbz2err, ebz2err;
00062         int fd;
00063         ssize_t oldsize,newsize;
00064         ssize_t bzctrllen,bzdatalen;
00065         u_char header[32],buf[8];
00066         u_char *old, *new;
00067         off_t oldpos,newpos;
00068         off_t ctrl[3];
00069         off_t lenread;
00070         off_t i;
00071 
00072         if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);
00073 
00074         /* Open patch file */
00075         if ((f = fopen(argv[3], "r")) == NULL)
00076                 err(1, "fopen(%s)", argv[3]);
00077 
00078         /*
00079         File format:
00080                 0       8       "BSDIFF40"
00081                 8       8       X
00082                 16      8       Y
00083                 24      8       sizeof(newfile)
00084                 32      X       bzip2(control block)
00085                 32+X    Y       bzip2(diff block)
00086                 32+X+Y  ???     bzip2(extra block)
00087         with control block a set of triples (x,y,z) meaning "add x bytes
00088         from oldfile to x bytes from the diff block; copy y bytes from the
00089         extra block; seek forwards in oldfile by z bytes".
00090         */
00091 
00092         /* Read header */
00093         if (fread(header, 1, 32, f) < 32) {
00094                 if (feof(f))
00095                         errx(1, "Corrupt patch\n");
00096                 err(1, "fread(%s)", argv[3]);
00097         }
00098 
00099         /* Check for appropriate magic */
00100         if (memcmp(header, "BSDIFF40", 8) != 0)
00101                 errx(1, "Corrupt patch\n");
00102 
00103         /* Read lengths from header */
00104         bzctrllen=offtin(header+8);
00105         bzdatalen=offtin(header+16);
00106         newsize=offtin(header+24);
00107         if((bzctrllen<0) || (bzdatalen<0) || (newsize<0))
00108                 errx(1,"Corrupt patch\n");
00109 
00110         /* Close patch file and re-open it via libbzip2 at the right places */
00111         if (fclose(f))
00112                 err(1, "fclose(%s)", argv[3]);
00113         if ((cpf = fopen(argv[3], "r")) == NULL)
00114                 err(1, "fopen(%s)", argv[3]);
00115         if (fseeko(cpf, 32, SEEK_SET))
00116                 err(1, "fseeko(%s, %lld)", argv[3],
00117                     (long long)32);
00118         if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
00119                 errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);
00120         if ((dpf = fopen(argv[3], "r")) == NULL)
00121                 err(1, "fopen(%s)", argv[3]);
00122         if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))
00123                 err(1, "fseeko(%s, %lld)", argv[3],
00124                     (long long)(32 + bzctrllen));
00125         if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
00126                 errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);
00127         if ((epf = fopen(argv[3], "r")) == NULL)
00128                 err(1, "fopen(%s)", argv[3]);
00129         if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
00130                 err(1, "fseeko(%s, %lld)", argv[3],
00131                     (long long)(32 + bzctrllen + bzdatalen));
00132         if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
00133                 errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);
00134 
00135         if(((fd=open(argv[1],O_RDONLY,0))<0) ||
00136                 ((oldsize=lseek(fd,0,SEEK_END))==-1) ||
00137                 ((old=malloc(oldsize+1))==NULL) ||
00138                 (lseek(fd,0,SEEK_SET)!=0) ||
00139                 (read(fd,old,oldsize)!=oldsize) ||
00140                 (close(fd)==-1)) err(1,"%s",argv[1]);
00141         if((new=malloc(newsize+1))==NULL) err(1,NULL);
00142 
00143         oldpos=0;newpos=0;
00144         while(newpos<newsize) {
00145                 /* Read control data */
00146                 for(i=0;i<=2;i++) {
00147                         lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
00148                         if ((lenread < 8) || ((cbz2err != BZ_OK) &&
00149                             (cbz2err != BZ_STREAM_END)))
00150                                 errx(1, "Corrupt patch\n");
00151                         ctrl[i]=offtin(buf);
00152                 };
00153 
00154                 /* Sanity-check */
00155                 if(newpos+ctrl[0]>newsize)
00156                         errx(1,"Corrupt patch\n");
00157 
00158                 /* Read diff string */
00159                 lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]);
00160                 if ((lenread < ctrl[0]) ||
00161                     ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
00162                         errx(1, "Corrupt patch\n");
00163 
00164                 /* Add old data to diff string */
00165                 for(i=0;i<ctrl[0];i++)
00166                         if((oldpos+i>=0) && (oldpos+i<oldsize))
00167                                 new[newpos+i]+=old[oldpos+i];
00168 
00169                 /* Adjust pointers */
00170                 newpos+=ctrl[0];
00171                 oldpos+=ctrl[0];
00172 
00173                 /* Sanity-check */
00174                 if(newpos+ctrl[1]>newsize)
00175                         errx(1,"Corrupt patch\n");
00176 
00177                 /* Read extra string */
00178                 lenread = BZ2_bzRead(&ebz2err, epfbz2, new + newpos, ctrl[1]);
00179                 if ((lenread < ctrl[1]) ||
00180                     ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
00181                         errx(1, "Corrupt patch\n");
00182 
00183                 /* Adjust pointers */
00184                 newpos+=ctrl[1];
00185                 oldpos+=ctrl[2];
00186         };
00187 
00188         /* Clean up the bzip2 reads */
00189         BZ2_bzReadClose(&cbz2err, cpfbz2);
00190         BZ2_bzReadClose(&dbz2err, dpfbz2);
00191         BZ2_bzReadClose(&ebz2err, epfbz2);
00192         if (fclose(cpf) || fclose(dpf) || fclose(epf))
00193                 err(1, "fclose(%s)", argv[3]);
00194 
00195         /* Write the new file */
00196         if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) ||
00197                 (write(fd,new,newsize)!=newsize) || (close(fd)==-1))
00198                 err(1,"%s",argv[2]);
00199 
00200         free(new);
00201         free(old);
00202 
00203         return 0;
00204 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines