* Integrated bsdiff/bspatch 4.2 (from

http://www.daemonology.net/bsdiff/bsdiff-4.2.tar.gz) into the source
  tree.  The license is a bit peculiar, but it does allow verbatim
  copying, which is what we do here (i.e., so don't make any changes
  to the sources).
This commit is contained in:
Eelco Dolstra 2004-12-29 22:08:48 +00:00
parent 54d8f08588
commit 4f07ebc67e
9 changed files with 817 additions and 1 deletions

View file

@ -189,6 +189,7 @@ AC_CONFIG_FILES([Makefile
src/nix-instantiate/Makefile
src/nix-env/Makefile
src/log2xml/Makefile
src/bsdiff-4.2/Makefile
scripts/Makefile
corepkgs/Makefile
corepkgs/fetchurl/Makefile

View file

@ -1,5 +1,5 @@
SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \
libexpr nix-instantiate nix-env log2xml
libexpr nix-instantiate nix-env log2xml bsdiff-4.2
EXTRA_DIST = aterm-helper.pl

121
src/bsdiff-4.2/LICENSE Normal file
View file

@ -0,0 +1,121 @@
BSD Protection License
February 2002
Preamble
--------
The Berkeley Software Distribution ("BSD") license has proven very effective
over the years at allowing for a wide spread of work throughout both
commercial and non-commercial products. For programmers whose primary
intention is to improve the general quality of available software, it is
arguable that there is no better license than the BSD license, as it
permits improvements to be used wherever they will help, without idealogical
or metallic constraint.
This is of particular value to those who produce reference implementations
of proposed standards: The case of TCP/IP clearly illustrates that freely
and universally available implementations leads the rapid acceptance of
standards -- often even being used instead of a de jure standard (eg, OSI
network models).
With the rapid proliferation of software licensed under the GNU General
Public License, however, the continued success of this role is called into
question. Given that the inclusion of a few lines of "GPL-tainted" work
into a larger body of work will result in restricted distribution -- and
given that further work will likely build upon the "tainted" portions,
making them difficult to remove at a future date -- there are inevitable
circumstances where authors would, in order to protect their goal of
providing for the widespread usage of their work, wish to guard against
such "GPL-taint".
In addition, one can imagine that companies which operate by producing and
selling (possibly closed-source) code would wish to protect themselves
against the rise of a GPL-licensed competitor. While under existing
licenses this would mean not releasing their code under any form of open
license, if a license existed under which they could incorporate any
improvements back into their own (commercial) products then they might be
far more willing to provide for non-closed distribution.
For the above reasons, we put forth this "BSD Protection License": A
license designed to retain the freedom granted by the BSD license to use
licensed works in a wide variety of settings, both non-commercial and
commercial, while protecting the work from having future contributors
restrict that freedom.
The precise terms and conditions for copying, distribution, and
modification follow.
BSD PROTECTION LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION, AND MODIFICATION
----------------------------------------------------------------
0. Definitions.
a) "Program", below, refers to any program or work distributed under
the terms of this license.
b) A "work based on the Program", below, refers to either the Program
or any derivative work under copyright law.
c) "Modification", below, refers to the act of creating derivative works.
d) "You", below, refers to each licensee.
1. Scope.
This license governs the copying, distribution, and modification of the
Program. Other activities are outside the scope of this license; The
act of running the Program is not restricted, and the output from the
Program is covered only if its contents constitute a work based on the
Program.
2. Verbatim copies.
You may copy and distribute verbatim copies of the Program as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice; keep
intact all the notices that refer to this License and to the absence of
any warranty; and give any other recipients of the Program a copy of this
License along with the Program.
3. Modification and redistribution under closed license.
You may modify your copy or copies of the Program, and distribute
the resulting derivative works, provided that you meet the
following conditions:
a) The copyright notice and disclaimer on the Program must be reproduced
and included in the source code, documentation, and/or other materials
provided in a manner in which such notices are normally distributed.
b) The derivative work must be clearly identified as such, in order that
it may not be confused with the original work.
c) The license under which the derivative work is distributed must
expressly prohibit the distribution of further derivative works.
4. Modification and redistribution under open license.
You may modify your copy or copies of the Program, and distribute
the resulting derivative works, provided that you meet the
following conditions:
a) The copyright notice and disclaimer on the Program must be reproduced
and included in the source code, documentation, and/or other materials
provided in a manner in which such notices are normally distributed.
b) You must clearly indicate the nature and date of any changes made
to the Program. The full details need not necessarily be included in
the individual modified files, provided that each modified file is
clearly marked as such and instructions are included on where the
full details of the modifications may be found.
c) You must cause any work that you distribute or publish, that in whole
or in part contains or is derived from the Program or any part
thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
5. Implied acceptance.
You may not copy or distribute the Program or any derivative works except
as expressly provided under this license. Consequently, any such action
will be taken as implied acceptance of the terms of this license.
6. NO WARRANTY.
THIS SOFTWARE IS PROVIDED "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 COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (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, EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

