resetting manifest requested domain to floor
[platform/upstream/deltarpm.git] / makedeltaiso.c
1 /*
2  * Copyright (c) 2005 Michael Schroeder (mls@suse.de)
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 #define _LARGEFILE64_SOURCE
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <stdint.h>
14
15 #include <zlib.h>
16 #include <bzlib.h>
17 #include <lzma.h>
18
19 #include "rpmoffs.h"
20 #include "delta.h"
21 #include "util.h"
22 #include "md5.h"
23 #include "cfile.h"
24
25 double targetsize;
26 double writtensize;
27
28 unsigned int readiso(FILE *fp, struct rpmpay *pay, int payn, unsigned char **isop)
29 {
30   off64_t size;
31   off64_t skipsum;
32   off64_t last;
33   int i;
34   unsigned char *iso;
35   unsigned int l, p, lastl;
36   char *lastn;
37
38   last = 0;
39   lastl = 0;
40   skipsum = 0;
41   lastn = "<start>";
42   for (i = 0; i < payn; i++)
43     {
44       if (pay[i].o == last)
45         {
46           if (pay[i].l != lastl)
47             {
48               fprintf(stderr, "files at same pos with different sizes\n");
49               exit(1);
50             }
51           continue;
52         }
53       if (last + lastl > pay[i].o)
54         {
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);
56           exit(1);
57         }
58       last = pay[i].o;
59       lastl = pay[i].l;
60       lastn = pay[i].name;
61       skipsum += pay[i].l;
62     }
63   if (fseeko64(fp, (off64_t)0, SEEK_END) != 0)
64     {
65       perror("fseeko64");
66       exit(1);
67     }
68   size = ftello64(fp);
69   if (size < skipsum)
70     {
71       fprintf(stderr, "size < skipsum\n");
72       exit(1);
73     }
74   if (fseeko64(fp, (off64_t)0, SEEK_SET) != 0)
75     {
76       perror("fseeko64");
77       exit(1);
78     }
79   if (size - skipsum >= 0x80000000)
80     {
81       fprintf(stderr, "remaining size too big: %lld\n", (long long int)(size - skipsum));
82       exit(1);
83     }
84   l = size - skipsum;
85   if ((iso = malloc(l)) == 0)
86     {
87       fprintf(stderr, "out of mem for iso (%d bytes)", l);
88       exit(1);
89     }
90   last = 0;
91   lastl = 0;
92   p = 0;
93   pay[payn].o = size;
94   for (i = 0; i <= payn; i++)
95     {
96       if (pay[i].o == last)
97         continue;
98       if (fread(iso + p, pay[i].o - (last + lastl), 1, fp) != 1)
99         {
100           fprintf(stderr, "read error\n");
101           exit(1);
102         }
103       pay[i].x = p;
104       pay[i].lx = pay[i].o - (last + lastl);
105       p += pay[i].o - (last + lastl);
106       last = pay[i].o;
107       lastl = pay[i].l;
108       if (fseeko64(fp, pay[i].o + pay[i].l, SEEK_SET))
109         {
110           perror("fseeko64");
111           exit(1);
112         }
113     }
114   if (p != l)
115     {
116       fprintf(stderr, "internal error %d %d\n", p, l);
117       exit(1);
118     }
119   *isop = iso;
120   return l;
121 }
122
123 void
124 recode_instr(struct instr *instr, int instrlen, unsigned int **b1p, int *nb1p, unsigned int **b2p, int *nb2p, struct rpmpay *pay, int payn)
125 {
126   unsigned int *b1;
127   int nb1;
128   unsigned int *b2;
129   int nb2;
130   int i, j;
131   int lastoff;
132   unsigned int x1, x2, x3, x4;
133   unsigned int left;
134   int payp;
135
136   b1 = b2 = 0; 
137   nb1 = nb2 = 0;
138   j = 0;  
139   lastoff = 0;
140   left = pay && payn ? pay[0].lx : 0;
141   payp = 0;
142   for (i = 0; i < instrlen; i++)
143     {
144       x1 = instr[i].copyout;
145       x2 = instr[i].copyin;
146       x3 = instr[i].copyoutoff;
147       x4 = instr[i].copyinoff;
148 retry:
149       if (!x1)
150         {
151           if (!x2)
152             continue;
153         }
154       if (x1)
155         {
156           if ((nb2 & 15) == 0)
157             b2 = xrealloc2(b2, nb2 + 16, 2 * sizeof(unsigned int));
158           if (lastoff <= x3)
159             b2[2 * nb2] = x3 - lastoff;
160           else
161             b2[2 * nb2] = (lastoff - x3) | 0x80000000;
162           if (left && x1 >= left)
163             {
164               b2[2 * nb2 + 1] = left;
165               nb2++;
166               j++;
167               x3 = lastoff = x3 + left;
168               x1 -= left;
169               if ((nb1 & 15) == 0)
170                 b1 = xrealloc2(b1, nb1 + 16, 3 * sizeof(unsigned int));
171               b1[3 * nb1] = j;
172               b1[3 * nb1 + 1] = 0xffffffff;
173               b1[3 * nb1 + 2] = payp;
174               nb1++;
175               j = 0;
176               left = 0;
177               while (payp < payn && pay[++payp].x == 0)
178                 ;
179               if (payp < payn)
180                 left = pay[payp].lx;
181               goto retry;
182             }
183           else
184             {
185               b2[2 * nb2 + 1] = x1;
186               nb2++;
187               j++;
188               x3 = lastoff = x3 + x1;
189               if (left)
190                 left -= x1;
191             }
192         }
193       if (x2)
194         {
195           if (left && x2 >= left)
196             {
197               if ((nb1 & 15) == 0)
198                 b1 = xrealloc2(b1, nb1 + 16, 3 * sizeof(unsigned int));
199               b1[3 * nb1] = j;
200               b1[3 * nb1 + 1] = left;
201               b1[3 * nb1 + 2] = x4;
202               nb1++;
203               j = 0;
204               x2 -= left;
205               x4 += left;
206               if ((nb1 & 15) == 0)
207                 b1 = xrealloc2(b1, nb1 + 16, 3 * sizeof(unsigned int));
208               b1[3 * nb1] = 0;
209               b1[3 * nb1 + 1] = 0xffffffff;
210               b1[3 * nb1 + 2] = payp;
211               nb1++;
212               left = 0;
213               while (payp < payn && pay[++payp].x == 0)
214                 ;
215               if (payp < payn)
216                 left = pay[payp].lx;
217               x1 = 0;
218               goto retry;
219             }
220           if ((nb1 & 15) == 0)
221             b1 = xrealloc2(b1, nb1 + 16, 3 * sizeof(unsigned int));
222           b1[3 * nb1] = j;
223           b1[3 * nb1 + 1] = x2;
224           b1[3 * nb1 + 2] = x4;
225           nb1++;
226           j = 0;
227           if (left)
228             left -= x2;
229         }
230     }
231   if (left || payp != payn)
232     {
233       fprintf(stderr, "oops, left = %d %d %d\n", left, payp, payn);
234       exit(1);
235     }
236   if (j)
237     {
238       if ((nb1 & 15) == 0)
239         b1 = xrealloc2(b1, nb1 + 16, 3 * sizeof(unsigned int));
240       b1[3 * nb1] = j;
241       b1[3 * nb1 + 1] = 0;
242       b1[3 * nb1 + 2] = 0;
243       nb1++;
244     }
245   *b1p = b1;
246   *nb1p = nb1;
247   *b2p = b2;
248   *nb2p = nb2;
249 }
250
251 void
252 bzput4(struct cfile *fp, unsigned int d)
253 {
254   unsigned char dd[4];
255   dd[0] = d >> 24;
256   dd[1] = d >> 16;
257   dd[2] = d >> 8;
258   dd[3] = d;
259   if (fp->write(fp, dd, 4) != 4)
260     {
261       perror("bzwrite");
262       exit(1);
263     }
264 }
265
266 void
267 put4(FILE *fp, unsigned int d)
268 {
269   unsigned char dd[4];
270   dd[0] = d >> 24;
271   dd[1] = d >> 16;
272   dd[2] = d >> 8;
273   dd[3] = d;
274   if (fwrite(dd, 4, 1, fp) != 1)
275     {
276       perror("fwrite");
277       exit(1);
278     }
279 }
280
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);
282
283 unsigned int payread(FILE *fp, off64_t off, unsigned int len, unsigned char **pp, MD5_CTX *ctx, unsigned char *namebuf)
284 {
285   int l, r;
286   struct cfile *cfile;
287
288   if (fseeko64(fp, off, SEEK_SET) != 0)
289     {
290       perror("fseeko");
291       exit(1);
292     }
293   cfile = cfile_open(CFILE_OPEN_RD, CFILE_IO_FILE, fp, CFILE_COMP_XX, len, ctx ? (cfile_ctxup)rpmMD5Update : 0, ctx);
294   if (!cfile)
295     {
296       fprintf(stderr, "cfile open failed\n");
297       exit(1);
298     }
299   if (namebuf)
300     {
301       cfile_detect_rsync(cfile);
302       namebuf[0] = cfile->comp;
303     }
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);
305   if (l == -1)
306     {
307       fprintf(stderr, "cfile_copy failed\n");
308       exit(1);
309     }
310   r = cfile->close(cfile);
311   if (r)
312     {
313       fprintf(stderr, "cfile not used up (%d bytes left)\n", r);
314       exit(1);
315     }
316   return l;
317 }
318
319 void
320 processrpm(struct cfile *fpout, FILE *fpold, FILE *fpnew, struct rpmpay *pay, struct rpmpay *oldpays, int oldpayn, MD5_CTX *ctx)
321 {
322   struct rpmpay *oldpay;
323   int i, n;
324   unsigned int l, newl, oldl;
325   unsigned char *new, *old;
326   unsigned char namebuf[258];
327
328   oldpay = 0;
329   for (i = 0; i < oldpayn; i++)
330     if (!strcmp(oldpays[i].name, pay->name))
331       {
332         oldpay = oldpays + i;
333         break;
334       }
335   l = strlen(pay->name);
336   if (l > 255)
337     l = 255;
338   namebuf[0] = 255;
339   namebuf[1] = l;
340   memcpy(namebuf + 2, pay->name, l);
341   namebuf[l + 2] = 0;
342   targetsize += pay->l;
343   if (!oldpay)
344     {
345       printf("%s: not found in old iso...", pay->name);
346       if (fpout->write(fpout, namebuf, l + 2) != l + 2)
347         {
348           perror("namebuf write");
349           exit(1);
350         }
351       bzput4(fpout, pay->l);
352       if (fseeko64(fpnew, pay->o, SEEK_SET) != 0)
353         {
354           perror("fseeko");
355           exit(1);
356         }
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)
358         {
359           fprintf(stderr, "cfile_copy failed\n");
360           exit(1);
361         }
362     }
363   else
364     {
365       n = 0;
366       for (i = 0; i < oldpayn; i++)
367         if (i == 0 || oldpays[i].x != 0)
368           {
369             if (oldpays[i].o == oldpay->o)
370               break;
371             else
372               n++;
373           }
374       if (i == oldpayn)
375         {
376           fprintf(stderr, "internal error\n");
377           exit(1);
378         }
379       if (oldpay->l != oldpays[i].l)
380         {
381           fprintf(stderr, "internal error, length mismatch %d %d\n", oldpay->l, oldpays[i].l);
382           exit(1);
383         }
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))
388         {
389           printf("%s: unchanged...", namebuf + 2);
390           namebuf[0] = 254;
391         }
392       else
393         {
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! */
397         }
398       fflush(stdout);
399       if (fpout->write(fpout, namebuf, l + 2) != l + 2)
400         {
401           perror("namebuf write");
402           exit(1);
403         }
404       bzput4(fpout, n);         /* offset id */
405       if (namebuf[0] == 254)
406         free(old);
407       else
408         diffit(fpout, 0, 0, old, oldl, new, newl, 0, 0, 0, 0, 0);
409       old = 0;
410       oldl = 0;
411       free(new);
412       new = 0;
413       newl = 0;
414     }
415   writtensize += fpout->bytes;
416   fpout->bytes = 0;
417   printf("%4.1f%%\n", writtensize * 100 / targetsize);
418 }
419
420 /* frees old! */
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)
422 {
423   unsigned int *b1;
424   int nb1;
425   unsigned int *b2;
426   int nb2;
427   struct instr *instr = 0;
428   int instrlen = 0;
429   unsigned char *addblk = 0;
430   unsigned int addblklen = 0;
431   int i, j, b2i;
432   unsigned int off;
433
434   mkdiff(DELTAMODE_HASH, old, oldl, new, newl, &instr, &instrlen, 0, 0, &addblk, &addblklen, 0, 0);
435   free(old);
436   old = 0;
437   recode_instr(instr, instrlen, &b1, &nb1, &b2, &nb2, newpays, newpayn);
438   free(instr);
439   instr = 0;
440   instrlen = 0;
441   bzput4(fpout, oldl);
442   bzput4(fpout, newl);
443   bzput4(fpout, nb1);
444   bzput4(fpout, nb2);
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]);
453
454   /* write add section */
455   bzput4(fpout, addblklen);
456   if (addblklen && fpout->write(fpout, addblk, addblklen) != addblklen)
457     {
458       perror("bzwrite");
459       exit(1);
460     }
461   if (addblk)
462     free(addblk);
463
464   /* write data section */
465   b2i = 0;
466   off = 0;
467   for (i = 0; i < nb1; i++)
468     {
469       if (ctx)
470         {
471           for (j = 0; j < b1[3 * i]; j++, b2i++)
472             {
473               if (b2[2 * b2i + 1])
474                 rpmMD5Update(ctx, new + off, b2[2 * b2i + 1]);
475               off += b2[2 * b2i + 1];
476             }
477         }
478       if (b1[3 * i + 1] == 0xffffffff)
479         {
480           processrpm(fpout, fpold, fpnew, newpays + b1[3 * i + 2], oldpays, oldpayn, ctx);
481         }
482       else if (b1[3 * i + 1])
483         {
484           if (ctx)
485             {
486               if (off != b1[3 * i + 2])
487                 {
488                   fprintf(stderr, "internal error: off mismatch %d %d\n", off, b1[3 * i + 2]);
489                   exit(1);
490                 }
491               rpmMD5Update(ctx, new + off, b1[3 * i + 1]);
492               off += b1[3 * i + 1];
493             }
494           if (fpout->write(fpout, new + b1[3 * i + 2], b1[3 * i + 1]) != b1[3 * i + 1])
495             {
496               perror("bzwrite");
497               exit(1);
498             }
499         }
500     }
501   free(b1);
502   free(b2);
503 }
504
505 int
506 main(int argc, char **argv)
507 {
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;
514   int oldpayn = 0;
515   struct rpmpay *newpays = 0;
516   int newpayn = 0;
517   int i, n;
518   struct cfile *bf;
519   MD5_CTX targetmd5;
520   unsigned char targetmd5res[16];
521
522   if (argc != 4)
523     {
524       fprintf(stderr, "usage: makedeltaiso <oldiso> <newiso> <deltaiso>\n");
525       exit(1);
526     }
527   if ((fpold = fopen64(argv[1], "r")) == 0)
528     {
529       perror(argv[1]);
530       exit(1);
531     }
532   if ((fpnew = fopen64(argv[2], "r")) == 0)
533     {
534       perror(argv[2]);
535       exit(1);
536     }
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)
542     {
543       perror(argv[3]);
544       exit(1);
545     }
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;
553
554   putc('D', fpout);
555   putc('I', fpout);
556   putc('S', fpout);
557   putc('O', fpout);
558   put4(fpout, 2);
559   if ((bf = cfile_open(CFILE_OPEN_WR, CFILE_IO_FILE, fpout, CFILE_COMP_BZ, CFILE_LEN_UNLIMITED, 0, 0)) == 0)
560     {
561       fprintf(stderr, "cfile wopen failed\n");
562       exit(1);
563     }
564   /* write old map */
565   n = 0;
566   for (i = 0; i < oldpayn; i++)
567     if (i == 0 || oldpays[i].x)
568       n++;
569   bzput4(bf, n);
570   for (i = 0; i < oldpayn; i++)
571     if (i == 0 || oldpays[i].x)
572       {
573         bzput4(bf, oldpays[i].lx);
574         bzput4(bf, oldpays[i].l);
575       }
576   bzput4(bf, oldpays[i].lx);
577
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);
582   oldiso = 0;
583   oldisolen = 0;
584   free(newiso);
585   newiso = 0;
586   newisolen = 0;
587   writtensize += bf->bytes;
588   bf->bytes = 0;
589   printf("iso diff done, final compression: %4.1f%%\n", writtensize * 100 / targetsize);
590   if (bf->write(bf, targetmd5res, 16) != 16)
591     {
592       perror("md5sum write");
593       exit(1);
594     }
595   if (bf->close(bf) == -1)
596     {
597       perror("cfile close");
598       exit(1);
599     }
600   if (fclose(fpout))
601     {
602       perror("fclose");
603       exit(1);
604     }
605   printf("iso md5sum is: ");
606   for (i = 0; i < 16; i++)
607     printf("%02x", targetmd5res[i]);
608   printf("\n");
609   for (i = 0; i < oldpayn; i++)
610     free(oldpays[i].name);
611   free(oldpays);
612   for (i = 0; i < newpayn; i++)
613     free(newpays[i].name);
614   free(newpays);
615   exit(0);
616 }