Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 272 lines (230 sloc) 6.774 kb
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
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
9bc63cc @andymatuschak Merge commit 'bdash/delta-updates'
andymatuschak authored
31 #include <bspatch.h>
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
32 #include <bzlib.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <err.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39
39bb82b @vslavik Don't compress in bsdiff.
vslavik authored
40 /* Compatibility layer for reading either the old BSDIFF40 or the new BSDIFN40
41 patch formats: */
42
43 typedef void* stream_t;
44
45 typedef struct
46 {
47 stream_t (*open)(FILE*);
48 void (*close)(stream_t);
49 int (*read)(stream_t, void*, int);
50 } io_funcs_t;
51
52 static stream_t BSDIFF40_open(FILE *f)
53 {
54 int bzerr;
55 BZFILE *s;
56 if ((s = BZ2_bzReadOpen(&bzerr, f, 0, 0, NULL, 0)) == NULL)
57 errx(1, "BZ2_bzReadOpen, bz2err = %d", bzerr);
58 return s;
59 }
60
61 static void BSDIFF40_close(stream_t s)
62 {
63 int bzerr;
64 BZ2_bzReadClose(&bzerr, (BZFILE*)s);
65 }
66
67 static int BSDIFF40_read(stream_t s, void *buf, int len)
68 {
69 int bzerr, lenread;
70 lenread = BZ2_bzRead(&bzerr, (BZFILE*)s, buf, len);
71 if (bzerr != BZ_OK && bzerr != BZ_STREAM_END)
72 errx(1, "Corrupt patch\n");
73 return lenread;
74 }
75
76 static io_funcs_t BSDIFF40_funcs = {
77 BSDIFF40_open,
78 BSDIFF40_close,
79 BSDIFF40_read
80 };
81
82
83 static stream_t BSDIFN40_open(FILE *f)
84 {
85 return f;
86 }
87
88 static void BSDIFN40_close(stream_t s)
89 {
90 }
91
92 static int BSDIFN40_read(stream_t s, void *buf, int len)
93 {
94 return fread(buf, 1, len, (FILE*)s);
95 }
96
97 static io_funcs_t BSDIFN40_funcs = {
98 BSDIFN40_open,
99 BSDIFN40_close,
100 BSDIFN40_read
101 };
102
103
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
104 #ifndef u_char
105 typedef unsigned char u_char;
106 #endif
107
108 static off_t offtin(u_char *buf)
109 {
110 off_t y;
111
112 y=buf[7]&0x7F;
113 y=y*256;y+=buf[6];
114 y=y*256;y+=buf[5];
115 y=y*256;y+=buf[4];
116 y=y*256;y+=buf[3];
117 y=y*256;y+=buf[2];
118 y=y*256;y+=buf[1];
119 y=y*256;y+=buf[0];
120
121 if(buf[7]&0x80) y=-y;
122
123 return y;
124 }
125
126 int bspatch(int argc,char * argv[])
127 {
128 FILE * f, * cpf, * dpf, * epf;
39bb82b @vslavik Don't compress in bsdiff.
vslavik authored
129 stream_t cstream, dstream, estream;
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
130 int fd;
131 ssize_t oldsize,newsize;
132 ssize_t bzctrllen,bzdatalen;
133 u_char header[32],buf[8];
134 u_char *old, *new;
135 off_t oldpos,newpos;
136 off_t ctrl[3];
137 off_t lenread;
138 off_t i;
39bb82b @vslavik Don't compress in bsdiff.
vslavik authored
139 io_funcs_t * io;
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
140
141 if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);
142
143 /* Open patch file */
144 if ((f = fopen(argv[3], "r")) == NULL)
145 err(1, "fopen(%s)", argv[3]);
146
147 /*
148 File format:
39bb82b @vslavik Don't compress in bsdiff.
vslavik authored
149 0 8 "BSDIFF40" (bzip2) or "BSDIFN40" (raw)
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
150 8 8 X
151 16 8 Y
152 24 8 sizeof(newfile)
153 32 X bzip2(control block)
154 32+X Y bzip2(diff block)
155 32+X+Y ??? bzip2(extra block)
156 with control block a set of triples (x,y,z) meaning "add x bytes
157 from oldfile to x bytes from the diff block; copy y bytes from the
158 extra block; seek forwards in oldfile by z bytes".
159 */
160
161 /* Read header */
162 if (fread(header, 1, 32, f) < 32) {
163 if (feof(f))
164 errx(1, "Corrupt patch\n");
165 err(1, "fread(%s)", argv[3]);
166 }
167
168 /* Check for appropriate magic */
39bb82b @vslavik Don't compress in bsdiff.
vslavik authored
169 if (memcmp(header, "BSDIFF40", 8) == 0)
170 io = &BSDIFF40_funcs;
171 else if (memcmp(header, "BSDIFN40", 8) == 0)
172 io = &BSDIFN40_funcs;
173 else
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
174 errx(1, "Corrupt patch\n");
175
176 /* Read lengths from header */
177 bzctrllen=offtin(header+8);
178 bzdatalen=offtin(header+16);
179 newsize=offtin(header+24);
180 if((bzctrllen<0) || (bzdatalen<0) || (newsize<0))
181 errx(1,"Corrupt patch\n");
182
183 /* Close patch file and re-open it via libbzip2 at the right places */
184 if (fclose(f))
185 err(1, "fclose(%s)", argv[3]);
186 if ((cpf = fopen(argv[3], "r")) == NULL)
187 err(1, "fopen(%s)", argv[3]);
188 if (fseeko(cpf, 32, SEEK_SET))
189 err(1, "fseeko(%s, %lld)", argv[3],
190 (long long)32);
39bb82b @vslavik Don't compress in bsdiff.
vslavik authored
191 cstream = io->open(cpf);
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
192 if ((dpf = fopen(argv[3], "r")) == NULL)
193 err(1, "fopen(%s)", argv[3]);
194 if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))
195 err(1, "fseeko(%s, %lld)", argv[3],
196 (long long)(32 + bzctrllen));
39bb82b @vslavik Don't compress in bsdiff.
vslavik authored
197 dstream = io->open(dpf);
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
198 if ((epf = fopen(argv[3], "r")) == NULL)
199 err(1, "fopen(%s)", argv[3]);
200 if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
201 err(1, "fseeko(%s, %lld)", argv[3],
202 (long long)(32 + bzctrllen + bzdatalen));
39bb82b @vslavik Don't compress in bsdiff.
vslavik authored
203 estream = io->open(epf);
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
204
205 if(((fd=open(argv[1],O_RDONLY,0))<0) ||
206 ((oldsize=lseek(fd,0,SEEK_END))==-1) ||
207 ((old=malloc(oldsize+1))==NULL) ||
208 (lseek(fd,0,SEEK_SET)!=0) ||
209 (read(fd,old,oldsize)!=oldsize) ||
210 (close(fd)==-1)) err(1,"%s",argv[1]);
211 if((new=malloc(newsize+1))==NULL) err(1,NULL);
212
213 oldpos=0;newpos=0;
214 while(newpos<newsize) {
215 /* Read control data */
216 for(i=0;i<=2;i++) {
39bb82b @vslavik Don't compress in bsdiff.
vslavik authored
217 lenread = io->read(cstream, buf, 8);
218 if (lenread < 8)
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
219 errx(1, "Corrupt patch\n");
220 ctrl[i]=offtin(buf);
221 };
222
223 /* Sanity-check */
224 if(newpos+ctrl[0]>newsize)
225 errx(1,"Corrupt patch\n");
226
227 /* Read diff string */
39bb82b @vslavik Don't compress in bsdiff.
vslavik authored
228 lenread = io->read(dstream, new + newpos, ctrl[0]);
229 if (lenread < ctrl[0])
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
230 errx(1, "Corrupt patch\n");
231
232 /* Add old data to diff string */
233 for(i=0;i<ctrl[0];i++)
234 if((oldpos+i>=0) && (oldpos+i<oldsize))
235 new[newpos+i]+=old[oldpos+i];
236
237 /* Adjust pointers */
238 newpos+=ctrl[0];
239 oldpos+=ctrl[0];
240
241 /* Sanity-check */
242 if(newpos+ctrl[1]>newsize)
243 errx(1,"Corrupt patch\n");
244
245 /* Read extra string */
39bb82b @vslavik Don't compress in bsdiff.
vslavik authored
246 lenread = io->read(estream, new + newpos, ctrl[1]);
247 if (lenread < ctrl[1])
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
248 errx(1, "Corrupt patch\n");
249
250 /* Adjust pointers */
251 newpos+=ctrl[1];
252 oldpos+=ctrl[2];
253 };
254
255 /* Clean up the bzip2 reads */
39bb82b @vslavik Don't compress in bsdiff.
vslavik authored
256 io->close(cstream);
257 io->close(dstream);
258 io->close(estream);
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
259 if (fclose(cpf) || fclose(dpf) || fclose(epf))
260 err(1, "fclose(%s)", argv[3]);
261
262 /* Write the new file */
263 if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) ||
264 (write(fd,new,newsize)!=newsize) || (close(fd)==-1))
265 err(1,"%s",argv[2]);
266
267 free(new);
268 free(old);
269
270 return 0;
271 }
Something went wrong with that request. Please try again.