View file

@ -0,0 +1,7 @@
libexec_PROGRAMS = bsdiff bspatch
bsdiff_SOURCES = bsdiff.c
bspatch_SOURCES = bspatch.c
AM_CFLAGS = -O3 -DBZIP2=\"$(bzip2)\"

View file

@ -0,0 +1,18 @@
CFLAGS += -O3
.ifdef BZIP2
CFLAGS += -DBZIP2=\"${BZIP2}\"
.endif
PREFIX ?= /usr/local
INSTALL_PROGRAM ?= ${INSTALL} -c -s -m 555
INSTALL_MAN ?= ${INSTALL} -c -m 444
all: bsdiff bspatch
bsdiff: bsdiff.c
bspatch: bspatch.c
install:
${INSTALL_PROGRAM} bsdiff bspatch ${PREFIX}/bin
.ifndef WITHOUT_MAN
${INSTALL_MAN} bsdiff.1 bspatch.1 ${PREFIX}/man/man1
.endif

36
src/bsdiff-4.2/bsdiff.1 Normal file
View file

@ -0,0 +1,36 @@
.Dd May 18, 2003
.Dt BSDIFF 1
.Os FreeBSD
.Sh NAME
.Nm bsdiff
.Nd generate a patch between two binary files
.Sh SYNOPSIS
.Nm
.Ao Ar oldfile Ac Ao Ar newfile Ac Ao Ar patchfile Ac
.Sh DESCRIPTION
.Nm
compares
.Ao Ar oldfile Ac
to
.Ao Ar newfile Ac
and writes to
.Ao Ar patchfile Ac
a binary patch suitable for use by bspatch(1).
When
.Ao Ar oldfile Ac
and
.Ao Ar newfile Ac
are two versions of an executable program, the
patches produced are on average a factor of five smaller
than those produced by any other binary patch tool known
to the author.
.Pp
.Nm
uses memory equal to 17 times the size of
.Ao Ar oldfile Ac ,
and requires
an absolute minimum working set size of 8 times the size of oldfile.
.Sh SEE ALSO
.Xr bspatch 1
.Sh AUTHORS
.An Colin Percival Aq cperciva@daemonology.net

385
src/bsdiff-4.2/bsdiff.c Normal file
View file

