2 * Copyright (c) 2005 Michael Schroeder (mls@suse.de)
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
8 #define _LARGEFILE64_SOURCE
28 unsigned int readiso(FILE *fp, struct rpmpay *pay, int payn, unsigned char **isop)
35 unsigned int l, p, lastl;
42 for (i = 0; i < payn; i++)
46 if (pay[i].l != lastl)
48 fprintf(stderr, "files at same pos with different sizes\n");
53 if (last + lastl > pay[i].o)
55 fprintf(stderr, "files overlap %s %s %lld %d %lld\n", lastn, pay[i].name, (long long int)last, lastl, (long long int)pay[i].o);
63 if (fseeko64(fp, (off64_t)0, SEEK_END) != 0)
71 fprintf(stderr, "size < skipsum\n");
74 if (fseeko64(fp, (off64_t)0, SEEK_SET) != 0)
79 if (size - skipsum >= 0x80000000)
81 fprintf(stderr, "remaining size too big: %lld\n", (long long int)(size - skipsum));
85 if ((iso = malloc(l)) == 0)
87 fprintf(stderr, "out of mem for iso (%d bytes)", l);
94 for (i = 0; i <= payn; i++)
98 if (fread(iso + p, pay[i].o - (last + lastl), 1, fp) != 1)
100 fprintf(stderr, "read error\n");
104 pay[i].lx = pay[i].o - (last + lastl);
105 p += pay[i].o - (last + lastl);
108 if (fseeko64(fp, pay[i].o + pay[i].l, SEEK_SET))
116 fprintf(stderr, "internal error %d %d\n", p, l);
124 recode_instr(struct instr *instr, int instrlen, unsigned int **b1p, int *nb1p, unsigned int **b2p, int *nb2p, struct rpmpay *pay, int payn)
132 unsigned int x1, x2, x3, x4;
140 left = pay && payn ? pay[0].lx : 0;
142 for (i = 0; i < instrlen; i++)
144 x1 = instr[i].copyout;
145 x2 = instr[i].copyin;
146 x3 = instr[i].copyoutoff;
147 x4 = instr[i].copyinoff;
157 b2 = xrealloc2(b2, nb2 + 16, 2 * sizeof(unsigned int));
159 b2[2 * nb2] = x3 - lastoff;
161 b2[2 * nb2] = (lastoff - x3) | 0x80000000;
162 if (left && x1 >= left)
164 b2[2 * nb2 + 1] = left;
167 x3 = lastoff = x3 + left;
170 b1 = xrealloc2(b1, nb1 + 16, 3 * sizeof(unsigned int));
172 b1[3 * nb1 + 1] = 0xffffffff;
173 b1[3 * nb1 + 2] = payp;
177 while (payp < payn && pay[++payp].x == 0)
185 b2[2 * nb2 + 1] = x1;
188 x3 = lastoff = x3 + x1;
195 if (left && x2 >= left)
198 b1 = xrealloc2(b1, nb1 + 16, 3 * sizeof(unsigned int));
200 b1[3 * nb1 + 1] = left;
201 b1[3 * nb1 + 2] = x4;
207 b1 = xrealloc2(b1, nb1 + 16, 3 * sizeof(unsigned int));
209 b1[3 * nb1 + 1] = 0xffffffff;
210 b1[3 * nb1 + 2] = payp;
213 while (payp < payn && pay[++payp].x == 0)
221 b1 = xrealloc2(b1, nb1 + 16, 3 * sizeof(unsigned int));
223 b1[3 * nb1 + 1] = x2;
224 b1[3 * nb1 + 2] = x4;
231 if (left || payp != payn)
233 fprintf(stderr, "oops, left = %d %d %d\n", left, payp, payn);
239 b1 = xrealloc2(b1, nb1 + 16, 3 * sizeof(unsigned int));
252 bzput4(struct cfile *fp, unsigned int d)
259 if (fp->write(fp, dd, 4) != 4)
267 put4(FILE *fp, unsigned int d)
274 if (fwrite(dd, 4, 1, fp) != 1)
281 void diffit(struct cfile *fpout, FILE *fpold, FILE *fpnew, unsigned char *old, unsigned int oldl, unsigned char *new, int newl, struct rpmpay *newpays, int newpayn, struct rpmpay *oldpays, int oldpayn, MD5_CTX *ctx);
283 unsigned int payread(FILE *fp, off64_t off, unsigned int len, unsigned char **pp, MD5_CTX *ctx, unsigned char *namebuf)
288 if (fseeko64(fp, off, SEEK_SET) != 0)
293 cfile = cfile_open(CFILE_OPEN_RD, CFILE_IO_FILE, fp, CFILE_COMP_XX, len, ctx ? (cfile_ctxup)rpmMD5Update : 0, ctx);
296 fprintf(stderr, "cfile open failed\n");
301 cfile_detect_rsync(cfile);
302 namebuf[0] = cfile->comp;
304 l = cfile_copy(cfile, cfile_open(CFILE_OPEN_WR, CFILE_IO_ALLOC, pp, CFILE_COMP_UN, CFILE_LEN_UNLIMITED, 0, 0), CFILE_COPY_CLOSE_OUT);
307 fprintf(stderr, "cfile_copy failed\n");
310 r = cfile->close(cfile);
313 fprintf(stderr, "cfile not used up (%d bytes left)\n", r);
320 processrpm(struct cfile *fpout, FILE *fpold, FILE *fpnew, struct rpmpay *pay, struct rpmpay *oldpays, int oldpayn, MD5_CTX *ctx)
322 struct rpmpay *oldpay;
324 unsigned int l, newl, oldl;
325 unsigned char *new, *old;
326 unsigned char namebuf[258];
329 for (i = 0; i < oldpayn; i++)
330 if (!strcmp(oldpays[i].name, pay->name))
332 oldpay = oldpays + i;
335 l = strlen(pay->name);
340 memcpy(namebuf + 2, pay->name, l);
342 targetsize += pay->l;
345 printf("%s: not found in old iso...", pay->name);
346 if (fpout->write(fpout, namebuf, l + 2) != l + 2)
348 perror("namebuf write");
351 bzput4(fpout, pay->l);
352 if (fseeko64(fpnew, pay->o, SEEK_SET) != 0)
357 if (cfile_copy(cfile_open(CFILE_OPEN_RD, CFILE_IO_FILE, fpnew, CFILE_COMP_UN, pay->l, (cfile_ctxup)rpmMD5Update, ctx), fpout, CFILE_COPY_CLOSE_IN) != 0)
359 fprintf(stderr, "cfile_copy failed\n");
366 for (i = 0; i < oldpayn; i++)
367 if (i == 0 || oldpays[i].x != 0)
369 if (oldpays[i].o == oldpay->o)
376 fprintf(stderr, "internal error\n");
379 if (oldpay->l != oldpays[i].l)
381 fprintf(stderr, "internal error, length mismatch %d %d\n", oldpay->l, oldpays[i].l);
384 /* payread will fix namebuf[0] */
385 newl = payread(fpnew, pay->o, pay->l, &new, ctx, namebuf);
386 oldl = payread(fpold, oldpay->o, oldpay->l, &old, 0, 0);
387 if (newl == oldl && pay->l == oldpay->l && !memcmp(new, old, newl))
389 printf("%s: unchanged...", namebuf + 2);
394 int comp = cfile_setlevel(namebuf[0], pay->level);
395 printf("%s (%s): creating delta...", namebuf + 2, cfile_comp2str(comp));
396 namebuf[0] = CFILE_COMPALGO(comp) | (CFILE_COMPLEVEL(comp) << 4); /* argh! */
399 if (fpout->write(fpout, namebuf, l + 2) != l + 2)
401 perror("namebuf write");
404 bzput4(fpout, n); /* offset id */
405 if (namebuf[0] == 254)
408 diffit(fpout, 0, 0, old, oldl, new, newl, 0, 0, 0, 0, 0);
415 writtensize += fpout->bytes;
417 printf("%4.1f%%\n", writtensize * 100 / targetsize);
421 void diffit(struct cfile *fpout, FILE *fpold, FILE *fpnew, unsigned char *old, unsigned int oldl, unsigned char *new, int newl, struct rpmpay *newpays, int newpayn, struct rpmpay *oldpays, int oldpayn, MD5_CTX *ctx)
427 struct instr *instr = 0;
429 unsigned char *addblk = 0;
430 unsigned int addblklen = 0;
434 mkdiff(DELTAMODE_HASH, old, oldl, new, newl, &instr, &instrlen, 0, 0, &addblk, &addblklen, 0, 0);
437 recode_instr(instr, instrlen, &b1, &nb1, &b2, &nb2, newpays, newpayn);
445 for (i = 0; i < nb1; i++)
446 bzput4(fpout, b1[3 * i]);
447 for (i = 0; i < nb1; i++)
448 bzput4(fpout, b1[3 * i + 1]);
449 for (i = 0; i < nb2; i++)
450 bzput4(fpout, b2[2 * i]);
451 for (i = 0; i < nb2; i++)
452 bzput4(fpout, b2[2 * i + 1]);
454 /* write add section */
455 bzput4(fpout, addblklen);
456 if (addblklen && fpout->write(fpout, addblk, addblklen) != addblklen)
464 /* write data section */
467 for (i = 0; i < nb1; i++)
471 for (j = 0; j < b1[3 * i]; j++, b2i++)
474 rpmMD5Update(ctx, new + off, b2[2 * b2i + 1]);
475 off += b2[2 * b2i + 1];
478 if (b1[3 * i + 1] == 0xffffffff)
480 processrpm(fpout, fpold, fpnew, newpays + b1[3 * i + 2], oldpays, oldpayn, ctx);
482 else if (b1[3 * i + 1])
486 if (off != b1[3 * i + 2])
488 fprintf(stderr, "internal error: off mismatch %d %d\n", off, b1[3 * i + 2]);
491 rpmMD5Update(ctx, new + off, b1[3 * i + 1]);
492 off += b1[3 * i + 1];
494 if (fpout->write(fpout, new + b1[3 * i + 2], b1[3 * i + 1]) != b1[3 * i + 1])
506 main(int argc, char **argv)
508 FILE *fpold, *fpnew, *fpout;
509 unsigned int oldisolen;
510 unsigned int newisolen;
511 unsigned char *oldiso;
512 unsigned char *newiso;
513 struct rpmpay *oldpays = 0;
515 struct rpmpay *newpays = 0;
520 unsigned char targetmd5res[16];
524 fprintf(stderr, "usage: makedeltaiso <oldiso> <newiso> <deltaiso>\n");
527 if ((fpold = fopen64(argv[1], "r")) == 0)
532 if ((fpnew = fopen64(argv[2], "r")) == 0)
537 oldpayn = rpmoffs(fpold, argv[1], &oldpays);
538 printf("%s: %d rpms\n", argv[1], oldpayn);
539 newpayn = rpmoffs(fpnew, argv[2], &newpays);
540 printf("%s: %d rpms\n", argv[2], newpayn);
541 if ((fpout = fopen64(argv[3], "w")) == 0)
546 printf("reading old iso (omitting payloads)\n");
547 oldisolen = readiso(fpold, oldpays, oldpayn, &oldiso);
548 printf("size without payloads is %d bytes\n", oldisolen);
549 printf("reading new iso (omitting payloads)\n");
550 newisolen = readiso(fpnew, newpays, newpayn, &newiso);
551 printf("size without payloads is %d bytes\n", newisolen);
552 targetsize = newisolen;
559 if ((bf = cfile_open(CFILE_OPEN_WR, CFILE_IO_FILE, fpout, CFILE_COMP_BZ, CFILE_LEN_UNLIMITED, 0, 0)) == 0)
561 fprintf(stderr, "cfile wopen failed\n");
566 for (i = 0; i < oldpayn; i++)
567 if (i == 0 || oldpays[i].x)
570 for (i = 0; i < oldpayn; i++)
571 if (i == 0 || oldpays[i].x)
573 bzput4(bf, oldpays[i].lx);
574 bzput4(bf, oldpays[i].l);
576 bzput4(bf, oldpays[i].lx);
578 printf("creating iso diff\n");
579 rpmMD5Init(&targetmd5);
580 diffit(bf, fpold, fpnew, oldiso, oldisolen, newiso, newisolen, newpays, newpayn, oldpays, oldpayn, &targetmd5);
581 rpmMD5Final(targetmd5res, &targetmd5);
587 writtensize += bf->bytes;
589 printf("iso diff done, final compression: %4.1f%%\n", writtensize * 100 / targetsize);
590 if (bf->write(bf, targetmd5res, 16) != 16)
592 perror("md5sum write");
595 if (bf->close(bf) == -1)
597 perror("cfile close");
605 printf("iso md5sum is: ");
606 for (i = 0; i < 16; i++)
607 printf("%02x", targetmd5res[i]);
609 for (i = 0; i < oldpayn; i++)
610 free(oldpays[i].name);
612 for (i = 0; i < newpayn; i++)
613 free(newpays[i].name);