Subversion Repositories nw_plus

Rev

Blame | Last modification | View Log | RSS feed

  1. /*-
  2.  * Copyright 2003-2005 Colin Percival
  3.  * All rights reserved
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted providing that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  *
  14.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  15.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  18.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  22.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  23.  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  24.  * POSSIBILITY OF SUCH DAMAGE.
  25.  */
  26.  
  27. #if 0
  28. __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:06 cperciva Exp $");
  29. #endif
  30.  
  31. #include <bzlib.h>
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <err.h>
  36. #include <unistd.h>
  37. #include <fcntl.h>
  38.  
  39. static off_t offtin(u_char *buf)
  40. {
  41.         off_t y;
  42.  
  43.         y=buf[7]&0x7F;
  44.         y=y*256;y+=buf[6];
  45.         y=y*256;y+=buf[5];
  46.         y=y*256;y+=buf[4];
  47.         y=y*256;y+=buf[3];
  48.         y=y*256;y+=buf[2];
  49.         y=y*256;y+=buf[1];
  50.         y=y*256;y+=buf[0];
  51.  
  52.         if(buf[7]&0x80) y=-y;
  53.  
  54.         return y;
  55. }
  56.  
  57. int main(int argc,char * argv[])
  58. {
  59.         FILE * f, * cpf, * dpf, * epf;
  60.         BZFILE * cpfbz2, * dpfbz2, * epfbz2;
  61.         int cbz2err, dbz2err, ebz2err;
  62.         int fd;
  63.         ssize_t oldsize,newsize;
  64.         ssize_t bzctrllen,bzdatalen;
  65.         u_char header[32],buf[8];
  66.         u_char *old, *new;
  67.         off_t oldpos,newpos;
  68.         off_t ctrl[3];
  69.         off_t lenread;
  70.         off_t i;
  71.  
  72.         if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);
  73.  
  74.         /* Open patch file */
  75.         if ((f = fopen(argv[3], "r")) == NULL)
  76.                 err(1, "fopen(%s)", argv[3]);
  77.  
  78.         /*
  79.         File format:
  80.                 0       8       "BSDIFF40"
  81.                 8       8       X
  82.                 16      8       Y
  83.                 24      8       sizeof(newfile)
  84.                 32      X       bzip2(control block)
  85.                 32+X    Y       bzip2(diff block)
  86.                 32+X+Y  ???     bzip2(extra block)
  87.         with control block a set of triples (x,y,z) meaning "add x bytes
  88.         from oldfile to x bytes from the diff block; copy y bytes from the
  89.         extra block; seek forwards in oldfile by z bytes".
  90.         */
  91.  
  92.         /* Read header */
  93.         if (fread(header, 1, 32, f) < 32) {
  94.                 if (feof(f))
  95.                         errx(1, "Corrupt patch\n");
  96.                 err(1, "fread(%s)", argv[3]);
  97.         }
  98.  
  99.         /* Check for appropriate magic */
  100.         if (memcmp(header, "BSDIFF40", 8) != 0)
  101.                 errx(1, "Corrupt patch\n");
  102.  
  103.         /* Read lengths from header */
  104.         bzctrllen=offtin(header+8);
  105.         bzdatalen=offtin(header+16);
  106.         newsize=offtin(header+24);
  107.         if((bzctrllen<0) || (bzdatalen<0) || (newsize<0))
  108.                 errx(1,"Corrupt patch\n");
  109.  
  110.         /* Close patch file and re-open it via libbzip2 at the right places */
  111.         if (fclose(f))
  112.                 err(1, "fclose(%s)", argv[3]);
  113.         if ((cpf = fopen(argv[3], "r")) == NULL)
  114.                 err(1, "fopen(%s)", argv[3]);
  115.         if (fseeko(cpf, 32, SEEK_SET))
  116.                 err(1, "fseeko(%s, %lld)", argv[3],
  117.                     (long long)32);
  118.         if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
  119.                 errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);
  120.         if ((dpf = fopen(argv[3], "r")) == NULL)
  121.                 err(1, "fopen(%s)", argv[3]);
  122.         if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))
  123.                 err(1, "fseeko(%s, %lld)", argv[3],
  124.                     (long long)(32 + bzctrllen));
  125.         if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
  126.                 errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);
  127.         if ((epf = fopen(argv[3], "r")) == NULL)
  128.                 err(1, "fopen(%s)", argv[3]);
  129.         if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
  130.                 err(1, "fseeko(%s, %lld)", argv[3],
  131.                     (long long)(32 + bzctrllen + bzdatalen));
  132.         if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
  133.                 errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);
  134.  
  135.         if(((fd=open(argv[1],O_RDONLY,0))<0) ||
  136.                 ((oldsize=lseek(fd,0,SEEK_END))==-1) ||
  137.                 ((old=malloc(oldsize+1))==NULL) ||
  138.                 (lseek(fd,0,SEEK_SET)!=0) ||
  139.                 (read(fd,old,oldsize)!=oldsize) ||
  140.                 (close(fd)==-1)) err(1,"%s",argv[1]);
  141.         if((new=malloc(newsize+1))==NULL) err(1,NULL);
  142.  
  143.         oldpos=0;newpos=0;
  144.         while(newpos<newsize) {
  145.                 /* Read control data */
  146.                 for(i=0;i<=2;i++) {
  147.                         lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
  148.                         if ((lenread < 8) || ((cbz2err != BZ_OK) &&
  149.                             (cbz2err != BZ_STREAM_END)))
  150.                                 errx(1, "Corrupt patch\n");
  151.                         ctrl[i]=offtin(buf);
  152.                 };
  153.  
  154.                 /* Sanity-check */
  155.                 if(newpos+ctrl[0]>newsize)
  156.                         errx(1,"Corrupt patch\n");
  157.  
  158.                 /* Read diff string */
  159.                 lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]);
  160.                 if ((lenread < ctrl[0]) ||
  161.                     ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
  162.                         errx(1, "Corrupt patch\n");
  163.  
  164.                 /* Add old data to diff string */
  165.                 for(i=0;i<ctrl[0];i++)
  166.                         if((oldpos+i>=0) && (oldpos+i<oldsize))
  167.                                 new[newpos+i]+=old[oldpos+i];
  168.  
  169.                 /* Adjust pointers */
  170.                 newpos+=ctrl[0];
  171.                 oldpos+=ctrl[0];
  172.  
  173.                 /* Sanity-check */
  174.                 if(newpos+ctrl[1]>newsize)
  175.                         errx(1,"Corrupt patch\n");
  176.  
  177.                 /* Read extra string */
  178.                 lenread = BZ2_bzRead(&ebz2err, epfbz2, new + newpos, ctrl[1]);
  179.                 if ((lenread < ctrl[1]) ||
  180.                     ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
  181.                         errx(1, "Corrupt patch\n");
  182.  
  183.                 /* Adjust pointers */
  184.                 newpos+=ctrl[1];
  185.                 oldpos+=ctrl[2];
  186.         };
  187.  
  188.         /* Clean up the bzip2 reads */
  189.         BZ2_bzReadClose(&cbz2err, cpfbz2);
  190.         BZ2_bzReadClose(&dbz2err, dpfbz2);
  191.         BZ2_bzReadClose(&ebz2err, epfbz2);
  192.         if (fclose(cpf) || fclose(dpf) || fclose(epf))
  193.                 err(1, "fclose(%s)", argv[3]);
  194.  
  195.         /* Write the new file */
  196.         if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) ||
  197.                 (write(fd,new,newsize)!=newsize) || (close(fd)==-1))
  198.                 err(1,"%s",argv[2]);
  199.  
  200.         free(new);
  201.         free(old);
  202.  
  203.         return 0;
  204. }
  205.