@ -0,0 +1,385 @@
/*
bsdiff.c -- Binary patch generator.
Copyright 2003 Colin Percival
For the terms under which this work may be distributed, please see
the adjoining file "LICENSE".
*/
#ifndef BZIP2
#define BZIP2 "/usr/bin/bzip2"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#define MIN(x,y) (((x)<(y)) ? (x) : (y))
void split(off_t *I,off_t *V,off_t start,off_t len,off_t h)
{
off_t i,j,k,x,tmp,jj,kk;
if(len<16) {
for(k=start;k<start+len;k+=j) {
j=1;x=V[I[k]+h];
for(i=1;k+i<start+len;i++) {
if(V[I[k+i]+h]<x) {
x=V[I[k+i]+h];
j=0;
};
if(V[I[k+i]+h]==x) {
tmp=I[k+j];I[k+j]=I[k+i];I[k+i]=tmp;
j++;
};
};
for(i=0;i<j;i++) V[I[k+i]]=k+j-1;
if(j==1) I[k]=-1;
};
return;
};
x=V[I[start+len/2]+h];
jj=0;kk=0;
for(i=start;i<start+len;i++) {
if(V[I[i]+h]<x) jj++;
if(V[I[i]+h]==x) kk++;
};
jj+=start;kk+=jj;
i=start;j=0;k=0;
while(i<jj) {
if(V[I[i]+h]<x) {
i++;
} else if(V[I[i]+h]==x) {
tmp=I[i];I[i]=I[jj+j];I[jj+j]=tmp;
j++;
} else {
tmp=I[i];I[i]=I[kk+k];I[kk+k]=tmp;
k++;
};
};
while(jj+j<kk) {
if(V[I[jj+j]+h]==x) {
j++;
} else {
tmp=I[jj+j];I[jj+j]=I[kk+k];I[kk+k]=tmp;
k++;
};
};
if(jj>start) split(I,V,start,jj-start,h);
for(i=0;i<kk-jj;i++) V[I[jj+i]]=kk-1;
if(jj==kk-1) I[jj]=-1;
if(start+len>kk) split(I,V,kk,start+len-kk,h);
}
void qsufsort(off_t *I,off_t *V,u_char *old,off_t oldsize)
{
off_t buckets[256];
off_t i,h,len;
for(i=0;i<256;i++) buckets[i]=0;
for(i=0;i<oldsize;i++) buckets[old[i]]++;
for(i=1;i<256;i++) buckets[i]+=buckets[i-1];
for(i=255;i>0;i--) buckets[i]=buckets[i-1];
buckets[0]=0;
for(i=0;i<oldsize;i++) I[++buckets[old[i]]]=i;
I[0]=oldsize;
for(i=0;i<oldsize;i++) V[i]=buckets[old[i]];
V[oldsize]=0;
for(i=1;i<256;i++) if(buckets[i]==buckets[i-1]+1) I[buckets[i]]=-1;
I[0]=-1;
for(h=1;I[0]!=-(oldsize+1);h+=h) {
len=0;
for(i=0;i<oldsize+1;) {
if(I[i]<0) {
len-=I[i];
i-=I[i];
} else {
if(len) I[i-len]=-len;
len=V[I[i]]+1-i;
split(I,V,i,len,h);
i+=len;
len=0;
};
};
if(len) I[i-len]=-len;
};
for(i=0;i<oldsize+1;i++) I[V[i]]=i;
}
off_t matchlen(u_char *old,off_t oldsize,u_char *new,off_t newsize)
{
off_t i;
for(i=0;(i<oldsize)&&(i<newsize);i++)
if(old[i]!=new[i]) break;
return i;
}
off_t search(off_t *I,u_char *old,off_t oldsize,
u_char *new,off_t newsize,off_t st,off_t en,off_t *pos)
{
off_t x,y;
if(en-st<2) {
x=matchlen(old+I[st],oldsize-I[st],new,newsize);
y=matchlen(old+I[en],oldsize-I[en],new,newsize);
if(x>y) {
*pos=I[st];
return x;
} else {
*pos=I[en];
return y;
}
};
x=st+(en-st)/2;
if(memcmp(old+I[x],new,MIN(oldsize-I[x],newsize))<0) {
return search(I,old,oldsize,new,newsize,x,en,pos);
} else {
return search(I,old,oldsize,new,newsize,st,x,pos);
};
}
void offtout(off_t x,u_char *buf)
{
off_t y;
if(x<0) y=-x; else y=x;
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;
if(x<0) buf[7]|=0x80;
}
int main(int argc,char *argv[])
{
int fd,p[2];
pid_t pid;
u_char *old,*new;
off_t oldsize,newsize;
off_t *I,*V;
off_t scan,pos,len;
off_t lastscan,lastpos,lastoffset;
off_t oldscore,scsc;
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];
if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);
/* Allocate oldsize+1 bytes instead of oldsize bytes to ensure
that we never try to malloc(0) and get a NULL pointer */
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(((I=malloc((oldsize+1)*sizeof(off_t)))==NULL) ||
((V=malloc((oldsize+1)*sizeof(off_t)))==NULL)) err(1,NULL);
qsufsort(I,V,old,oldsize);
free(V);
/* Allocate newsize+1 bytes instead of newsize bytes to ensure
that we never try to malloc(0) and get a NULL pointer */
if(((fd=open(argv[2],O_RDONLY,0))<0) ||
((newsize=lseek(fd,0,SEEK_END))==-1) ||
((new=malloc(newsize+1))==NULL) ||
(lseek(fd,0,SEEK_SET)!=0) ||
(read(fd,new,newsize)!=newsize) ||
(close(fd)==-1)) err(1,"%s",argv[2]);
if(((db=malloc(newsize+1))==NULL) ||
((eb=malloc(newsize+1))==NULL)) err(1,NULL);
dblen=0;
eblen=0;
if((fd=open(argv[3],O_CREAT|O_TRUNC|O_WRONLY,0666))<0)
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);
memset(header+8,0,24);
if(write(fd,header,32)!=32) err(1,"%s",argv[3]);
if((pipe(p)==-1) || ((pid=fork())==-1)) err(1,NULL);
if(pid==0) {
if((close(0)==-1) || (close(1)==-1) || (dup2(fd,1)==-1) ||
(dup2(p[0],0)==-1) || (close(fd)==-1) ||
(close(p[0])==-1) || (close(p[1])==-1))
err(1,NULL);
execl(BZIP2,BZIP2,"-zc",NULL);
err(1,"%s",BZIP2);
};
if(close(p[0])==-1) err(1,NULL);
scan=0;len=0;
lastscan=0;lastpos=0;lastoffset=0;
while(scan<newsize) {
oldscore=0;
for(scsc=scan+=len;scan<newsize;scan++) {
len=search(I,old,oldsize,new+scan,newsize-scan,
0,oldsize,&pos);
for(;scsc<scan+len;scsc++)
if((scsc+lastoffset<oldsize) &&
(old[scsc+lastoffset] == new[scsc]))
oldscore++;
if(((len==oldscore) && (len!=0)) ||
(len>oldscore+8)) break;
if((scan+lastoffset<oldsize) &&
(old[scan+lastoffset] == new[scan]))
oldscore--;
};
if((len!=oldscore) || (scan==newsize)) {
s=0;Sf=0;lenf=0;
for(i=0;(lastscan+i<scan)&&(lastpos+i<oldsize);) {
if(old[lastpos+i]==new[lastscan+i]) s++;
i++;
if(s*2-i>Sf*2-lenf) { Sf=s; lenf=i; };
};
lenb=0;
if(scan<newsize) {
s=0;Sb=0;
for(i=1;(scan>=lastscan+i)&&(pos>=i);i++) {
if(old[pos-i]==new[scan-i]) s++;
if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; };
};
};
if(lastscan+lenf>scan-lenb) {
overlap=(lastscan+lenf)-(scan-lenb);
s=0;Ss=0;lens=0;
for(i=0;i<overlap;i++) {
if(new[lastscan+lenf-overlap+i]==
old[lastpos+lenf-overlap+i]) s++;
if(new[scan-lenb+i]==
old[pos-lenb+i]) s--;
if(s>Ss) { Ss=s; lens=i+1; };
};
lenf+=lens-overlap;
lenb-=lens;
};
for(i=0;i<lenf;i++)
db[dblen+i]=new[lastscan+i]-old[lastpos+i];
for(i=0;i<(scan-lenb)-(lastscan+lenf);i++)
eb[eblen+i]=new[lastscan+lenf+i];
dblen+=lenf;
eblen+=(scan-lenb)-(lastscan+lenf);
offtout(lenf,buf);
if(write(p[1],buf,8)!=8) err(1,NULL);
offtout((scan-lenb)-(lastscan+lenf),buf);
if(write(p[1],buf,8)!=8) err(1,NULL);
offtout((pos-lenb)-(lastpos+lenf),buf);
if(write(p[1],buf,8)!=8) err(1,NULL);
lastscan=scan-lenb;
lastpos=pos-lenb;
lastoffset=pos-scan;
};
};
if((close(p[1])==-1) || (waitpid(pid,NULL,0)!=pid)) err(1,NULL);
if((len=lseek(fd,0,SEEK_END))==-1) err(1,"%s",argv[3]);
offtout(len-32,buf);
if((lseek(fd,8,SEEK_SET)!=8) || (write(fd,buf,8)!=8))
err(1,"%s",argv[3]);
offtout(newsize,buf);
if((lseek(fd,24,SEEK_SET)!=24) || (write(fd,buf,8)!=8))
err(1,"%s",argv[3]);
if(lseek(fd,0,SEEK_END)==-1) err(1,"%s",argv[3]);
if((pipe(p)==-1) || ((pid=fork())==-1)) err(1,NULL);
if(pid==0) {
if((close(0)==-1) || (close(1)==-1) || (dup2(fd,1)==-1) ||
(dup2(p[0],0)==-1) || (close(fd)==-1) ||
(close(p[0])==-1) || (close(p[1])==-1))
err(1,NULL);
execl(BZIP2,BZIP2,"-zc",NULL);
err(1,"%s",BZIP2);
};
if(close(p[0])==-1) err(1,NULL);
if(write(p[1],db,dblen)!=dblen) err(1,NULL);
if((close(p[1])==-1) || (waitpid(pid,NULL,0)!=pid)) err(1,NULL);
if((newsize=lseek(fd,0,SEEK_END))==-1) err(1,"%s",argv[3]);
offtout(newsize-len,buf);
if((lseek(fd,16,SEEK_SET)!=16) || (write(fd,buf,8)!=8))
err(1,"%s",argv[3]);
if(lseek(fd,0,SEEK_END)==-1) err(1,"%s",argv[3]);
if((pipe(p)==-1) || ((pid=fork())==-1)) err(1,NULL);
if(pid==0) {
if((close(0)==-1) || (close(1)==-1) || (dup2(fd,1)==-1) ||
(dup2(p[0],0)==-1) || (close(fd)==-1) ||
(close(p[0])==-1) || (close(p[1])==-1))
err(1,NULL);
execl(BZIP2,BZIP2,"-zc",NULL);
err(1,"%s",BZIP2);
};
if(close(p[0])==-1) err(1,NULL);
if(write(p[1],eb,eblen)!=eblen) err(1,NULL);
if((close(p[1])==-1) || (waitpid(pid,NULL,0)!=pid)) err(1,NULL);
if(close(fd)==-1) err(1,"%s",argv[3]);
free(db);
free(eb);
free(I);
free(old);
free(new);
return 0;
}

