OLD | NEW |
1 /*- | 1 /*- |
2 * Copyright 2003-2005 Colin Percival | 2 * Copyright 2003-2005 Colin Percival |
3 * All rights reserved | 3 * All rights reserved |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted providing that the following conditions | 6 * modification, are permitted providing that the following conditions |
7 * are met: | 7 * are met: |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 15 matching lines...) Expand all Loading... |
26 | 26 |
27 #if 0 | 27 #if 0 |
28 __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bsdiff/bsdiff.c,v 1.1 2005/08/06 01:59:05
cperciva Exp $"); | 28 __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bsdiff/bsdiff.c,v 1.1 2005/08/06 01:59:05
cperciva Exp $"); |
29 #endif | 29 #endif |
30 | 30 |
31 #include <sys/types.h> | 31 #include <sys/types.h> |
32 | 32 |
33 #include <bzlib.h> | 33 #include <bzlib.h> |
34 #include <err.h> | 34 #include <err.h> |
35 #include <fcntl.h> | 35 #include <fcntl.h> |
| 36 #include <openssl/sha.h> |
36 #include <stdio.h> | 37 #include <stdio.h> |
37 #include <stdlib.h> | 38 #include <stdlib.h> |
38 #include <string.h> | 39 #include <string.h> |
39 #include <unistd.h> | 40 #include <unistd.h> |
| 41 #include <zlib.h> |
| 42 |
| 43 #if defined(__APPLE__) |
| 44 #include <libkern/OSByteOrder.h> |
| 45 #define htole64(x) OSSwapHostToLittleInt64(x) |
| 46 #elif defined(__linux__) |
| 47 #include <endian.h> |
| 48 #elif defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64)) |
| 49 #define htole64(x) (x) |
| 50 #else |
| 51 #error Provide htole64 for this platform |
| 52 #endif |
40 | 53 |
41 #define MIN(x,y) (((x)<(y)) ? (x) : (y)) | 54 #define MIN(x,y) (((x)<(y)) ? (x) : (y)) |
42 | 55 |
43 static void split(off_t *I,off_t *V,off_t start,off_t len,off_t h) | 56 static void split(off_t *I,off_t *V,off_t start,off_t len,off_t h) |
44 { | 57 { |
45 off_t i,j,k,x,tmp,jj,kk; | 58 off_t i,j,k,x,tmp,jj,kk; |
46 | 59 |
47 if(len<16) { | 60 if(len<16) { |
48 for(k=start;k<start+len;k+=j) { | 61 for(k=start;k<start+len;k+=j) { |
49 j=1;x=V[I[k]+h]; | 62 j=1;x=V[I[k]+h]; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 }; | 181 }; |
169 | 182 |
170 x=st+(en-st)/2; | 183 x=st+(en-st)/2; |
171 if(memcmp(old+I[x],new,MIN(oldsize-I[x],newsize))<0) { | 184 if(memcmp(old+I[x],new,MIN(oldsize-I[x],newsize))<0) { |
172 return search(I,old,oldsize,new,newsize,x,en,pos); | 185 return search(I,old,oldsize,new,newsize,x,en,pos); |
173 } else { | 186 } else { |
174 return search(I,old,oldsize,new,newsize,st,x,pos); | 187 return search(I,old,oldsize,new,newsize,st,x,pos); |
175 }; | 188 }; |
176 } | 189 } |
177 | 190 |
178 static void offtout(off_t x,u_char *buf) | 191 static inline void offtout(off_t x,u_char *buf) |
179 { | 192 { |
180 » off_t y; | 193 » *((off_t*)buf) = htole64(x); |
| 194 } |
181 | 195 |
182 » if(x<0) y=-x; else y=x; | 196 /* zlib provides compress2, which deflates to deflate (zlib) format. This is |
| 197 * unfortunately distinct from gzip format in that the headers wrapping the |
| 198 * decompressed data are different. gbspatch reads gzip-compressed data using |
| 199 * the file-oriented gzread interface, which only supports gzip format. |
| 200 * compress2gzip is identical to zlib's compress2 except that it produces gzip |
| 201 * output compatible with gzread. This change is achieved by calling |
| 202 * deflateInit2 instead of deflateInit and specifying 31 for windowBits; |
| 203 * numbers greater than 15 cause the addition of a gzip wrapper. */ |
| 204 static int compress2gzip(Bytef *dest, uLongf *destLen, |
| 205 const Bytef *source, uLong sourceLen, int level) |
| 206 { |
| 207 » z_stream stream; |
| 208 » int err; |
183 | 209 |
184 » » buf[0]=y%256;y-=buf[0]; | 210 » stream.next_in = (Bytef*)source; |
185 » y=y/256;buf[1]=y%256;y-=buf[1]; | 211 » stream.avail_in = (uInt)sourceLen; |
186 » y=y/256;buf[2]=y%256;y-=buf[2]; | |
187 » y=y/256;buf[3]=y%256;y-=buf[3]; | |
188 » y=y/256;buf[4]=y%256;y-=buf[4]; | |
189 » y=y/256;buf[5]=y%256;y-=buf[5]; | |
190 » y=y/256;buf[6]=y%256;y-=buf[6]; | |
191 » y=y/256;buf[7]=y%256; | |
192 | 212 |
193 » if(x<0) buf[7]|=0x80; | 213 » stream.next_out = dest; |
| 214 » stream.avail_out = (uInt)*destLen; |
| 215 » if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; |
| 216 |
| 217 » stream.zalloc = (alloc_func)0; |
| 218 » stream.zfree = (free_func)0; |
| 219 » stream.opaque = (voidpf)0; |
| 220 |
| 221 » err = deflateInit2(&stream, |
| 222 » level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY); |
| 223 » if (err != Z_OK) return err; |
| 224 |
| 225 » err = deflate(&stream, Z_FINISH); |
| 226 » if (err != Z_STREAM_END) { |
| 227 » » deflateEnd(&stream); |
| 228 » » return err == Z_OK ? Z_BUF_ERROR : err; |
| 229 » } |
| 230 » *destLen = stream.total_out; |
| 231 |
| 232 » err = deflateEnd(&stream); |
| 233 » return err; |
| 234 } |
| 235 |
| 236 /* Recompress buf of size buf_len using bzip2 or gzip. The smallest version is |
| 237 * used. The original uncompressed variant may be the smallest. Returns a |
| 238 * number identifying the encoding, 1 for uncompressed, 2 for bzip2, and 3 for |
| 239 * gzip. If the original uncompressed variant is not smallest, it is freed. |
| 240 * The caller must free any buf after this function returns. */ |
| 241 static char make_small(u_char **buf, off_t *buf_len) |
| 242 { |
| 243 » u_char *source = *buf; |
| 244 » off_t source_len = *buf_len; |
| 245 » u_char *bz2, *gz; |
| 246 » unsigned int bz2_len; |
| 247 » unsigned long gz_len; |
| 248 » int zerr; |
| 249 » char smallest; |
| 250 |
| 251 » smallest = 1; |
| 252 |
| 253 » bz2_len = source_len + 1; |
| 254 » bz2 = malloc(bz2_len); |
| 255 » zerr = BZ2_bzBuffToBuffCompress((char*)bz2, &bz2_len, (char*)source, |
| 256 » source_len, 9, 0, 0); |
| 257 » if (zerr == BZ_OK) { |
| 258 » » if (bz2_len < *buf_len) { |
| 259 » » » smallest = 2; |
| 260 » » » *buf = bz2; |
| 261 » » » *buf_len = bz2_len; |
| 262 » » } else { |
| 263 » » » free(bz2); |
| 264 » » » bz2 = NULL; |
| 265 » » } |
| 266 » } else if (zerr == BZ_OUTBUFF_FULL) { |
| 267 » » free(bz2); |
| 268 » » bz2 = NULL; |
| 269 » } else { |
| 270 » » errx(1, "BZ2_bzBuffToBuffCompress: %d", zerr); |
| 271 » } |
| 272 |
| 273 » gz_len = source_len + 1; |
| 274 » gz = malloc(gz_len); |
| 275 » zerr = compress2gzip(gz, &gz_len, source, source_len, 9); |
| 276 » if (zerr == Z_OK) { |
| 277 » » if (gz_len < *buf_len) { |
| 278 » » » smallest = 3; |
| 279 » » » *buf = gz; |
| 280 » » » *buf_len = gz_len; |
| 281 » » } else { |
| 282 » » » free(gz); |
| 283 » » » gz = NULL; |
| 284 » » } |
| 285 » } else if (zerr == Z_BUF_ERROR) { |
| 286 » » free(gz); |
| 287 » » gz = NULL; |
| 288 » } else { |
| 289 » » errx(1, "compress2gzip: %d", zerr); |
| 290 » } |
| 291 |
| 292 » if (smallest != 1) { |
| 293 » » free(source); |
| 294 » } |
| 295 |
| 296 » return smallest; |
194 } | 297 } |
195 | 298 |
196 int main(int argc,char *argv[]) | 299 int main(int argc,char *argv[]) |
197 { | 300 { |
198 int fd; | 301 int fd; |
199 u_char *old,*new; | 302 u_char *old,*new; |
200 off_t oldsize,newsize; | 303 off_t oldsize,newsize; |
201 off_t *I,*V; | 304 off_t *I,*V; |
202 off_t scan,pos,len; | 305 off_t scan,pos,len; |
203 off_t lastscan,lastpos,lastoffset; | 306 off_t lastscan,lastpos,lastoffset; |
204 off_t oldscore,scsc; | 307 off_t oldscore,scsc; |
205 off_t s,Sf,lenf,Sb,lenb; | 308 off_t s,Sf,lenf,Sb,lenb; |
206 off_t overlap,Ss,lens; | 309 off_t overlap,Ss,lens; |
207 off_t i; | 310 off_t i; |
208 » off_t dblen,eblen; | 311 » off_t cblen, dblen, eblen; |
209 » u_char *db,*eb; | 312 » u_char *cb, *db, *eb; |
210 » u_char buf[8]; | 313 » u_char header[96]; |
211 » u_char header[32]; | |
212 FILE * pf; | 314 FILE * pf; |
213 BZFILE * pfbz2; | |
214 int bz2err; | |
215 | 315 |
216 » if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); | 316 » if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile",argv[0]); |
217 | 317 |
218 /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure | 318 /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure |
219 that we never try to malloc(0) and get a NULL pointer */ | 319 that we never try to malloc(0) and get a NULL pointer */ |
220 if(((fd=open(argv[1],O_RDONLY,0))<0) || | 320 if(((fd=open(argv[1],O_RDONLY,0))<0) || |
221 ((oldsize=lseek(fd,0,SEEK_END))==-1) || | 321 ((oldsize=lseek(fd,0,SEEK_END))==-1) || |
222 ((old=malloc(oldsize+1))==NULL) || | 322 ((old=malloc(oldsize+1))==NULL) || |
223 (lseek(fd,0,SEEK_SET)!=0) || | 323 (lseek(fd,0,SEEK_SET)!=0) || |
224 (read(fd,old,oldsize)!=oldsize) || | 324 (read(fd,old,oldsize)!=oldsize) || |
225 (close(fd)==-1)) err(1,"%s",argv[1]); | 325 (close(fd)==-1)) err(1,"%s",argv[1]); |
226 | 326 |
227 if(((I=malloc((oldsize+1)*sizeof(off_t)))==NULL) || | 327 if(((I=malloc((oldsize+1)*sizeof(off_t)))==NULL) || |
228 ((V=malloc((oldsize+1)*sizeof(off_t)))==NULL)) err(1,NULL); | 328 ((V=malloc((oldsize+1)*sizeof(off_t)))==NULL)) err(1,NULL); |
229 | 329 |
230 qsufsort(I,V,old,oldsize); | 330 qsufsort(I,V,old,oldsize); |
231 | 331 |
232 free(V); | 332 free(V); |
233 | 333 |
234 /* Allocate newsize+1 bytes instead of newsize bytes to ensure | 334 /* Allocate newsize+1 bytes instead of newsize bytes to ensure |
235 that we never try to malloc(0) and get a NULL pointer */ | 335 that we never try to malloc(0) and get a NULL pointer */ |
236 if(((fd=open(argv[2],O_RDONLY,0))<0) || | 336 if(((fd=open(argv[2],O_RDONLY,0))<0) || |
237 ((newsize=lseek(fd,0,SEEK_END))==-1) || | 337 ((newsize=lseek(fd,0,SEEK_END))==-1) || |
238 ((new=malloc(newsize+1))==NULL) || | 338 ((new=malloc(newsize+1))==NULL) || |
239 (lseek(fd,0,SEEK_SET)!=0) || | 339 (lseek(fd,0,SEEK_SET)!=0) || |
240 (read(fd,new,newsize)!=newsize) || | 340 (read(fd,new,newsize)!=newsize) || |
241 (close(fd)==-1)) err(1,"%s",argv[2]); | 341 (close(fd)==-1)) err(1,"%s",argv[2]); |
242 | 342 |
243 » if(((db=malloc(newsize+1))==NULL) || | 343 » if(((cb=malloc(newsize+1))==NULL) || |
| 344 » » ((db=malloc(newsize+1))==NULL) || |
244 ((eb=malloc(newsize+1))==NULL)) err(1,NULL); | 345 ((eb=malloc(newsize+1))==NULL)) err(1,NULL); |
| 346 cblen=0; |
245 dblen=0; | 347 dblen=0; |
246 eblen=0; | 348 eblen=0; |
247 | 349 |
248 /* Create the patch file */ | 350 /* Create the patch file */ |
249 » if ((pf = fopen(argv[3], "w")) == NULL) | 351 » if ((pf = fopen(argv[3], "wb")) == NULL) |
250 err(1, "%s", argv[3]); | 352 err(1, "%s", argv[3]); |
251 | 353 |
252 » /* Header is | 354 » /* File format: |
253 » » 0» 8» "BSDIFF40" | 355 » » 0» 8» "BSDIFF4G" |
254 » » 8» 8» length of bzip2ed ctrl block | 356 » » 8» 8» length of compressed control block (x) |
255 » » 16» 8» length of bzip2ed diff block | 357 » » 16» 8» length of compressed diff block (y) |
256 » » 24» 8» length of new file */ | 358 » » 24» 8» length of compressed extra block (z) |
257 » /* File is | 359 » » 32» 8» length of old file |
258 » » 0» 32» Header | 360 » » 40» 8» length of new file |
259 » » 32» ??» Bzip2ed ctrl block | 361 » » 48» 20» SHA1 of old file |
260 » » ??» ??» Bzip2ed diff block | 362 » » 68» 20» SHA1 of new file |
261 » » ??» ??» Bzip2ed extra block */ | 363 » » 88» 1» encoding of control block |
262 » memcpy(header,"BSDIFF40",8); | 364 » » 89» 1» encoding of diff block |
263 » offtout(0, header + 8); | 365 » » 90» 1» encoding of extra block |
264 » offtout(0, header + 16); | 366 » » 91» 5» unused |
265 » offtout(newsize, header + 24); | 367 » » 96» x» compressed control block |
266 » if (fwrite(header, 32, 1, pf) != 1) | 368 » » 96+x» y» compressed diff block |
| 369 » » 96+x+y» z» compressed extra block |
| 370 » Encodings are 1 (uncompressed), 2 (bzip2), and 3 (gzip). */ |
| 371 » memset(header, 0, sizeof(header)); |
| 372 » if (fwrite(header, sizeof(header), 1, pf) != 1) |
267 err(1, "fwrite(%s)", argv[3]); | 373 err(1, "fwrite(%s)", argv[3]); |
| 374 memcpy(header, "BSDIFF4G", 8); |
| 375 offtout(oldsize, header + 32); |
| 376 offtout(newsize, header + 40); |
| 377 SHA1(old, oldsize, header + 48); |
| 378 SHA1(new, newsize, header + 68); |
268 | 379 |
269 » /* Compute the differences, writing ctrl as we go */ | 380 » /* Compute the differences */ |
270 » if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL) | |
271 » » errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err); | |
272 scan=0;len=0; | 381 scan=0;len=0; |
273 lastscan=0;lastpos=0;lastoffset=0; | 382 lastscan=0;lastpos=0;lastoffset=0; |
274 while(scan<newsize) { | 383 while(scan<newsize) { |
275 oldscore=0; | 384 oldscore=0; |
276 | 385 |
277 for(scsc=scan+=len;scan<newsize;scan++) { | 386 for(scsc=scan+=len;scan<newsize;scan++) { |
278 len=search(I,old,oldsize,new+scan,newsize-scan, | 387 len=search(I,old,oldsize,new+scan,newsize-scan, |
279 0,oldsize,&pos); | 388 0,oldsize,&pos); |
280 | 389 |
281 for(;scsc<scan+len;scsc++) | 390 for(;scsc<scan+len;scsc++) |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 }; | 433 }; |
325 | 434 |
326 for(i=0;i<lenf;i++) | 435 for(i=0;i<lenf;i++) |
327 db[dblen+i]=new[lastscan+i]-old[lastpos+i]; | 436 db[dblen+i]=new[lastscan+i]-old[lastpos+i]; |
328 for(i=0;i<(scan-lenb)-(lastscan+lenf);i++) | 437 for(i=0;i<(scan-lenb)-(lastscan+lenf);i++) |
329 eb[eblen+i]=new[lastscan+lenf+i]; | 438 eb[eblen+i]=new[lastscan+lenf+i]; |
330 | 439 |
331 dblen+=lenf; | 440 dblen+=lenf; |
332 eblen+=(scan-lenb)-(lastscan+lenf); | 441 eblen+=(scan-lenb)-(lastscan+lenf); |
333 | 442 |
334 » » » offtout(lenf,buf); | 443 » » » offtout(lenf, cb + cblen); |
335 » » » BZ2_bzWrite(&bz2err, pfbz2, buf, 8); | 444 » » » cblen += 8; |
336 » » » if (bz2err != BZ_OK) | |
337 » » » » errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); | |
338 | 445 |
339 » » » offtout((scan-lenb)-(lastscan+lenf),buf); | 446 » » » offtout((scan - lenb) - (lastscan + lenf), cb + cblen); |
340 » » » BZ2_bzWrite(&bz2err, pfbz2, buf, 8); | 447 » » » cblen += 8; |
341 » » » if (bz2err != BZ_OK) | |
342 » » » » errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); | |
343 | 448 |
344 » » » offtout((pos-lenb)-(lastpos+lenf),buf); | 449 » » » offtout((pos - lenb) - (lastpos + lenf), cb + cblen); |
345 » » » BZ2_bzWrite(&bz2err, pfbz2, buf, 8); | 450 » » » cblen += 8; |
346 » » » if (bz2err != BZ_OK) | |
347 » » » » errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); | |
348 | 451 |
349 lastscan=scan-lenb; | 452 lastscan=scan-lenb; |
350 lastpos=pos-lenb; | 453 lastpos=pos-lenb; |
351 lastoffset=pos-scan; | 454 lastoffset=pos-scan; |
352 }; | 455 }; |
353 }; | 456 }; |
354 BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL); | |
355 if (bz2err != BZ_OK) | |
356 errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err); | |
357 | 457 |
358 » /* Compute size of compressed ctrl data */ | 458 » header[88] = make_small(&cb, &cblen); |
359 » if ((len = ftello(pf)) == -1) | 459 » header[89] = make_small(&db, &dblen); |
360 » » err(1, "ftello"); | 460 » header[90] = make_small(&eb, &eblen); |
361 » offtout(len-32, header + 8); | |
362 | 461 |
363 » /* Write compressed diff data */ | 462 » if (fwrite(cb, 1, cblen, pf) != cblen) |
364 » if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL) | 463 » » err(1, "fwrite"); |
365 » » errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err); | 464 » if (fwrite(db, 1, dblen, pf) != dblen) |
366 » BZ2_bzWrite(&bz2err, pfbz2, db, dblen); | 465 » » err(1, "fwrite"); |
367 » if (bz2err != BZ_OK) | 466 » if (fwrite(eb, 1, eblen, pf) != eblen) |
368 » » errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); | 467 » » err(1, "fwrite"); |
369 » BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL); | |
370 » if (bz2err != BZ_OK) | |
371 » » errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err); | |
372 | 468 |
373 » /* Compute size of compressed diff data */ | 469 » offtout(cblen, header + 8); |
374 » if ((newsize = ftello(pf)) == -1) | 470 » offtout(dblen, header + 16); |
375 » » err(1, "ftello"); | 471 » offtout(eblen, header + 24); |
376 » offtout(newsize - len, header + 16); | |
377 | |
378 » /* Write compressed extra data */ | |
379 » if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL) | |
380 » » errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err); | |
381 » BZ2_bzWrite(&bz2err, pfbz2, eb, eblen); | |
382 » if (bz2err != BZ_OK) | |
383 » » errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); | |
384 » BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL); | |
385 » if (bz2err != BZ_OK) | |
386 » » errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err); | |
387 | 472 |
388 /* Seek to the beginning, write the header, and close the file */ | 473 /* Seek to the beginning, write the header, and close the file */ |
389 if (fseeko(pf, 0, SEEK_SET)) | 474 if (fseeko(pf, 0, SEEK_SET)) |
390 err(1, "fseeko"); | 475 err(1, "fseeko"); |
391 » if (fwrite(header, 32, 1, pf) != 1) | 476 » if (fwrite(header, sizeof(header), 1, pf) != 1) |
392 err(1, "fwrite(%s)", argv[3]); | 477 err(1, "fwrite(%s)", argv[3]); |
393 if (fclose(pf)) | 478 if (fclose(pf)) |
394 err(1, "fclose"); | 479 err(1, "fclose"); |
395 | 480 |
396 /* Free the memory we used */ | 481 /* Free the memory we used */ |
| 482 free(cb); |
397 free(db); | 483 free(db); |
398 free(eb); | 484 free(eb); |
399 free(I); | 485 free(I); |
400 free(old); | 486 free(old); |
401 free(new); | 487 free(new); |
402 | 488 |
403 return 0; | 489 return 0; |
404 } | 490 } |
OLD | NEW |