32
src/bsdiff-4.2/bspatch.1 Normal file
View file

@ -0,0 +1,32 @@
.Dd May 18, 2003
.Dt BSPATCH 1
.Os FreeBSD
.Sh NAME
.Nm bspatch
.Nd apply a patch built with bsdiff(1)
.Sh SYNOPSIS
.Nm
.Ao Ar oldfile Ac Ao Ar newfile Ac Ao Ar patchfile Ac
.Sh DESCRIPTION
.Nm
generates
.Ao Ar newfile Ac
from
.Ao Ar oldfile Ac
and
.Ao Ar patchfile Ac
where
.Ao Ar patchfile Ac
is a binary patch built by bsdiff(1).
.Pp
.Nm
uses memory equal to the size of
.Ao Ar oldfile Ac
plus the size of
.Ao Ar newfile Ac ,
but can tolerate a very small working set without a dramatic loss
of performance.
.Sh SEE ALSO
.Xr bsdiff 1
.Sh AUTHORS
.An Colin Percival Aq cperciva@daemonology.net

216
src/bsdiff-4.2/bspatch.c Normal file
View file

@ -0,0 +1,216 @@
/*
.c -- Binary patcher
Copyright 2003,2004 Colin Percival
For the terms under which this work may be distributed, please see
the adjoining file "LICENSE".
*/
#ifndef BZIP2
#define BZIP2 "/usr/bin/bzip2"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
ssize_t loopread(int d,void *buf,size_t nbytes)
{
ssize_t ptr,lenread;
for(ptr=0;ptr<nbytes;ptr+=lenread) {
lenread=read(d,buf+ptr,nbytes-ptr);
if(lenread==0) return ptr;
if(lenread==-1) return -1;
};
return ptr;
}
int bz2read(int fd,off_t offset,off_t len,char * fname,pid_t * pids)
{
int p0[2],p1[2];
u_char * data;
if((pipe(p0)==-1) || (pipe(p1)==-1)) err(1,NULL);
if((pids[0]=fork())==-1) err(1,NULL);
if(pids[0]==0) {
if(close(0) || close(1) || close(p0[0]) ||
close(p1[0]) || close(p1[1])) err(1,NULL);
if((data=malloc(len+1))==NULL) err(1,NULL);
if((pread(fd,data,len,offset)!=len) || close(fd))
err(1,"%s",fname);
if((write(p0[1],data,len)!=len) || close(p0[1]))
err(1,NULL);
free(data);
_exit(0);
};
if((pids[1]=fork())==-1) err(1,NULL);
if(pids[1]==0) {
if(close(0) || close(1) || close(p0[1]) ||
close(p1[0])) err(1,NULL);
if((dup2(p0[0],0)==-1) || close(p0[0])) err(1,NULL);
if((dup2(p1[1],1)==-1) || close(p1[1])) err(1,NULL);
if(close(fd)==-1) err(1,"%s",fname);
execl(BZIP2,BZIP2,"-dc",NULL);
err(1,"%s",BZIP2);
};
if(close(p0[0]) || close(p0[1]) || close(p1[1])) err(1,NULL);
return p1[0];
}
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[])
{
int fd,ctrlpipe,diffpipe,extrapipe;
pid_t pids[6];
ssize_t patchsize,oldsize,newsize;
ssize_t bzctrllen,bzdatalen;
u_char header[32],buf[8];
int version=0;
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]);
if(((fd=open(argv[3],O_RDONLY,0))<0) ||
((patchsize=lseek(fd,0,SEEK_END))==-1) ||
(lseek(fd,0,SEEK_SET)!=0)) err(1,"%s",argv[3]);
if(patchsize<32) errx(1,"Corrupt patch\n");
/*
Ok, this is going to be messy. There are two different patch
formats which we need to support.
The old format (pre-4.0) is:
0 8 "QSUFDIFF" or "BSDIFF30"
8 8 X
16 8 Y
24 8 sizeof(newfile)
32 X bzip2(control block)
32+X Y bzip2(data block)
with control block a set of pairs (x,y) meaning "seek forward
in oldfile by y bytes, and add the next x bytes to x bytes from
the data block".
The new format (4.0) is:
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".
*/
if(read(fd,header,32)!=32) err(1,"%s",argv[3]);
if(memcmp(header,"QSUFDIFF",8)==0) version=1;
if(memcmp(header,"BSDIFF30",8)==0) version=1;
if(memcmp(header,"BSDIFF40",8)==0) version=2;
if(!version) errx(1,"Corrupt patch\n");
bzctrllen=offtin(header+8);
bzdatalen=offtin(header+16);
newsize=offtin(header+24);
if((bzctrllen<0) || (bzdatalen<0) || (newsize<0) ||
((version==1) && (32+bzctrllen+bzdatalen!=patchsize)))
errx(1,"Corrupt patch\n");
ctrlpipe=bz2read(fd,32,bzctrllen,argv[3],pids);
diffpipe=bz2read(fd,32+bzctrllen,bzdatalen,argv[3],pids+2);
if(version==2) {
extrapipe=bz2read(fd,32+bzctrllen+bzdatalen,
patchsize-(32+bzctrllen+bzdatalen),argv[3],pids+4);
};
if(close(fd)==-1) err(1,"%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((new=malloc(newsize+1))==NULL) err(1,NULL);
oldpos=0;newpos=0;
while(newpos<newsize) {
for(i=0;i<=version;i++) {
if((lenread=loopread(ctrlpipe,buf,8))<0) err(1,NULL);
if(lenread<8) errx(1,"Corrupt patch\n");
ctrl[i]=offtin(buf);
};
if(version==1) oldpos+=ctrl[1];
if(newpos+ctrl[0]>newsize) errx(1,"Corrupt patch\n");
if((lenread=loopread(diffpipe,new+newpos,ctrl[0]))<0)
err(1,NULL);
if(lenread!=ctrl[0]) errx(1,"Corrupt patch\n");
for(i=0;i<ctrl[0];i++)
if((oldpos+i>=0) && (oldpos+i<oldsize))
new[newpos+i]+=old[oldpos+i];
newpos+=ctrl[0];
oldpos+=ctrl[0];
if(version==2) {
if(newpos+ctrl[1]>newsize) errx(1,"Corrupt patch\n");
if((lenread=loopread(extrapipe,new+newpos,ctrl[1]))<0)
err(1,NULL);
if(lenread!=ctrl[1]) errx(1,"Corrupt patch\n");
newpos+=ctrl[1];
oldpos+=ctrl[2];
};
};
if(loopread(ctrlpipe,buf,1)!=0) errx(1,"Corrupt patch\n");
if(loopread(diffpipe,buf,1)!=0) errx(1,"Corrupt patch\n");
if(version==2)
if(loopread(extrapipe,buf,1)!=0) errx(1,"Corrupt patch\n");
if(close(ctrlpipe) || close(diffpipe) ||
((version==2) && close(extrapipe)))
err(1,NULL);
for(i=0;i<(version+1)*2;i++) waitpid(pids[i],NULL,0);
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;
}